指针
1指针定义
1、定义一个指针变量p,类型是int*。
2、p指向一个int型的数据【涉及的指针符号:* &】
int *p;
2指针的绑定
p = &a;
//指针的解引用,*p得到了变量(a)。
*p = 23;
3指针的初始化【定义指针的同时 应该并且初始化】
int *p1 = &a; // == int *p, a; p = &a
【int *p=NULL】专用于指针的初始化
注意【指针的运算,就是指针所指向的变量类型所占字节大小(sizeof(int)) * 1】
野指针危害:
1、直接指向内核区
2、指向可用也没有别的数据的区域
3、最可怕,可用但有别的数据
const
1【const与指针, 就近原则】
【1】int const *p1;
p1 = &a;
*p1 = 11; // 错误 error: assignment of read-only location ‘*p1’【p1指向的内容不可改变,但是p1所指向的地址可以改变】
【2】const int * p2; // p2 ,p2所指向的数据(int) 等同于p1
【3】int * const p3; // 野指针 修饰p3,p3不可改, 也就是说p3所指向的内容可改变
【4】const int *const p4; // 必须定义时 同时初始化 两者都不能变
2【const 关键字, 修饰的变量是常数,不可更改。只能初始化一次】
函数的输出型参数
1、数组名作为函数参数退化为一个指针
2、子函数内部改变了原数组里面的内容
举例 【主函数省略】
void func_arr(int *arr, int lenth) // == (int arr[]) == (int arr[数字]) { printf("arr = %p. sizeof(arr) = %d.\n", arr, sizeof(arr));
*arr = 11; // == arr[0] = 11
arr[1] = 22;
}
【不用返回值也可以改变主函数的值】
数组与指针
【1】【不太理解】
int *p1 = &arr[0];
printf("*p++ = %d.\n", *p++)【】
printf("*(p++) = %d.\n", *(p++));
printf("*++p = %d.\n", *++p);
printf("(*p)++ = %d *p = %d.\n", (*p)++, *p);
printf("*p = %d (*p)++ = %d.\n", *p, (*p)++);
printf("*p = %d.\n", *p);
int *q = arr + 5;
// 同一数组,指针相减是个数
int ret = q - p;
【2】二维数组
二维数组, 变量名:首元素首地址{arr[0], arr[1]} //arr &arr[0] &arr[0][0] //arr代表数组首元素首地址(&arr[0]) //&arr[0]代表第一维数组的首元素首地址 //&arr[0][0]代表数组的第二维数组是首元素首地址 int arr[2][3] = {1, 2, 3, 4, 5, 6};
//数组指针, 指针指向了一个int[3]类型的数据结构
int (*p)[3]
typedef
【/typedef是重命名的关键字,他不是发明新类型,而是给类型起了一个新外号】
函数是一个地址,也就可以理解成指针,所以函数也可以 //用类型这个理解方法 //类型名 + 变量名 //定义一个函数指针, 并且绑定, C语言里对于函数名的绑定有两种方式: //func、&func,通常写成func void (*p)(void) = &func; //调用函数, 指针的解引用
malloc动态数组
1 malloc堆申请的空间,【默认是有最小分配的】
int *p = NULL
p = (int *)malloc(num * sizeof(int));
2 判断申请空间是否成功
if (NULL == p)
{
printf("malloc error.\n");
return -1;
}
3 清空这段内存
memset(p, 0, num*sizeof(int));
4释放堆内存
1、整个程序结束,会自动释放堆内存
2、申请一次,释放一次,不能多次释放
3、释放的堆内存必须是这块内存的首地址
if (NULL != p)
{
free(p);
//p就是一个野指针
p = NULL;
}
return 0;
}