五、指针运算
- 指针+- 整数
- 指针-指针
- 指针的关系运算
5.1 指针+- 整数
#include <stdio.h> int main() { int arr[10] = { 0 }; int* p = arr; int i = 0; for (i = 0; i < 10; i++) { *p = i; p++; } for(i = 0; i < 10; i++) { printf("%d ", *(p+i)); } for(i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
5.2 指针-指针
指针-指针运算的前提条件是两个指针指向了同一块空间
应用:计算字符串的 长度
#include <stdio.h> 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; }
5.3 指针的关系运算
#define N_VALUES 5 float values[N_VALUES]; for(vp = &values[N_VALUES]; vp > &values[0];) { *--vp = 0; }
将代码简化,修改为:
#define N_VALUES 5 float values[N_VALUES]; for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--) { *vp = 0; }
这种写法在绝大部分的编译器上是可以顺利完成任务的,但是我们还是应该避免这样写,因为标准并不保证它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与 指向第一个元素之前的那个内存位置的指针进行比较。
可以拿p和p2比,但是不可以拿p和p1比
六、指针和数组
指针和数组虽然是不同的东西,但它们之间有着一些联系,接下来就让我带着大家学习两者之间的相同点和不同点。
根据上述结果我们可以得出数组名就是数组首元素的地址。
将数组视为指针,也催生除了数组和指针的密切关系
1. int arr[10] = {1,2,3,4,5,6,7,8,9,0}; 2. int *p = arr;//p存放的是数组首元素的地址
这里声明了数组arr和指针p。p初始化的值是arr,因为数值名arr会被解释为&arr[0],所以p中存放的值为&arr[0]。也就是说p会被初始化为指向数组arr的起始元素arr[0]的地址。
注意:p指向的是起始元素,不是整个数组。
6.1数组名不是首元素地址的情况
1. 作为sizeof运算符的操作数出现
sizeof(数组名) 不会生成指向起始元素的指针的长度,而是生成数组整体的长度。
2. 作为取地址操作符的操作数出现
&数组名 不是指向起始元素的地址的指针,二是指向数组整体的指针。
1. int a[5]; 2. int b[5]; 3. a=b; //错误
这样赋值,那么数组a的地址就会被改变。因此 ,赋值表达式的左操作数不能是数组。
“不可以使用赋值运算符改变指向数组起始元素的指针”
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; }
6.2 通过指针引用数组元素
- 下标法:如a[i]的形式
- 指针法:如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,初始值p=a
(1)下标法 int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; } (2)通过数组名计算数组元素地址,找出元素 int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", *(arr + i)); } return 0; } (3)用指针变量指向数组元素 int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int* p = arr; int i = 0; for (p = arr; p < arr + 9; p++) { printf("%d ", *p); } return 0; }
注意:在使用指针变量指向数组元素是要注意
1.可以通过改变指针变量的值指向不同的元素,如指针变量p来指向元素,用p++使p的值不断改变从而指向不同的元素。
2.要注意指针变量的当前值。
6.3以变量名和数组名作为函数参数的比较
实参类型 | 变量名 | 数组名 |
要求形参的类型 | 变量名 | 数组名或指针变量 |
传递的信息 | 变量的值 | 实参数组首元素的地址 |
通过函数调用能否改变实参的值 | 不能改变实参变量的值 | 能改变实参变量的值 |
注意:实参数组名代表的是一个固定的地址,或者说是指针变量,但形参数组名并不是一个固定的地址,而是按指针变量处理。
七、二级指针
int main() { int a = 10; int* p = &a; //p是一级指针,指针变量也是变量,是变量就有地址,在内存上开辟空间 int** pp = &p; //pp是二级指针变量,二级指针变量是用来存放一级指针变量的地址 }
二级指针的运算有:
- *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa
1. int a = 10; 2. int* p = &a; 3. int** pp = &p; 4. *pp=&a; //等价于 p = &a
- **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
1. **pp = 30; 2. //等价于*p = 30 3. //等价于a = 30
八、指针数组
8.1什么是指针数组
一个数组,若其元素均为指针类型数据,称为指针数组。也就是说,指针数组中的每一个元素都存放一个地址。下面定义一个指针数组:
int* p[4];
定义指针数组的形式
类型名 * 数组名[数组长度]
int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 2,3,4,5,6 }; int arr3[] = { 3,4,5,6,6 }; int* parr[] = { arr1,arr2,arr3 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 5; j++) { printf("%d ", *(parr[i] + j)); } printf("\n"); } return 0; }
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者的支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。