当你不知道指针变量初始化什么时,可以初始化为空指针
cpp
int *p=NULL;
我们看NULL的定义,可以看出NULL是0被强制转化为Void* 类型的0;实质还是个0;
如何避免野指针:
- 指针初始化
- 小心指针越界
- 指针指向空间释放即使置 NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
指针运算
- 指针+- 整数
- 指针-指针
- 指针的关系运算
指针+- 整数
下面这段代码实现的是打印数组的元素。
cpp
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (i = 0; i < sz; i++)
{
printf("%d ", *p);
p = p + 1;
}
return 0;
}
指针 - 指针
cpp
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这个函数
cpp
int my_strlen(char* str)
{
char* start = str;
char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;
}
int main()
{
char arr[] = "bit";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
指针与数组
数组名是首元素地址,怎么证明呢?通过下面的代码进行证明
cpp
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
注意:两个例外
1.&arr - &数组名 - 数组名不是首元素地址-数组名表示整个数组 ,所以&数组名取出的是整个数组的地址,
2.sizeof(arr) - sizeof(数组名)-数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小。单位字节
下面的代码我们来看看他们的区别
cpp
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0]+1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
return 0;
}
调试代码如下:
前面两个都是地址加4,最后一个加了40,(16进制的运算)
可以看出&arr是整个数组的地址,整个数组的地址加1,是跳过(整型)4*10(元素个数)=40
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问其中任意一个就成为可能。
看下面的代码:
cpp
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
}
return 0;
}
可以看出是是一一对应的关系,所以 p+i 其实计算的是数组 arr 下标为i的地址。 那我们就可以直接通过指针来访问数组。
打印数组元素
cpp
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int* p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
for (i = 0; i < sz; i++)
{
printf("%d \n", arr[i]);
}
return 0;
}
二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
所以我们就有二级指针
a 的类型是int
pa 的类型是int*
ppa 的类型是int** 最后一个*表示是指针,指向的对象是int*
cpp
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;
printf("%d\n", **ppa);
}
指针数组
与数组指针的区别 就像好孩子,重点是孩子,
指针数组-数组 --存放指针的数组。
数组指针-指针。
为啥要与指针数组,跟数组的由来一样,看下面的代码,对同一类型的地址存储,如果一个一个写下去,太麻烦了,所以我们要有指针数组来存放,这样就方便多了。
cpp
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* pa = &a;
int* pb = &b;
int* pc = &c;
return 0;
}
怎么初始化呢?
cpp
int arr[10];
int* arr1[3];//指针数组初始化
存放的类型都是int* 的类型
cpp
int* arr1[3] = { &a,&b,&c };
cpp
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr2[3] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d \n", *(arr2[i]));
}
return 0;
}