C语言刷题(20)

指针笔试题

笔试题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;
}
//程序的结果是什么?

*(a + 1)等同于a[1],第一个是2,a的类型是int [5],&a的类型就是int(*)[5],
是个数组指针。所以给int(*)[5]类型加一,相当于加了一个int [5]的长度。也就
是这个指针直接跳过了a全部的元素,直接指在了刚好越界的位置上,然后转换成了
int *后再减一,相当于从那个位置向前走了一个int,从刚好越界的位置回到了5的
址处,所以第二个是5



笔试题2

由于还没学习结构体,这里告知结构体的大小是20个字节

struct Test
{
    int Num;
    char *pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
    p = (struct Test*)0x100000
    printf("%p\n", p + 0x1);
    printf("%p\n", (unsigned long)p + 0x1);
    printf("%p\n", (unsigned int*)p + 0x1);
    return 0;
}

本质上考察指针加1的知识点:

p = 0x100000

p + 0x1 为跳过一个结构体指针(20字节),所以为0x100014

(unsigned long)p + 0x1  为强制类型转换为整型(1048576),整型数字加1(1048577),写成16进制就是0x100001

(unsigned int*)p + 0x1   为强制类型转换为整型指针,加的就是一个指针的大小4/8,就是0x100004/8

而在X86环境下打印,地址是4个字节

答案就是:

0010014

0010001

0010004

笔试题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;
}

ptr1[ -1 ] == *(ptr1-1)   因为ptr1直接指在了刚好越界的位置上,然后转换成了
int *后再减一,相当于从那个位置向前走了一个int,从刚好越界的位置回到了4的
址处,所以是4

(int)a + 1  假设a的首元素地址为0x0012ff40,将它强制转换成 int 整型,整型数字加1,就是0x0012ff41,相当于往后移了一个字节,再将它强制转换成 int* 指针类型,假设是小端存储,存储形式就是  01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ,而 *ptr2 解引用就是往后读取4个字节(因为是int *)大小(00 00 00 02)0x02000000,又因为是以%x形式打印,所以就是16进制。答案是2000000


笔试题4

#include <stdio.h>
int main()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  int *p;
  p = a[0];
  printf( "%d", p[0]);
  return 0;
}

答案是1

注意:(0, 1), (2, 3), (4, 5)是逗号表达式,不是每一行数组的内容,因为二维数组每一行也是一个数组,所以也要用{ },所以{ (0, 1), (2, 3), (4, 5) }表示的其实是{1,3,5},因为a[0] 是第一行的数组名,就是数组第一行的首元素地址(即a[0][0]),p[0] == *(p+0) == *p ,所以就是a[0][0]


笔试题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;
}

注:指针 - 指针 结果是指针之间的元素个数

a表示二维数组首元素地址,也就是数组第一行的地址,p = a 相当于将int(*)[ 5 ]类型的指针赋给 int(*)[ 4 ]类型的指针,而p+1 == &p[ 1 ]跨过的是四个整型大小,a+1跨过的是5个整型大小,所以算出&p[4][2] - &a[4][2]为-4(相差4个整型大小),而前面是用%p打印,相当于把-4当作地址,-4在内存中是以补码的形式存储的,就是11111111 11111111 11111111 11111100,16进制就是0xff ff ff fc

所以答案是:0xff ff ff fc,-4


笔试题6

int main()
{
  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", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}

&aa + 1 是整个二维数组的地址+1,就是刚好越界的位置,再强制转换成int *,所以*(ptr1 - 1)就是往前移一个int大小,就是指向9,再解引用

*(aa + 1) == aa[ 1 ] 中aa是二维数组首元素的地址,就是第一行的地址,再加1就是第二行的地址,解引用就变成第二行第一个元素的地址,再强制转换成int *,所以*(ptr2 - 1)就是往前移一个int大小,就是指向5,再解引用


笔试题7

#include <stdio.h>
int main()
{
    char *a[] = {"work","at","alibaba"};
    char**pa = a;
    pa++;
    printf("%s\n", *pa);
    return 0;
}

    char *a[] = {"work","at","alibaba"}是将"work","at","alibaba"三个字符串的首元素(w , a , a)的地址放入a数组里

   char**pa = a;就是pa指针的地址指向a数组首元素的地址(w)

    pa++;就是pa指针的地址指向a数组第二个元素的地址(a)

最后以%s打印,就是从a的地址开始打印字符串,结果就是at


笔试题8

int main()
{
    char *c[] = {"ENTER","NEW","POINT","FIRST"};
    char**cp[] = {c+3,c+2,c+1,c};
    char***cpp = cp;
    printf("%s\n", **++cpp);
    printf("%s\n", *--*++cpp+3);
    printf("%s\n", *cpp[-2]+3);
    printf("%s\n", cpp[-1][-1]+1);
    return 0;
}

需要画图来看(画指向关系)

    char *c[] = {"ENTER","NEW","POINT","FIRST"};是将"ENTER","NEW","POINT","FIRST"四个字符串的首元素(E , N , P , F)的地址放入c数组里
    char**cp[] = {c+3,c+2,c+1,c};cp数组每个元素是char**,那么就是四个指针分别指向c的首元素地址+3(c的首元素地址+3又指向F地址),c的首元素地址+2(P),c的首元素地址+1(N),c的首元素地址(E)
    char***cpp = cp;cpp就是三级指针,指向cp的首元素地址
    printf("%s\n", **++cpp);cpp变成指向cp第二个元素地址的地址(发生变化了),解引用一次就是cp第二个元素(指向P的地址的地址),再解引用一次就是P的地址,最后以%s打印,就是从P的地址开始打印字符串,结果就是POINT
    printf("%s\n", *--*++cpp+3);++cpp使cpp变成指向cp第三个元素地址的地址(发生变化了),再解引用得到cp第三个元素(指向N的地址的地址),再进行--,就是cp第三个元素变成指向E的地址的地址(发生变化了),就是存储的从c+1变成c,再解引用得到E的地址,再+3得到第二个E的地址,最后以%s打印,就是从第二个E的地址开始打印字符串,结果就是ER
    printf("%s\n", *cpp[-2]+3); *cpp[-2]+3  == **(cpp-2)+3,cpp现在是指向cp第三个元素地址的地址,-2变成指向cp首元素地址的地址,解引用得到c+3,再解引用得到F的地址,再+3得到S的地址,最后以%s打印,就是从S的地址开始打印字符串,结果就是ST
    printf("%s\n", cpp[-1][-1]+1);cpp[-1][-1] == *(*(cpp-1)-1),cpp现在是指向cp第三个元素地址的地址,-1变成指向cp第二个元素地址的地址,再解引用得到c+2,再-1得到c+1,再解引用得到N地址,再+1变成E的地址,最后以%s打印,就是从E的地址开始打印字符串,结果就是EW

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值