指针初步讲解(上):https://developer.aliyun.com/article/1624361
3.2 如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放即使置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
#include <stdio.h> int main() { int *p = NULL; int a = 10; p = &a; if(p != NULL) { *p = 20; } return 0; }
4.指针运算
4.1 指针±整数
#include <stdio.h> #define N_VALUES 5 int main(){ float values[N_VALUES]; float *vp; //指针+-整数;指针的关系运算 for (vp = &values[0]; vp < &values[N_VALUES];) { *vp++ = 0; //*vp=0;vp++ } for(int i=0;i<N_VALUES;i++){ printf("%d ",values[i]);} return 0; } 运行结果:0 0 0 0 0
4.2 指针-指针
#include <stdio.h> int my_strlen(char *s) { char *p = s; while (*p != '\0') p++; return p - s; } int main() { char str[] = "Hello, World!"; int length = my_strlen(str); printf("字符串长度:%d\n", length); return 0; } 运行结果:字符串长度:13
指针与指针之间的减法运算可以提供两个指针之间的偏移量。这意味着我们可以计算出指针之间的元素个数。指向同一块的两个空间的指针才能相减。
4.3 指针的关系运算
for(vp = &values[N_VALUES]; vp > &values[0];) { *--vp = 0; }
代码简化, 这将代码修改如下:
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--) { *vp = 0; }
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证
它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。
5.指针和数组
我们看一个例子:
#include <stdio.h> 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; }
运行结果:
000000000065FDF0
000000000065FDF0
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。(2种情况除外,数组章节讲解了)
特例:
- sizeof (数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
- &数组名,取出的是整个数组的地址。
那么这样写代码是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0}; int *p = arr;//p存放的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
例如:
#include <stdio.h> int main() { int arr[] = {1,2,3,4,5,6,7,8,9,0}; int *p = arr; //指针存放数组首元素的地址 int sz = sizeof(arr)/sizeof(arr[0]);//求出数组元素个数 for(i=0; i<sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i); } return 0; } 运行结果: &arr[0] = 000000000065FDE0 <====> p+0 = 000000000065FDE0 &arr[1] = 000000000065FDE4 <====> p+1 = 000000000065FDE4 &arr[2] = 000000000065FDE8 <====> p+2 = 000000000065FDE8 &arr[3] = 000000000065FDEC <====> p+3 = 000000000065FDEC &arr[4] = 000000000065FDF0 <====> p+4 = 000000000065FDF0 &arr[5] = 000000000065FDF4 <====> p+5 = 000000000065FDF4 &arr[6] = 000000000065FDF8 <====> p+6 = 000000000065FDF8 &arr[7] = 000000000065FDFC <====> p+7 = 000000000065FDFC &arr[8] = 000000000065FE00 <====> p+8 = 000000000065FE00 &arr[9] = 000000000065FE04 <====> p+9 = 000000000065FE04
所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。
如下:
#include <stdio.h> 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)); } return 0; } 运行结果;1 2 3 4 5 6 7 8 9 0
6.二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?这就是 二级指针 。
int a=10; int* pa=&a; int**ppa=&pa; //a的地址存放在pa中,pa的地址存放在ppa中,pa是一级指针,ppa是二级指针。
对于二级指针的运算有:
*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .
int b = 20; *ppa = &b;//等价于 pa = &b;
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
**ppa = 30; //等价于*pa = 30; //等价于a = 30;
7.指针数组
指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
int* arr3[5];//是什么? arr3是一个数组,有五个元素,每个元素是一个整形指针。
应用:指针数组模拟二维数组。
#include <stdio.h> int main(){ int arr1[]={1,2,3,4,5}; int arr2[]={2,3,4,5,6}; int arr3[]={3,4,5,6,7}; int *arr[]={arr1,arr2,arr3}; for(int i=0;i<3;i++){ for(int j=0;j<5;j++){ printf("%d ",arr[i][j]);//等价于*(*(arr+i)+j) } printf("\n"); } } 运行结果: 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7
OK,指针的初步讲解就到这里,友友们留下个三连加评论吧,谢谢~~~