定义是这样:
多级指针(二级指针),C语言多级指针的用法详解 (biancheng.net)
这是针对变量,且是一级一级的取的。但是我们经常要面对数组,用到二级指针。如前面第一篇所述,对一维数组名取地址,则表示数组地址,再对其求值,则表示首元素的地址,所以按说对一维数组名取地址就是二级指针,可以定义一个二级指针,然后将一维数组名取地址赋值给它。
但是,实际写程序发现会报错:
编辑器就报错了。编译:
可见,虽然&a是指向指针的指针,但如第一篇所述,它确是指向4个元素数组的指针,也就是指向一个行数组的首个元素,是有限制的,类型是int (*)[4],并不表示是指向一个int变量的地址,即int **。
那么,按说,因为数组第一个元素是int型,我对数组第一个元素取地址后再取地址,应该是二级指针int**了吧?尝试:
pp = &(&a[0]);
编译报错:
这里用了两个&号,表示取两次地址,含义 上是没错的,这报错,是C语法的问题,是将前面一个&当成与操作,所以需要左值是变量或者函数调用形式,而右边只有括号里的&是真取了地址,所以报C2440,无法从int*转换为int**。
那么,这种赋值是不行的么?难道说二级指针不能指向数组的么?非也!这里就有个神奇的讲究了。其实就是和参考文章中一样,也就是一般二级指针赋值一样,分两次赋值就可以啦!
int a[4] = {1,3,5,4};
int** pp; // 二级指针
int* p;
p = &a[0];
pp = &p;
这种其实是多此一举了,还不如直接用p,因为其实pp表示存第一个元素的地址的地址,pp+1这种操作已经和原数组没什么关系了。程序:
#include <stdio.h>
int main()
{
int a[4] = {1,3,5,4};
int* p;
int** pp;
printf("a=%d\n", a);
printf("&a=%d\n", &a);
printf("*a=%d\n", *a);
printf("a+1=%d\n", a + 1);
printf("&a+1=%d\n", &a + 1);
printf("*a+1=%d\n", *a + 1);
p = &a[0];//a代表数组首元素地址
pp = &p;
printf("p=%d\n", p);
printf("pp=%d\n", pp);
printf("*p=%d\n", *p);
printf("*pp=%d\n", *pp);
printf("**pp=%d\n", **pp);
printf("p+1=%d\n", p + 1);
printf("pp+1=%d\n", pp + 1);
printf("*(p+1)=%d\n", *(p + 1));
printf("**(pp+1)=%d\n", **(pp + 1)); // 这行编译不报错,但运行报错,非法访问内存空间
return 0;
}
运行到倒数第二个printf:
a=177208296
&a=177208296
*a=1
a+1=177208300
&a+1=177208312
*a+1=2
p=177208296
pp=177208344
*p=1
*pp=177208296
**pp=1
p+1=177208300
pp+1=177208352
*(p+1)=3
注意看*(p+1),即可表示下一个元素,但是**(pp+1),并不是表示第二个元素值,而是因为pp+1这个地址不允许访问而执行出错!
将上面程序中的p初始化赋值语句改为:
p = a;
结果是一样的。其实也是,因为一维数组名就是首元素的地址。
所以,重点来了,对于一维数组,这种二级指针其实是多此一举了,那么对于二维数组呢?应该是刚刚好了吧?
下篇讨论吧~