int b[m][n]和int **b——关于数组名和指针的关系这件“小事”

来源:互联网 发布:合肥淘宝兼职 编辑:程序博客网 时间:2024/06/07 13:12
#include<stdio.h>int pa(int *a){return a[3];};int pb(int **b){return b[1][4];};int main(){int a[] = {1,2,3,4,5};int b[][5] = {{1,2,3,4,5},{6,7,8,9,10}};printf("%d\t%d\n",a[3],b[1][4]);printf("%d\n",pa(a));printf("%d\n",pb(b));     //is this right??printf("0x%x\t0x%x\t0x%x\t0x%x\n",b, b[0], &b[0], &b[0][0]);return 0;}


先看上面一段代码,是不是觉得没有什么问题?

那么你可以先自己尝试跑跑看。

编译时有warning,运行时直接segment fault。



仔细想想,二维数组int b[m][n]的数组名可以直接传给形参为int **b的二级指针吗,他俩的性质是对应的吗?

经过验证之后,答案显然是否定的。

int **b大家都知道是指针的指针,也就是地址的地址。即它本身是一个地址值,这个地址指向的内存单元里又是一个地址值(即int *b),然后这个地址指向的内存单元才存着一个整型数(int b)。

然而对于int b[m][n],翻了翻大一的《C语言程序设计》,里面赫然写着:

用数组名表示数组在内存中的起始地址,一维数组是如此,多维数组也是这样。

当年丹尼斯-里奇就是这样设计的C语言及其编译器,至于为什么这样,我暂时还不想去深究个中原因,就当是个结论先记住吧。

将产生段错误的那句注释掉,再编译运行,可以发现最后一个printf语句中,虽然四个参数的类型不都相同,但对应的地址值都是一样的,即都是多维数组在内存中的起始地址。



话说之所以想到这个问题,是在刷leetcode题目的时候,给的要实现的函数形参为int **b,自己写完后提交WA了,于是自己又写了个main函数想调试下,结果在写main函数的时候开始直接把二维数组的数组名当实参给传过去,出现了段错误。后来只好老实的用malloc函数申请了一个二级指针的空间,再老老实实的去指向若干个一维数组。


刚才又重新看了一下当年教材的相关章节,没发现有用int **b作为形参的函数例子。然后发现了书中用指向数组的指针表示多维数组的例子,才发现:

原来N维数组的数组名的性质等同于指向(N-1)维数组的指针。

即int b[m][n]的数组名b的类型为int(*p)[n],其实这个编译的时候已经给出来了,可我没有去在意。


那么int **b能否可以作为形参,接受二维数组名作为实参的传值(址)呢,从上面的结论和目前做的实验,我觉得编译器是没有这样做的。

最后再写一下我个人的理解:

1)int **p,这里的p是一个指向存着整型数地址值(数据类型为 int *)的内存单元的指针。

2)int b[m][n],b的数据类型为int (*)[n],这里的b是一个指向长度为n的一维整型数组的指针。

看红色的地方即可,这两句话是一样的吗?

显然是有区别的。

一个内存单元里存着一个整型指针,它就一定指向一个长度为n的整型数组吗?

显然不是的,比如说它可能是个空指针。就算不是空指针,它指向的数组长度是多少呢?显然不一定就是n。


原来问题的关键,还是在于内存是否被分配上。



0 0
原创粉丝点击