前言
近些天探究Linux内核双链表部分的知识进程缓慢,发现其根源还是基础不牢固,之前对C语言的学习只停留在做题的层面,对一些概念理解的迷迷糊糊,这几天我重新学习了指针部分,也就是C语言中的难点部分。发一篇博客来说说困扰了我好几天的数组指针、指针数组以及二级指针。
概念
数组指针:首先数组指针是一个指针,指向数组地址,它指向的是数组中的具体元素,并不是整个数组,所以说数组指针的类型和数组元素的类型有关,在32位系统下永远占4个字节。
指针数组:首先指针数组是一个数组,数组中的元素都是指针,数组占的字节数由数组本身决定,数组中的每个元素都是指针。
二级指针:通过指针变量可以访问数组元素,要求它的类型必须是指向该元素类型的指针类型。那么想要通过指针变量访问指针数组的元素,就必须定义二级指针,即为指向指针的指针,用二级指针变量指向指针数组的各元素。
演示
判断指针数组与数组指针
int (*a)[5];
int *b[5];
-
()的优先级比[]高,所以*号与()先构成一个指针的定义,该指针变量名为a,int即为数组中每个元素的类型,a是一个指针,指向一个包含5个int类型数据的数组,即数组指针。
-
[]的优先级比*高,所以说b先与[]结合构成一个数组,b为数组名,int是数组里每个元素的类型,数组中包含5个指向int类型数据的指针,即为指针数组。
关于数组指针
我们正常定义一个指针变量都是直接加在指针类型后面的,比如说:int (*)[5] p 这种样子,通过查阅资料,数组指针的原型的确如此,只不过为了美观将指针变量前移了而已。
利用指针遍历数组元素
#include <stdio.h>
int main(void)
{
int arr[]={1,2,3,4,5,6,7,8} //定义数组
int len;
len=sizeof(arr)/sizeof(int); //数组的长度
int i;
for (i=0;i<len;i++)
{
printf("%d",*(arr+i)); //*(arr+i)即为arr[i]
}
printf("\n");
return 0;
}
这里arr是数组名,表示数组首元素的地址,arr+i指向数组的第i个元素,*(arr+i)表示取数组中第i个数据,等价于arr[i],这里的arr是int *类型的指针,arr每加1,自身就会加上sizeof(int),也就是4,arr+i也就是自身的值加上i * sizeof(int)
利用数组指针遍历数组
#include <stdio.h>
int main(void)
{
int array[]={1,2,3,4,5,6,7,8};
int len;
len=sizeof(arr)/sizeof(int);
int *pp=arr;
int i;
for (i=0;i<len;i++)
{
printf("%d",*(pp+i));
}
printf("\n");
}
这里的sizeof(arr)不可以换成sizeof(pp),因为这里的pp是变量,而arr是字符常量,编译器不能明白pp指向的是一个元素还是整个数组,所以这里的sizeof(pp)求的仅仅是这个指针变量所占有的字节数,在32位系统下也就是4,并不是整个数组所占的字节数。
所以说,通过上述两个例子我们不难发现,要想访问数组元素,可以通过数组下标或者指针来进行。
使用下标
用arr[i]的形式访问数组元素,如果指针pp指向arr,也可以用pp[i]来访问数组元素,其等价于arr[i]。
使用指针
也就是通过 *(pp+i)的形式来访问数组元素,其等价于 *(arr+i),因为arr本身也是指针。
所以说不管是用数组名还是数组指针都可以访问数组元素,不同的是数组名是字符常量,不能随意改变,它只能指向数组的开头,而指针变量即可以随意改变,既可以指向数组开头,也可以指向数组任意位置,这点一定要注意。
例子如下图
#include <stdio.h>
int main(void)
{
char *pp[5]={"mmhdsg1997715","building","linux","interesting","funny"};
char *str1=pp[1];
char *str2=*(pp+2);
char a=*(*(pp+2)+4);
char b=(*pp+3)[2];
char c=*pp[1]+3;
printf("str1=%s\n",str1);
printf("str2=%s\n",str2);
printf("a=%c\n",a);
printf("b=%c\n",b);
printf("c=%c\n",c);
return 0;
}
运行后的结果如下图:
str1=building
str2=linux
a=x
b=g
c=e
这里的pp为二级指针,也就是指向指针的指针,所以*(pp+i)为指针, **(pp+n)为具体的字符。
答案解释
1 、这里的pp[1]即为*(pp+1),它是一个指针,指向字符串str1。
2、这里的*(pp+2)即为pp[2]。
3、这里的*( *(pp+2)+4 )可以写成 *(pp[2]+4),其中pp[2]+4就是字符串"linux"第四个字符的地址(指针就是地址),所以 *(pp[2]+4)就是"linux"第四个字符即为’x’。
4、这里的(*pp+3)[2]可以写成( *(pp+0)+3)[2]等价于(pp[0]+3)[2]等价于 *((pp[0]+3)+2)等价于 *(pp[0]+5),即为字符串"mmhdsg1997715"第五个字符’g’。
5、这里的*pp[1]+3即为 *(pp[1]+0)+3为字符串"building"的第0个字符’b’的ASCII码值加上3,即为字符’e’。
总结
希望自己的总结能帮助到大家吧!