关于C语言指针数组的一些理解
最近在准备考研复习数据结构,重新拿起来好久不用的C语言,在学习的过程中发现了之前没有学习到的知识点----- 指针数组。虽然感觉指针数组很少会遇到和用到(至少在学习阶段),但我感觉搞懂指针数组对于本来就不是很理解指针的人有很大帮助,因此在这里写下自己的一些浅薄之见供大家参考,我理解不对的地方还请大家指正。
众所周知,就像下面这段代码一样,要初始化一个int类型的指针,就要传入一个int类型变量的地址。
int number=0;
int *numbertoken=&number;
那么我们能不能定义一个指向指针的指针呢?
int ** numbertwicetoken;
那我们在初始化它时传入的应该是&numbertoken,也就是numbertoken的地址,而不是numbertoken,因为在这里numbertoken的值是number的地址。
numbertwicetoken=&numbertoken;
那我们再来看下面的代码
char string[]="hello world";
char *stoken=string;
在这里我们初始化字符指针时传入的是string而不是&string,这是因为在存储数组中,string存储的是数组中第一个元素的地址,而&string的含义是整个数组的地址,但如果你尝试以整形打印string和&string你会发现他们的值是一样的,也就是说数组的地址就是数组第一个元素的地址。那么问题来了,我是否能将代码写成这样呢?
char *stoken=&string;
显然是不可以的,这里的&string是数组的地址,而我们定义的指针是字符指针,应该传入字符的地址,而&string应该传入到数组指针中,注意这里是数组指针,而不是指针数组。顾名思义数组指针是指指向数组的指针,让我们来看它的定义方式:
char (*stoken)[12]=&string;
注意重点这里的*stoken是在括号里的,在C语言中()的优先级要大于[],所以stoken要先是一个指针,因此这里stoken是一个指向数组的指针。
那么那么那么,如果去掉括号呢,那就是这次的主角了-----指针数组
指针数组,就是数个指针组成的数组,该数组中的每一项都是一个指针,下面我们来看指针数组的声明方式
char * string2[]={"hello","world"};
在C语言中[]的优先级要高于星号因此 string要先是一个数组,所以string2是一个指针数组。
为了继续探究指针数组的难点,首先让我们先回到刚刚声明的字符数组string,刚刚我们说过string的值是该数组中第一个元素的地址,因此*string得到的值将是该数组的第一个元素的值也就是“h”
printf("%c\n",*string);//输出结果为h
咱们会发现这一点与指针一模一样,但string是一个指针吗?
并不是。
表面上看string是一个指向“h”的字符指针可以实现和stoken一样的功能。但如果我们用二重指针来测试一下
char **stwicetoken=&string
char **stwicetoken=string
这俩段代码是会报错的,第一个的原因是&string是数组地址,而第二个是应该是赋值给stoken这种第一层指针。
那么再让我们回到我们的指针数组string2上来,
这时如果我们这样编写一段代码就完全不会出错
char **stwicetoken=string2;
好多小伙伴第一次看到这段代码可能会一懵
但其实只要深入思考一下就会发现这很合理。
string2是一个指针数组,string2的值是这个数组第一个元素的地址,而这个是个指针数组,所以第一个元素也就是string2[0]是指针!所以这段代码就相当于
char **stwicetoken=&string2[0];
那我们来继续缕一缕整个指针数组的地址问题。
首先我们知道string2的值就是string2[0]的地址值,那可能有人就要想了,那string2[0]是一个字符数组,所以string2[0]的地址就是字符数组的首元素的地址,因此string的值就是“h”的地址值。这是不对的!!!!
要注意string2[0]是一个指针,它指向了"hello"这个字符数组,因此他的值是"hello"这个字符数组的首地址,而string2[0]的地址则是另一个值,这就相当于之前的字符指针&stoken与stoken的区别(stoken的值是string的地址,而stoken也拥有自己的地址&stoken),而不是像字符数组&string与string的值相等一样(数组的地址就是数组首元素的地址)。因为stoken是一个指针,而string是一个字符数组!!字符数组的地址等于它首元素的地址,而指针不是。
画了一个草图帮助大家理解一下:
因此执行下列代码得到的结果是一样的。
printf("string2[0]:%d\n",string2[0]);
printf("*string2:%d\n",*string2);
因为string2[0]是string2数组中首元素的值,而string2指向string2[0]的地址,而*string2便是string2[0]的值,所以这两段代码取到的都是"hello"这个字符数组的首地址。
同理
printf("string2[1]:%d\n",string2[1]);
printf("*(string2+1):%d\n",*(string2+1));
这哥俩取到的便是"world"这个字符数组的首地址
再看这段代码
printf("*string2+1:%s\n",*string2+1);
得到的则是字符串"ello",这是因为我们在*string2的基础上加一,便是使指针从"hello"的首地址向后移一位,指向了第二个元素"e"的地址
那么再看这两行代码
printf("*string2[0]:%c\n",*string2[0]);
printf("**string2:%c\n",**string2);
取到的则是"h"这个字符,因为*string2与string2[0]为"h"的地址。
printf("&string2[0]:%d\n",&string2[0]);
printf("string2:%d\n",string2);
这两段代码得到的是string[0]这个指针的地址
printf("*string2[0]:%s\n",string2[0]);
printf("**string2:%s\n",*string2);
这两段代码的打印结果则为”hello“
个人感觉指针数组可以帮助大家缕清指针与指针直接地址的关系,对学习C语言有很大的帮助,这篇文章也就相当于我自己的学习笔记了,拿出来和大家交流一下(主要目的是找找大腿抱一下)。