指针
如果既没有给指针有效地址,也没有给指针空地址,那么这就是一个野指针,一定必须肯定绝对不能出现野指针
- 指针变量是指向一个存储位置的地址
- 普通变量是指向一个存储位置的数据
#include <stdio.h>
int main()
{
int *p_num = NULL;
int num = 0;
p_num = #
*p_num = 10;
printf("num is %d\n", num);
return 0;
}
复制代码
/**
* 从键盘得到三个数字
* 使用指针变量找出其中最大的数字
*/
#include <stdio.h>
int main()
{
int num = 0, num1 = 0, num2 = 0;
int *p_num = &num, *p_num1 = &num1, *p_num2 = &num2;
printf("请输入三个数字:");
scanf("%d %d %d", &num, &num1, &num2);
if (*p_num < *p_num1)
{
*p_num += *p_num1;
*p_num1 = *p_num - *p_num1;
*p_num -= *p_num1;
}
if (*p_num < *p_num2)
{
*p_num += *p_num2;
*p_num2 = *p_num - *p_num2;
*p_num -= *p_num2;
}
printf("最大值是:%d\n", *p_num);
return 0;
}
复制代码
/**
* 把数字从小到大打印
*/
#include <stdio.h>
int main()
{
int num = 0, num1 = 0, num2 = 0;
int *p_num = &num, *p_num1 = &num1, *p_num2 = &num2;
printf("请输入三个数字:");
scanf("%d %d %d", p_num, p_num1, p_num2);
if (*p_num < *p_num1)
{
int *p_tmp = p_num;
p_num = p_num1;
p_num1 = p_tmp;
}
if (*p_num < *p_num2)
{
int *p_tmp = p_num;
p_num = p_num2;
p_num2 = p_tmp;
}
if (*p_num1 < *p_num2)
{
int *p_tmp = p_num1;
p_num1 = p_num2;
p_num2 = p_num;
}
printf("%d %d %d\n", *p_num, *p_num1, *p_num2);
return 0;
}
复制代码
指针类型转换
- 指针变量的类型转换过程中不会导致地址数据受影响
- %p占位符用来打印地址数据
- 指针变量的类型转换过程中影响的是和指针配对的普通变量存贮位置
/**
* p_num是0x7ffd428988d4,*p_num是300
* (char*)p_num是0x7ffd428988d4,*(char*)是44
* int 是4个字节 32位 00000000000000000000000100101100
* char 是一个字节 8位 00101100
* 所以300变成了44
*/
#include <stdio.h>
int main()
{
int num = 300;
int *p_num = #
printf("p_num是%p,*p_num是%d\n", p_num, *p_num);
printf("(char*)p_num是%p,*(char*)是%d\n", (char*)p_num, *(char*)p_num);
return 0;
}
复制代码
void型指针
void型指针通常用来接收来源不明的数据地址,这种类型的指针只表示了其中记录了一个地址数据,但是并没有告诉我们可以根据它找到什么类型的存储位置
#include <stdio.h>
int main()
{
char ch = 'a';
void *p_val = &ch;
printf("%c\n", *(char*)p_val);
return 0;
}
复制代码
指针形参
#include <stdio.h>
void swap(void *arr, int num)
{
if (num == 0)
{
printf("*arr的值是%d\n", *(int*)arr);
} else if (num == 1)
{
printf("*arr的值是%c\n", *(char*)arr);
} else {
printf("*arr的值是%g\n", *(float*)arr);
}
}
int main()
{
int number = 100;
char ch = 'a';
float fnum = 12.21f;
swap(&number, 0);
swap(&ch, 1);
swap(&fnum, 2);
}
复制代码
指针函数和返回值
- 指针类型变量可作为函数的返回值使用
- 指针类型的返回值可以用来表示一个存储位置
- 不可以把局部变量的地址赋值给指针类型的返回变量
- 局部变量的生命周期仅在这个函数调用期间
#include <stdio.h>
int max(int num, int num1)
{
return num > num1 ? num : num1;
}
int *max1(int *num, int *num1)
{
return *num > *num1 ? num : num1;
}
int main()
{
int num = 3, num1 =7;
int *p_num = max1(&num, &num1);
printf("p_num是:%d", *p_num);
return 0;
}
复制代码
内存分配空间
- 程序在内存中是分段存储的
- 代码段
- 存放语句转换成的数字,程序运行的时候不可以被修改
- 全局段
- 用来记录全局变量和静态变量的位置,这个段落的大小不会随着程序的运行而发生改变
- 栈
- 用来存放局部变量,块变量,形式参数,返回值,这个段落的大小是随着程序的运行而不断发生改变的,每当一个函数调运出现的时候,就从这个段落一段段落分配一段空间来记录它自己的变量,当函数调用语句结束的时候,他被分配的空间就会被计算机收回
- 不同的函数调用的空间遵循后进先出的原则
- 堆
- 这个段落用来存放动态分配的存储位置,动态变量的分配和回收工作由程序员编写的语句管理,如果管理语句错误会产生严重的后果
指针数组
#include <stdio.h>
int main()
{
char ranks[5][4] = {"dot", "lol", "jaa", "pp", "c"};
int num = 0;
for (num = 0; num <= 4; num++)
{
printf("%s\n", ranks[num]);
}
char *ranks1[5] = {"doa", "lol", "jaa", "php", "c"};
int num1 = 0;
for (num1 = 0; num1 <= 4; num1++)
{
printf("%s\n", ranks1[num1]);
}
return 0;
}
复制代码
动态内存分配
-
动态分配内存一定来来自于堆这个段落
-
C语言有提供几个标准函数用来分配和回收堆中的存储位置
-
使用动态分配内存函数需要头文件stdlib.h
-
malloc标准函数
- malloc标准函数用来分配动态内存中多个连续的存储位置
- 函数会把第一个字节的地址赋值给返回值变量 void*
- malloc函数和文件操作一样是有可能会失败的,因为文件操作就是一个动态分配内存 在失败的时候要给malloc函数NULL赋值给返回值
-
数free标准函
- free标准函用来回收不再使用的动态分配内存
- 所有的动态内存在使用完毕后必须立刻释放
- 一次分配所得的内存必须统一释放
#include <stdio.h>
#include <stdlib.h>
/**
* 动态分配内存存储三个数字,分别是123,然后打印出来
*/
int main()
{
int num = 0;
int *p_num = (int*)malloc(sizeof(int) * 3);
if (p_num)
{
for (num = 0; num <= 2; num++)
{
*(p_num + num) = num + 1;
}
for (num = 0; num <= 2; num++)
{
printf("%d\n", *(p_num + num));
}
free(p_num);
p_num = NULL;
}
return 0;
}
复制代码