数组、字符串和指针 | C指针基础(二)
- 数组名 arr、&arr 与 &arr[0] 打印结果为何相同?
- 字符串与指针
- 利用指针读取数组
数组名 arr、&arr 与 &arr[0] 打印结果为何相同?
先运行下面这段程序:
#include<stdio.h>intmain(){intarr[10]={0};printf("%d\n",arr);printf("%d\n",&arr);printf("%d\n",&arr[0]);return0;}运行后你会发现,三个 printf 打印出来的结果完全相同,并且输出的都是地址。这是因为:在表达式中,数组名 arr 会退化为指向首元素的指针,其值等于&arr[0];而&arr取的是整个数组的地址,虽然类型不同,但地址数值也与首元素地址相同,因此三者打印结果一致。
也就是说:在C语言中,数组名本质上是一个指针,存储的是该数组第一个元素的内存地址。数组名的取地址和取第一个元素的地址是同一个操作。
字符串与指针
我们知道,在 C 语言中,字符串本质上也是一种字符数组,因此可以仿照上一节的方式运行下面的程序:
#include<stdio.h>intmain(){charname[10];charname1[10];charname2[10];scanf("%s",&name);scanf("%s",name1);scanf("%s",&name2[0]);printf("%s\n",&name);printf("%s\n",name1);printf("%s\n",&name2[0]);return0;}运行后你会发现,分别向 name、name1、name2 输入内容后,三个 printf 都能正确打印出最开始输入的字符串,而不是像上一节那样打印地址。
这是因为两次示例使用的格式占位符不同:数组示例中使用%d,打印的是指针本身保存的地址数值;而字符串示例中使用%s,printf会沿着传入指针所指向的首字符开始,逐个读取并输出字符,直到遇到\0结束符,因此最终打印出来的是完整的字符串内容。
对比示例:
// 数组示例:%d 输出地址printf("%d\n",arr);// 输出类似:一串地址数值// 字符串示例:%s 输出字符串printf("%s\n",name);// 输出类似:hello(你输入的内容)也就是说:在 C 语言中,字符串是字符数组,字符串名同样可以看作指向首字符的指针;&name、name、&name[0]在数值上都等于字符串首字符的地址。
利用指针读取数组
前面已经知道,数组名在表达式中会退化为指向首元素的指针,因此除了用下标访问,还可以利用指针来读取数组元素。先看下面的程序:
#include<stdio.h>intmain(){intarr[10]={10001,20003,0};printf("%d\n",*arr);// 等价于 arr[0]printf("%d\n",*(arr+1));// 等价于 arr[1]return0;}运行后会输出:
10001 20003根据上一篇笔记可知,*是解引用运算符,用来取出指针所指向的内容;而数组名arr本身就表示首元素地址,所以*arr就是取出第一个元素,等价于arr[0]。
同理,arr + 1并不是把地址简单地加 1 个字节,而是按照指针指向的类型自动步进。因为arr是int类型数组,arr + 1会指向下一个int元素,也就是arr[1]的地址;再对它解引用,就得到第二个元素的值。
下面两组写法完全等价:
printf("%d\n",arr[0]);// 下标方式读取第一个元素printf("%d\n",*arr);// 指针方式读取第一个元素printf("%d\n",arr[1]);// 下标方式读取第二个元素printf("%d\n",*(arr+1));// 指针方式读取第二个元素推广到一般情况,arr[i]与*(arr + i)等价,这就是 C 语言中指针与数组之间的联通关系。