C语言|C 语言与指针 , 指针部分笔试题目及解析

一 、 回顾两个定义
在开始讲解题目之前先回顾一下两个概念,数组指针和指针数组。
数组指针,即数组的指针,是指针,其内容指向一个数组。例: int(*)p[5] 即为指向数组的指针,称数组指针。
【C语言|C 语言与指针 , 指针部分笔试题目及解析】指针数组,即数组元素全为指针的数组。例: int *p[5] 有5个指针类型的数组元素。
二 、 C与指针题目
1. 下列程序的输出结果?

int main() { int a[5] = { 1, 2, 3, 4, 5 }; int *ptr = (int *)(&a + 1); printf( "%d,%d", *(a + 1), *(ptr - 1)); return 0; }

分析: (1)第四行中 (int* )(&a + 1)首先 &a 是取数组地址,意为 int(*)[5], 然后 + 1跳过整个数组。所以 ptr 指向元素 5 后面的地址。那么 ptr - 1 表示 数组a最后一个元素 5 的地址,然后解引用输出结果为 5 .
(2)第5行中 *(a+1)数组名不能直接 + 1,所以此处a被转换成指针,指向数组的第一个元素,再a+1表示数组第二个元素地址,然后解引用输出,得到结果 2.
(3)输出结果为 2 , 5.
2. 下列程序输出结果是什么?
struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4]; }*p; int main() { printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }

分析: (1)结构体的长度为 4 + 4 + 2 + 1*2 +2*4 = 20.
(2)假设结构 p 地址为 0x00000000.
(3)第一个 printf 中p + 0x1 p是结构体指针,p + 1 跳过整个结构体指向下一个内容。所以应该跳过20. 由于该打印通过16进制表示,20的16进制为0x14,所以该printf 的输出结果为 0x00000014 .
(4)第二个 printf 中(unsigned long) p 表示将p结构体类型转换成unsigned long 类型,再+1 表示数字 +1 ,即 0x00000000 + 0x1 结果为 0x 00000001;
(5)第三个printf 道理同 (4) 将p 转换成 unsigned int* 型,指针 + 1 , 由于unsigned int 长度为4 ,所以(unsigned int *)p + 0x1即 0x00000000 + 0x4结果为 0x00000004.
(6) 最后的输出结果为 0x000000014; 0x00000001; 0x00000004.
3. 下列程序输出结果是什么?
int main() { int a[4] = { 1, 2, 3, 4 }; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf("%x,%x", ptr1[-1], *ptr2); return 0; }

分析:(1) 代码第四行中 (&a + 1)中 &a 表示 int(*)[4], 所以+1之后跳过整个数组指向下一个内容。所以ptr1指向数组元素4之后的内容,输出时 ptr[-1] 相当于*(ptr1 - 1)此时指向内容并解引用结果为4, 以x%形式输出为 4.
(2) 代码第五行中 ((int)a+1)a 本来为数组名,这里转换成指针,指向数组首元素地址,然后又强转为int整形,再对int整形 + 1. 此时该地址为首元素中第二个字节的地址,然后以int* 型解引用,即从首元素第二个字节的地址向后读四个字节,此时内容变为首元素第二个字节和第二个元素的前三个字节,其地址及内容的变换如下图:

C语言|C 语言与指针 , 指针部分笔试题目及解析
文章图片

(3) 测试机的存储顺序为小段字节序,所以其存储内容如图所示。所以*ptr2的内容用16进制表示输出为 20000000.
4. 下列程序输出结果是什么?
int main(int argc, char * argv[]) { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int *p; p = a[0]; printf( "%d", p[0]); }

分析:(1)代码第三行定义数组时,注意赋值时采用了都好运算符,所以其内容数组的内容为:
13
50
00
(2)首先,该二维数组表示数组a中有三个元素,每个元素中又有两个元素,则指针 p 为数组的收元素地址。
(3)p[0] 表示 *(p + 0)即a[0][0], 所以输出结果为 1 .
5.下列程序输出结果是什么?
int main() { int a[5][5]; int(*p)[4]; p = a; printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); return 0; }

分析:(1)代码中 int(*p)[4] 表示指针p指向4个元素的地址。同时 int[4][4]可隐式转换成int(*)[4].
(2)通过下图展示数组a和数组p的内容。
C语言|C 语言与指针 , 指针部分笔试题目及解析
文章图片

(3)由图可见 &p[4][2] - &a[4][2]表示两个地址之间有几个元素,由于a地址大,p地址小,故结果为-4,
(4)输出结果为 16进制的-4 和十进制的-4.

三、 总结
暂时先分析这几个指针题目。指针是C语言的难点也是重点,特别在实际使用中数组和指针之间灵活的隐式转换给我们的使用带来了诸多不便,所以在使用数组和指针时要注意其具体表示的内容,然后进行程序代码的分析。


    推荐阅读