C语言 ——— 指针笔试题(中篇)

指针加减整数和解引用的笔试题 

笔试题1:

int a[5][5];
int(*p)[4];
p = a;

printf("%p  %d", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

问:打印的结果为?(分别以 %d 和 %p 的形式打印)

解析:p = a; 

a是一个二维数组,a单独拿出来时是数组名,表示首元素的地址,而二维数组首元素的地址就是第一行元素的地址(也就是一个一维数组),那么这里a的类型是 int(*)[5] ,p是一个指针,这个指针的类型是 int(*)[4] ,把 a赋值给p ,那么把a赋值给p会发生截断,而p每次只能访问4个字节

解析:&p[4][2] - &a[4][2]

内存示意图:

p 每次加1只能访问4个字节,且同一空间的 指针 减去 指针 得到的是指针之间的元素个数,所以 &p[4][2] - &a[4][2] 以%d 的形式打印的结果是 -4 (因为是小地址 减去 大地址,且指针减指针没有绝对值的概念)

所以 &p[4][2] - &a[4][2] 以%d打印的结果是 -4

-4 存储在内存中补码的示意图:

以%p的形式打印,那么会把 -4的补码当作地址打印出来,这时就没有正负数之分了

-4 的补码以%p的形式打印示意图:

每4位二进制表示一位十六进制

所以 &p[4][2] - &a[4][2] 以%p的形式打印的结果是 FFFFFFFC 


笔试题2:

int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };

int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));

printf("%d  %d\n", (ptr1 - 1), *(ptr2 - 1));

问:打印的结果为? 

代码解析:

aa是一个2行5列的二维数组,所以 { 1,2,3,4,5,6,7,8,9,10 } 等价于 { {1,2,3,4,5} , {6,7,8,9,10} }

解析:int* ptr1 = (int*)(&aa + 1); 

&数组名,取出的是整个数组的地址,加1后指向的是数组最后一个元素的下一个位置的地址,把地址强制类型转换为 int* 类型,再用 int* 类型的ptr1接收

解析:*(ptr1 - 1) 

ptr1 指向的是aa数组的最后一个元素的下一个位置,减1后指向了数组最后一个元素的首地址,再解引用,就拿到了数组的最后一个元素,且最后一个元素是10

所以 *(ptr1 - 1) 以%d的形式打印的结果是 10

解析:int* ptr2 = (int*)(*(aa + 1)); 

aa是数组首元素地址,而二维数组的首元素地址是第一行所以元素的地址,也就是一个一维数组,那么 aa + 1 后指向的是数组第二行的所以地址,强制类型转换为 int* 后赋值给 int* 类型的ptr2,那么此时ptr2指向的就是二维数组aa 的第二行的第一个元素的首地址,也就是元素为6的首地址

解析:*(ptr2 - 1) 

因为不论是一维数组还是二维数组,存储在内存中的数据都是连续的,所以 ptr2 - 1 就指向了数组的 上一个元素的首地址,也就是 5 这个元素的首地址,再解引用,拿到的就是5这个元素

所以 *(ptr2 - 1) 以%d的形式打印的结果是 5


笔试题3:

char* a[] = { "work", "at" , "alibaba" };

char** pa = a;

printf("%s\n", *(pa + 1));

问:打印的结果为? 

代码解析:

a是一个字符指针数组,a的类型是char**,存储的并不是常量字符串,存储的是常量字符串的首元素地址,所以存储每个元素的类型是 char*

解析:char** pa = a; 

a是一个二级指针,要存储a的话,需要二级指针才能存储,所以存储到的是 char** 类型的 pa,此时的pa指向的也是 数组a 首元素的地址,也就是 字符 'w' 的首地址

解析:*(pa + 1) 

pa + 1 后就指向了 数组a中的第二个元素的首地址,再通过%s的形式打印 ,打印的就是第二个常量字符串

所以 *(pa + 1) 以%s的形式打印的结果是 "at" 

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值