一、指针类型大小
int main()
{
int* pa;
char* pc;
float* pf;
printf("%d\n", sizeof(pa));
printf("%d\n", sizeof(pc));
printf("%d\n", sizeof(pf));
//都是4,指针类型大小一样
return 0;
}
运行结果:
->既然指针类型大小一样,那么指针类型的意义是什么?
1、指针类型决定了 指针解引用的权限有多大
int main()
{
int a = 0x11223344;
//a在内存中为44 33 22 11
//int类型的指针:
int* pa = &a;
*pa = 0;
//a在内存中为00 00 00 00
//char类型的指针:
char* pc = &a;
*pc = 0;
//a在内存中为00 33 22 11
//只改了一个字节
return 0;
}
2、指针类型决定了指针走一步,能走多远(步长)
int main()
{
int arr[10] = { 0 };
int* p = arr;
char* pc = arr;
printf("%p\n", p); //结果和pc一样
printf("%p\n", p+1); //结果向右跳过了四个字节
printf("%p\n", pc); //结果和p一样
printf("%p\n", pc+1); //结果向右跳过了一个字节
return 0;
}
总结:
指针类型的意义
1、指针类型决定了 指针解引用的权限有多大
2、指针类型决定了指针走一步,能走多远(步长)
二、野指针
(一)概念:野指针就是指针指向的位置是不可知的(随机、不正确、没有明确限制)
(二)野指针的成因:
1、指针未初始化
int main()
{
int* p;//p是一个局部的指针变量,局部变量不初始化默认是随机值
//把20放进随机一个地址的内存
*p = 20;//非法访问内存了,报错
return 0;
}
2、指针越界
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i; i <= 10; i++)
{
*p = i; //当i=10的时候,*p越界了,该指针就是野指针了
p++;
}
return 0;
}
3、指针指向了空间释放
(三)如何避免野指针
1、当前不知道p应该初始化为什么地址的时候,直接初始化为NULL。
int main()
{
int* p = NULL; //当前不知道p应该初始化为什么地址的时候,直接初始化为NULL
return 0;
}
2、明确初始化的值
int main()
{
int a = 10;
int* p = &a;
return 0;
}
3、指针指向空间释放,及时置成NULL
4、小心指针越界(C语言本身不会检查数据越界行为)
5、指针使用前要检查有效性
int main()
{
int* p = NULL;
if (p != NULL)
*p = 10;
return 0;
}
三、指针运算
指针 减 指针 得到的是两个指针之间的元素个数 (该运算前提是两个指针指向同一块空间)
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", &arr[9] - &arr[0]);
return 0;
}
运行结果:
指针运算的灵活运用:
例题:用指针-指针实现strlen()函数
strlen() 求字符串长度
代码实现:
int my_strlen(char* str)
{
int* start = str;
while (*str != '\0')
str++;
return str - start;
}
int main()
{
int len = my_strlen("abc");
printf("%d", len);
return 0;
}
运行结果:
3
四、数组指针与数组的关系换算
首先创建一个数组并初始化:int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
指针p指向数组首元素:int* p = arr;
在arr[2]中,[] 是一个操作符 2和arr是两个操作数,所以:
arr[2] 等于 *(arr+2) 等于 *(p+2) 等于 *(2+p) 等于 *(2+arr) 等于 2[arr]
即 arr[2] 等于 2[arr]
p等于arr,所以arr[2] 等于 p[2] 等于 2[p]
代码验证:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
//arr[2] 等于 *(arr+2) 等于 *(p+2) 等于 *(2+p) 等于 *(2+arr) 等于 2[arr]
//arr[2] 等于 2[arr]
//arr[2] 等于 p[2] 等于 2[p]
printf("%d\n", arr[2]);
printf("%d\n", 2[arr]);
printf("%d\n", p[2]);
printf("%d\n", 2[p]);
return 0;
}
运行结果:
五、二级指针
int main()
{
int a = 10;
int* pa = &a; //pa是指针变量,一级指针
//ppa是一个二级指针变量
int* *ppa = &pa; //pa也是个变量,&pa取出pa在内存中起始地址
//pppa是三级指针
int*** pppa = &ppa;
return 0;
}
由上可知:
*ppa == pa
*pa == a
* *ppa == a
六、指针数组
指针数组的本质是数组
int main()
{
int arr1[10];//整型数组
char arr2[10];//字符数组
//指针数组 - 存放指针的数组
int* parr[10];//整型指针的数组
char* pch[10];//字符指针的数组
return 0;
}