• 指针进阶笔试题


    在这里插入图片描述
    今天分享的是指针的笔试题,相信看完这篇文章对指针又会有深入的了解,让我们来学习吧。
    首先分享的是指针和数组的关系,我们都知道数组名是首元素的地址,那就让我们来看一下一维数组和指针的关系吧

    //一维数组
    int a[] = { 1,2,3,4 };
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(a + 0));
    printf("%d\n", sizeof(*a));
    printf("%d\n", sizeof(a + 1));
    printf("%d\n", sizeof(a[1]));
    printf("%d\n", sizeof(&a));
    printf("%d\n", sizeof(*&a));
    printf("%d\n", sizeof(&a + 1));
    printf("%d\n", sizeof(&a[0]));
    printf("%d\n", sizeof(&a[0] + 1));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这些题目我们一定要牢记一些规则,第一个就是数组名就是首元素的地址,只有两个是例外,一个就是sizeof这个操作符,一定要记住他不是函数,然后还有一个就是我们经常看到的取地址操作符(&)这两个是取出整个数组的,其他的都只是首元素的地址,那我们现在来看一下题目吧

    int a[] = { 1,2,3,4 };
    printf("%d\n", sizeof(a));
    //这里a在sizeof内部,是单独出现的,所以表示整个数组的大小,因为sizeof单位是字节
    //所以大小就是16,一个int是4个字节
    printf("%d\n", sizeof(a + 0));
    a不是单独出现,所以表示数组首元素的大小,这里加0就还是数组首元素的地址,所以就是4或者8个字节大小
    
    printf("%d\n", sizeof(*a));
    //这里的a就是表示首元素的地址,我们对它解引用,那就是第一个元素,所以这里就表示第一个元素的大小
    
    printf("%d\n", sizeof(a + 1));
    //a表示数组首元素的地址,所以加1就是跳过一个int,但是本质还是地址,所以还是4/8个字节
    printf("%d\n", sizeof(a[1]));
    表示第二个元素,是整型,所以就是4个字节
    printf("%d\n", sizeof(&a));
    &取出的就是整个数组,就是这个数组的地址,是地址大小就是4/8个字节的大小
    printf("%d\n", sizeof(*&a));
    *&就相当于加减,所以这里就表示sizeof(a)就是整个数组的大小,所以大小就是16
    printf("%d\n", sizeof(&a + 1));
    我们先取出a的地,表示真个数组的地址,然后加一跳过的就是整个数组,相当于是4后面的地址,是地址就是4/8
    
    printf("%d\n", sizeof(&a[0]));
    是地址就是4/8
    printf("%d\n", sizeof(&a[0] + 1));
    取出第一个元素的地址然后我们加1,那么就是第二个元素的地址,但是他的本质还是地址,是地址答案就是4/8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    其实这些题目只要掌握一些规则就可以解决了,比如要知道数组名是首元素的大小,要知道sizeof和&取出的是整个数组的大小,这些问题就可以解决了

    //字符数组
    char arr[] = { 'a','b','c','d','e','f' };
    printf("%d\n", sizeof(arr));
    printf("%d\n", sizeof(arr + 0));
    printf("%d\n", sizeof(*arr));
    printf("%d\n", sizeof(arr[1]));
    printf("%d\n", sizeof(&arr));
    printf("%d\n", sizeof(&arr + 1));
    printf("%d\n", sizeof(&arr[0] + 1));
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr + 0));
    printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));
    printf("%d\n", strlen(&arr));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    下面我们再来看一下字符数组的题目和上面一样的道理

    //字符数组
    char arr[] = { 'a','b','c','d','e','f' };
    printf("%d\n", sizeof(arr));
    还是一样的道理,首先是数组名单独出现在sizeof中,所以表示的就是整个数组的大小
    char的大小就是一个字节大小,所以答案就是6
    printf("%d\n", sizeof(arr + 0));
    arr就是首元素的地址,所以加上0还是首元素的地址,是地址大小就是4/8个字节的大小
    printf("%d\n", sizeof(*arr));
    arr不是单独出现,所以这里表示的就是首元素的地址,那么对它解引用就是第一个元素
    那答案就是一个字节大小
    printf("%d\n", sizeof(arr[1]));
    这里就是数组索引,表示的就是第二个元素,所以大小也是1个字节
    printf("%d\n", sizeof(&arr));
    是地址就是4/8
    printf("%d\n", sizeof(&arr + 1));
    地址4/8
    printf("%d\n", sizeof(&arr[0] + 1));
    地址4/8
    printf("%d\n", strlen(arr));
    strlen统计的是'\0'之前的,因为我们这里数组结尾并没有\0所以是随机数
    printf("%d\n", strlen(arr + 0));
    这里也是一样的
    printf("%d\n", strlen(*arr));
    这里表示的是第一个元素,但是我们strlen的参数是指针,所以这里表示错误
    printf("%d\n", strlen(arr[1]));
    表示错误
    printf("%d\n", strlen(&arr));
    随机数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这里的strlen我们可以上cplusplsu查看

    在这里插入图片描述
    通过图片我们可以看到它的参数是一个char类型的指针,所以表示的意思就是只能接收指针,我们接收int的时候编译器就会报错

    
    int main()
    {
    	char* p = "abcdef";
    
    	printf("%d\n", strlen(p));
    	printf("%d\n", strlen(p + 1));
    	printf("%d\n", strlen(*p));
    	printf("%d\n", strlen(p[0]));
    	printf("%d\n", strlen(&p));
    	printf("%d\n", strlen(&p + 1));
    	printf("%d\n", strlen(&p[0] + 1));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们在来看看这个题目,首先p存放不是这个常量字符串,存放的应该是a首元素的地址,那我们对他进行操作就比较容易理解了,让我们来看一下吧

    
    	//printf("%d\n", sizeof(p));//4/8 计算的是指针变量的大小
    	//printf("%d\n", sizeof(p + 1));//p+1还是地址,大小是4/8个字节
    	//printf("%d\n", sizeof(*p));//1个字节, *p == 'a'
    	//printf("%d\n", sizeof(p[0]));//1个字节, p[0]--> *(p+0) --> *p == 'a';
    
     //	printf("%d\n", sizeof(&p));//4/8个字节,&p 是地址
    	//printf("%d\n", sizeof(&p + 1));//&p是地址,&p+1还是地址,是地址就是4/8个字节
    
    	//printf("%d\n", sizeof(&p[0] + 1));
    	因为p是数组首元素的地址,其实它的意思就可以是数组名,那我们取出的就是第一个地址元素的地址,然后我们对它进行加1,那么就是的哥元素的地址,是地址大小就是4/8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    看了一维数组之后,我们在来看一下二维数组的题目,二维数组其实本质就是一维数组的数组

    /二维数组
    int a[3][4] = { 0 };
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(a[0][0]));
    printf("%d\n", sizeof(a[0]));
    printf("%d\n", sizeof(a[0] + 1));
    printf("%d\n", sizeof(*(a[0] + 1)));
    printf("%d\n", sizeof(a + 1));
    printf("%d\n", sizeof(*(a + 1)));
    printf("%d\n", sizeof(&a[0] + 1));
    printf("%d\n", sizeof(*(&a[0] + 1)));
    printf("%d\n", sizeof(*a));
    printf("%d\n", sizeof(a[3]));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    数组的第一个元素是0,后面数组的内容就是随机值。

    //二维数组
    int a[3][4] = { 0 };
    printf("%d\n", sizeof(a));
    首先是a是数组名,说过数组名是首元素的地址,但是由于是二维数组,所以这里的意思就是第一行的地址
    类型可不是int 而是int (*)[4],所以这里的意思就是第一行的大小,那就是16个字节
    printf("%d\n", sizeof(a[0][0]));
    表示第一个元素的大小,所以大小就是4个字节
    printf("%d\n", sizeof(a[0]));
    表示的是第一行的数组名,所以这里的大小也是16
    printf("%d\n", sizeof(a[0] + 1));
    a[0]就是第一行的数组名,数组名就是首元素的大小,加一就是第一行第二个元素的地址,是地址就是4/8
    printf("%d\n", sizeof(*(a[0] + 1)));
    a[0]就是第一行的数组名,数组名就是首元素的地址,加一就是第一行第二个元素大小,所以解引用就是一个整型
    大小就是4个字节
    printf("%d\n", sizeof(a + 1));
    表示第二行的大小,因为a是第一行的地址,加1跳过的是一行,所以就是第二行的地址,那大小
    就是4/8个字节大小
    printf("%d\n", sizeof(*(a + 1)));
    解引用出来应该第二行的所有数据,所以大小就是16个字节
    printf("%d\n", sizeof(&a[0] + 1));
    因为a[0]表示第一行的数组名,所以取地址应该是第一行,是整个第一行,然后进行加1那么就是第二行
    的地址,是地址大小就是4/8
    printf("%d\n", sizeof(*(&a[0] + 1)));
    根据上面的分心,这是第二行的地址,所以解引用是整个第二行,那大小就是16个字节大小
    
    printf("%d\n", sizeof(*a));、
    a是数组名,表示第一行的地址,那么解引用就是第一行,大小就是16个字节
    printf("%d\n", sizeof(a[3]));
    这里a[3]虽然看起来越界了,但是其实没有,我们这里还是可以理解为它是个数组名,因为数组名单独出现在sizeof当中,那么
    表示的就是16个字节大小
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    我们在继续往下面看一些笔试题

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这个题目其实看完上面的在来看就有点杀鸡用牛刀的感觉哈哈哈
    首先a前面有个取地址的符号,那我们取出的a这个数组的整个地址,然后加以的意思就是跳到5
    位置后面一个int大小的地方,所以答案就是2,5

    //程序的结果是什么?
    //由于还没学习结构体,这里告知结构体的大小是20个字节
    struct Test
    {
    	int Num;
    	char* pcName;
    	short sDate;
    	char cha[2];
    	short sBa[4];
    }*p;
    //假设p 的值为0x100000。 如下表表达式的值分别为多少?
    //已知,结构体Test类型的变量大小是20个字节
    int main()
    {
    	printf("%p\n", p + 0x1);
    	printf("%p\n", (unsigned long)p + 0x1);
    	printf("%p\n", (unsigned int*)p + 0x1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们在继续往后面看这个题目,我们其实也有文章讲结构体大小对齐的,大家有兴趣可以去看一下,那这里直接告诉大家大小就是20个字节,0x就是表示16进制,然后\p是地址的打印,我们先来看第一个,第一个是结构体类型的大小进行加1,加就是20,那20用16进制表示的14,所以答案就是0x10014,下面这个就有点误导,我们可以看到的是unsigned,这里大家可不要被骗,以为加的是8,其实爱他就是整型加减,加的就是数字1,按这里的答案是0x100001,接下来继续看后面,这里就是加一个整型大小,所以答案就是0x100004

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这道题也是一样的很有误导性,第一个很简单,&a就是把整个数组取出来,那我们进行加1跳过的就是整个数组的大小,指向的就是4后面的地址,ptr[-1]就是*(ptr-1)那我们就%x也是打印地址,就是我们的4 所以就是00000004,但是后面的就不是这里了,a先强制转换成一个整型,因为a是首元素的地址,
    在这里插入图片描述
    那我们加一在强转成整型的话,其实就是相当于取到的就是02 00 00 00,打印的就是2000000

    #include 
    int main()
    {
    	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    	int* p;
    	p = a[0];
    	printf("%d", p[0]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们继续往后来看这道题,我平常数组应该用{}这个,但是这里是()表示的是一个逗号表达式
    那其实数组第一个元素就是1,答案就是1

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在来看这个,这个相当于指针减去指针,我们也知道指针减去指针其实就是元素个数是多少
    我们这里一定要画图。
    所以一个就是以%d打印的就是-4 还有一个是就是-4的补码然后变成16进制就行了,这里我偷懒了,因为我马上要去吃饭了哈哈哈

    还有三道题,小编已经饿死了

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们在来看一下这个题目,首先取出的是整个二维数组的地址,然后加1跳过的就是10后面的int大小的地址,我们ptr1-1就是访问的就是10,继续看aa是第一行的地址加1就是第二行的地址,然后强转成int* ptr2-1就是5

    #include 
    int main()
    {
    	char* a[] = { "work","at","alibaba" };
    	char** pa = a;
    	pa++;
    	printf("%s\n", *pa);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个画图就可以写出来,大家ctrl+F5看一下结果,受不了了,我要吃饭了,不写了

    谢谢大家 今天的分享就到这里,我们下次再见!!!

  • 相关阅读:
    策略设计模式
    洛谷 P1343 地震逃生(最大流dinic算法)
    基于JavaSwing开发学生成绩管理系统(SQLServer数据库) 课程设计 大作业
    SpringCloud Alibaba - Sentinel 微服务保护解决雪崩问题、Hystrix 区别、安装及使用
    开源二三事|ShardingSphere 与 Database Mesh 之间不得不说的那些事
    《数字化与碳中和(园区篇)》报告正式发布,助力加快推进国家“双碳”战略实施
    本地部署和运行大型语言模型(Large Language Models, LLMs)的工具Ollama
    C语言 驼峰命名法和下划线命名法
    12月份PMP考试首次采用新考纲,该怎么学?
    CentOS 升级内核至5.15.52
  • 原文地址:https://blog.csdn.net/2301_76895050/article/details/132914785