关于指针与数组这对兄弟
指针和数组是 C 语言中比较重要的知识点,尤其是指针和数组结合之后,很多同学就不清楚是怎么一回事了。在这里结合几个例子,介绍一下我所理解的指针和数组,希望对大家有所帮助。
指针
指针在 C 语言中是一种类型,就和其他基本数据类型一样。通常在32位机器上面占四个字节,在64位机器上占八个字节。指针用来保存其他变量的地址,请看下面整型指针与整型变量的对比:
int main() { int a = 4; //定义整型变量 a int b = 10; //定义整形变量 b int *p = &b; //定义整型指针 p ,保存变量 b 的地址 //a 变量和 p 变量的值 printf("a 变量的值为: %d\n", a); printf("p 变量的值为: %p\n", p); //指针变量的特殊操作 printf("指针所指向变量的值: %d\n", *p); *p = 15; printf("指针所指向变量的值: %d\n", *p); printf("b 变量的值为: %d\n", b); return 0; }
解释:
在上面的程序中,定义了整型变量 a、整型变量 b 和 整型指针变量p,让指针变量 p 保存变量 b 的内存地址,也就是说 p 指针”指向“变量 b 。程序接着打印 a 变量的值和p 变量的值,分别代表整型变量 a 保存的整数值和指针变量 p 保存的变量 b 的地址值(%p表示用十六进制数字表示地址值)。指针还有特殊的操作:*操作
,通过*操作
可以访问指针所指向的变量,在程序中也就是说 *p
与变量 b
是等价的,操作变量 *p
就是操作变量 b
。
类型 | 变量 | 值 | 特殊操作 |
---|---|---|---|
int | a | a (使用 %d 打印) | 无 |
int * | p | p (使用 %p 打印) | *p (代表指向的变量) |
数组
数组是一种特殊的数据类型,它把具有相同类型的若干变量按照有序的顺序组织起来,极大的方便了我们的开发。数组名代表数组的首地址,即数组第一个元素的地址,通过下标 []
来访问数组里面的元素。
int main() { int a[5] = {1, 2, 3, 4, 5}; printf("%d\n", a[0]); return 0; }
上面代码中的 a[0]
代表数组中的第一个元素,输出的结果为1;
数组和指针的联系
其实数组的下标 []
操作也是一种特殊操作,与指针的 *
操作十分相似。数组名是一个指针:指针常量。它无法改变指向,只能指向数组的首地址,所以a++、a–之类的操作都是错误的(a是数组名)。既然数组名是一个指针,可以使用下标 []
操作,那么普通的指针变量是不是也可以使用呢?反过来,普通指针的 *
操作是不是也适合数组呢?
int main() { int a[4] = {5, 6, 7, 8}; int *p = a; int i; printf("输出数组里面的内容:\n"); for(i = 0; i < 4; i++) printf("a[%d] = %d\t", i, a[i]); printf("\n"); for(i = 0; i < 4; i++) printf("p[%d] = %d\t", i, p[i]); printf("\n"); for(i = 0; i < 4; i++) printf("*(a+%d)=%d\t", i, *(a+i)); printf("\n"); for(i = 0; i < 4; i++) printf("*(p+%d)=%d\t", i, *(p+i)); printf("\n"); return 0; }
运行结果:
运行结果
从结果可以看出,[]
和 *
操作都适用于指针变量,数组也是通过操作指针来实现对元素的查询、修改操作。让我们再深入一点,数组是如何通过下标操作找到对应的元素的呢?
int main() { int a[5] = {1, 2, 3, 4, 5}; int *p = a; printf("%d\n", p[2]); printf("%d\n", *(p+2)); p = &a[2]; printf("%d\n", p[0]); printf("%d\n", *p); return 0; }
运行一下代码发现,输出的数据都是3,也就是数组中的第三个元素。怎么会这样?
解释:
程序中当指针 p 指向数组的第三个元素的时候,这时候 p[0]
输出的是3,也就是a[2]
的值,那么 p[0]
的操作结果与 *p
的操作结果一致;另外,大家试一试
输出 p[1]
的值,不出所料操作结果应与 *(p+1)
的操作结果一致。发现规律没?[]
操作其实就是 *
操作啊!!!发现新大陆了啊,有没有?
让我们冷静的分析一下: []
操作和 *
操作实际上都是偏移操作(内存地址偏移),通过当前指针指向的内存地址以及常量来进行地址偏移,最后通过指针的类型解析所指向地址的内容。
那么偏移的单位是多少?这个与指针或者数组的类型有关,比如 int *
类型的指针一次偏移 sizeof(int)
的地址,double *
类型的指针一次偏移 sizeof(double)
的地址。
指针访问数组的方式
- 使用 [] 访问。例如
int a; int *p = a;
用 p 表示输出 a[2] 的值:p[2] ;如果是这样int a[5]; int *p = &a[2];
用 p 表示输出a[3] 的值:p[1]。 -
使用 * 访问。例如
int a[5]; int *p = a;
用 p 表示输出 a[2] 的值:*(p+2);如果是这样:int a[5]; int *p = &a[2];
用 p 表示输出 a[3] 的值:*(p+1)。
思考
知道指针和数组的操作原理后,下面的题你会做吗?
第一题:
int main() { int a[5] = {1, 2, 3, 4, 5}; p = &a[2]; printf("%d\n", p[-2]); printf("%d\n", *(p-2)); return 0; }
第二题:
int main() { int a[5] = {1, 2, 3, 4, 5}; int *ptr = (int *)(&a + 1); printf("%d %d\n", *(a+1), *(ptr-1)); return 0; }
第二题注意指针的类型变化哦,自己编写运行一下,看结果与自己想的一样吗?
ps: 竟然还能 p[-2],坑爹有没有…
总结
- 指针和数组都可以使用下标或者 * 操作。
- 下标操作或者 * 操作的本质都是地址偏移,通过指针的类型来解析内存地址里面存储的数据。
- void * 指针可以指向任何地址,但是无法使用 * 操作,原因就是编译器不知道如何解析void * 指针所指向的内存地址的内容。
原文地址:https://www.jianshu.com/p/bb0b685e7938
相关推荐
-
回文序列 c/c++
2019-6-29
-
C++ 开发 PHP 7 扩展之模块入口定义 c/c++
2019-3-28
-
为了更好更方便地活着——爱上private c/c++
2019-9-2
-
C/C++ 函数指针 c/c++
2019-3-29
-
前端如何学习 c/c++
2019-7-24
-
变量定义式——尽量延后定义时间 c/c++
2019-9-2
-
C与C++的差异 c/c++
2019-10-16
-
进程间通信 c/c++
2019-6-30
-
C语言轻松高效学习方法之:多种方法实现 c/c++
2019-3-30
-
Linux环境g++编译TinyXML动态库 c/c++
2019-9-15