C语言面试题详解(第10节)
发表于: 2019-02-26 18:58:47 | 已被阅读: 27 | 分类于: C语言
对于很多C语言初学者来说,指针是一大难点,但是指针也是C语言非常关键的组成部分,离开了指针,C语言几乎就只能处理小学数学题了。其实,指针虽难,肯定没有难到大多数人学不会的程度。之前的文章也强调过:
先来看看下面这个题目
下面这个题目是美国某著名软件公司的一道面试题,它的C语言代码如下,请看:
#include <stdio.h>
int main()
{
int v[2][10] = {
{1,2,3,4,5,6,7,8,9,10},
{11,12,13,14,15,16,17,18,19,20}
};
int (*a)[10] = v;
printf("%d, %d, %d, %d, %d\n", **a, **(a+1),
*(*a+1), *(a[0]+1), *(a[1]));
return 0;
}
初步分析
显然,这是一道考察指针的题目,关键点在于指针 a。按照上面说的:“在理解指针时,要像 char,short,int 一样,把它也当做是一种数据类型”,那么 a 其实就是一个 int [10] 类型的数组指针。
“a 是 int [10] 类型的数组指针”,上一节文章已经较为详细的分析过,这里就不再赘述了,读者若感到费解,可以看看上一节的文章。
那么,这个C语言程序会输出什么呢?得到答案最简单粗暴的方法就是编译并执行这段程序,请看:
# gcc t.c
# ./a.out
1, 11, 2, 2, 11
答案是 1, 11, 2, 2, 11,为什么呢?最好理解的是
二维数组在内存中的数据存储
应该明白,即使是二维数组,其在内存中也是线性存储的:
int a[] = {1, 2, 3};
但是在定义二维数组时,不指定二维数组的第二维就不允许了:
// 报错
int a[][] = {{1,2}, {3,4}};
相信读者现在应该明白原因了,因为编译器在访问二维数组数据时,需要知道数组的第二维数才能计算得到要访问的地址。知道了这一点,再分析上面这个面试题就简单了,请继续往下看。
C语言中的指针移动
文章开头提到:“语言中变量的
同样的道理,short 类型占用 2 字节内存空间,因此 short 型指针是逐 2 字节访问内存的,若 ps 指向地址 1,那 ps+1 显然就执行地址 3 了。char 型指针的移动分析也是类似的,就不赘述了。
到这里,相信读者也发现了,指针的加减法似乎并不严格的遵循 1+1=2 的数学规则,对于 int 型指针来说,1+1 居然“等于”4,而对于 short 型指针来说,1+1 又“等于”2 !
现在再来分析面试题的C语言程序就简单了,因为指针 a 是 int [10] 型的,所以在考虑指针 a 的加减法时,它的“单位”就是 sizeof(int [10]),也即是 10。那么,既然 a 指向数组 v 中的 1,a+1 就指向 11,这就解释了上面的C语言程序输出的第二个数字。
再来看看第三个数字。我们使用符号 T 表示 int [10] 类型,那么指针 a 就是 T 型指针,数组 v 的定义则可以写成 T v[2],那么
第四个数字的分析和第三个数字是类似的(因为这里 a[0] 和
小结
本节,我们先分析了二维数组在内存中的存储方式,然后讨论了C语言中指针的移动,发现其实只要考虑指针的“单位”,分析指针的加减就简单了。最后,我们把指针像 short、 int 一样当作是一种数据类型,分析了一道面试题。