最近在找工作所以找了些科技公司的笔试题来做做。
今天做的一道题就听有意思的。
我们在c语言编程的时候,会非常多的用到数组,做缓冲区也好,存储字符串也好,存储数据也好。
但是我们用的都是一维数组,二维数组很少今天我们就来讨论一下二维数组的特性。
我们先来看看这个笔试题:
-
下列程序的运行结果是______
intmain()
{
inta[5][2] = {
0,1, 2, 3, 4, 5, 6, 7, 8, 9
};
int*p = a[0];
int(*p2)[2] = &a[1];
++p;
++p2;
printf("%d",*p); 1
printf("%d",**p2); 4
printf("%d",p2[1][2]); 8
答案在题后面标出了。
我们说说这道题的地址传递吧。
首先是声明了一个二维数组,5行2列(我想这么说会直观一点在我之后的分析中)
那么它的排列结构我假定为:
0 1
2 3
4 5
6 7
8 9
那么对应于它的数组名分别为
a[0][0] a[0][1]
a[1][0] a[1][1]
a[2][0] a[2][1]
a[3][0] a[3][1]
a[4][0] a[4][1]
接着我们声明了两个指针变量
int*p = a[0];
int(*p2)[2] = &a[1];
第一个自不必说,*p指向数组开头第二个就有些意思了,从C 语言语法翻译过来是*p2是个数组头,它的第三个变量指向a[1]的地址
然后我做了下测试
**p == 2
*p[1]==4
*p[2]==6
那么也就是说我们上文的认为是错的,不管*p2后面跟的数据是多少,a[1]的地址都是指向*p2的而后面的[2]也根本不是
数组元素的意思,而是二维数组的意思,所以我们对*p2进行加一操作的时候,它的地址会直接增加2,这个我也做了
测试,如果我们把后面的2换成4的话,那么*p2[1]指向的就是6了这样我们就明白了这种赋值方式。
接着是一个加一操作
++p;
++p2;
如我们所知,数组的地址都是连续的,我想二维数组也一样。所以我们在打印的时候就很快明白了
printf("%d",*p); 1
printf("%d",**p2); 4
这两句话的结果了,一个是地址加一,第二个由于声明的时候是一个二维数组的方式,所以加一的跨度是地址上的两个(实际上,我觉得应该是加1加在了p[i][j]中的i上了)
然后就是最后一句打印信息了
printf("%d",p2[1][2]); 8
为什么是8呢?我们先来分析一下,
p2的值的变化
最开始它指向2也就是a[1][0]
那么他加一以后呢
p2指向的是a[2][0]也就是数值4,
接着p2[0][1] p2[0][2] p2[1][1] p[1][2]
的值分别是5 6 7 8
其实由于地址都是连续的我们不必每次都把“行”“列”号写清楚。
如果我们打印 p[1][3]会是什么结果呢?
测试结构是9。
我在做测试的时候发现,p2[0][6]于p2[2][2]的结果是相同的(注意现在的p2没有执行++操作。)
这样在我看来二维数组并不像,我们所常认为的那样,是行列的形式。
也就是
a[0][0]~~~a[5][2] 等价于 a[0][0]~~~~~~~~~~~a[0][10] 这个猜想测试是正确的。不过如果不是二维数组的形式,打印出的结果就不是正确的了,
也就是说二维数组是对格式有要求的。