4. 指针运算
- 指针± 整数
- 指针-指针
- 指针的关系运算
4.1 指针±整数
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int arr[10] = { 0 }; //不使用下标访问数组 int* p = &arr[0]; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; i++)//方式1:p本身变化 { *p = i; p++;//p = p+1 } p = arr; for (i = 0; i < sz; i++)//方法2:p不变 { printf("%d ", *(p + i));//p+i } /*for (i = 0; i < sz; i++) { printf("%d ", arr[i]); }*/ return 0; }
小小拓展
优秀样例🥇
#define N_VALUES 5 float values[N_VALUES]; float *vp; //指针+-整数;指针的关系运算 for (vp = &values[0]; vp < &values[N_VALUES];) { *vp++ = 0; }
4.2 指针-指针
int main() { int arr[10] = { 0 }; printf("%d\n", &arr[9] - &arr[0]);//? printf("%d\n", &arr[0] - &arr[9]);//? return 0; }
结果
通过上面的例子可以得出
指针-指针:差值的绝对值是中间元素的个数
注意:指针-指针的前提是:两个指针指向同一块空间
int main() { int arr[10] = { 0 }; char ch[5] = {0}; //指针和指针相减的前提是:两个指针指向了同一块空间 printf("%d\n", &ch[4] - &arr[0]);//err return 0; }
有效使用
指针-指针的这个特性可以运用到
模拟实现strlen中
int my_strlen(char* s) { char* start = s; while (*s != '\0') { s++; } return s - start; } int main() { char arr[] = "abcdef"; int len = my_strlen(arr); printf("%d\n", len); return 0; }
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. 指针和数组
指针和数组之间是什么关系呢?
- 指针变量就是指针变量,不是数组,指针变量的大小是4/8个字节,专门是用来存放地址的。
- 数组就是数组,不是指针,数组是一块连续的空间,可以存放1个或者多个类型相同的数据。
联系
数组中,数组名其实是数组首元素的地址,数组名 == 地址 == 指针
当我们知道数组首元素的地址的时候,因为数组又是连续存放的,所以通过指针就可以遍历访问数组,数组是可以通过指针来访问的。
我们看一个例子:
#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; }
可见数组名和数组首元素的地址是一样的
结论:数组名表示的是数组首元素的地址。
那么这样写代码是可行的🥇:
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; }
所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。
如下🥈:
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; }
6. 二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是二级指针
帮助理解
对于二级指针的运算有
- *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 main() { char arr1[] = "abcdef"; char arr2[] = "hello world"; char arr3[] = "cuihua"; //指针数组 char* parr[] = { arr1, arr2, arr3 }; int i = 0; for (i = 0; i < 3; i++) { printf("%s\n", parr[i]); } return 0; }