• C语言指针笔试题讲解


    大家好,我们来学习一些C语言的指针笔试题。对于C语言指针的模块想必大家都非常的头疼吧,那么我们就来就来看看一些关于C语言指针的笔试题。

    在这里插入图片描述

    首先让我们看到我们今天的第一题。

    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

    在这里插入图片描述
    看到这个程序运行的结果,我们就好好地来分析下这个题。

    在这里插入图片描述

    我们看到图片,我们printf语句中的a指的是数组首元素的地址指向的就是图中1位置,a+1就代表数组中第二个元素的地址,所以我们 *(a+1)得到就是第二个元素,我们的指针指向的是图中2位置,因为&a取的是数组的地址,所以&a+1指向的就是图中2位置,ptr-1指向的就是图中3位置,所以我们 *(ptr-1)得到就是第五个元素。

    我们看到下一题

    //由于还没学习结构体,这里告知结构体的大小是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

    在这里插入图片描述

    我们看到在x86环境下打印的结果,因为我们的地址在内存中的存储是16进制,所以我们的结构体大小为20个字节,指针结构体加1,跳过一个结构体的大小,我们这里第一个打印就是16进制的20,第二个我们是无符号数的长整型所以加1就是普通加1,所以打印的结果就是00000001,最后一个我们的p是int*类型的指针,所以我们这里就是加4,所以结果就是00000004。

    我们继续–>:

    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
    int main()
    {
    	int a[4] = { 1, 2, 3, 4 };
    	int* ptr1 = (int*)(&a + 1);
    	int* ptr2 = (int*)((int)a + 1);
    	printf("%x,%x\n", ptr1[-1], *ptr2);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    我们这里依旧是ptr1指向下一组数据,也就是与数组最后一个元素相邻的数据,而打印ptr1[-1]就是ptr1向前挪一个整型也就是4个字节,所以ptr1指向的就是数组的最后一个数据,所以结果就是4。第二个它先是把数组名a强制转换成整型变量,然后再加1,然后再强制转换成整型指针!就是让ptr2指向a[0]的第二个字节,看到下图:
    在这里插入图片描述
    在这里插入图片描述

    ptr2指向了a[0]的第二个字节由于x86平台是小端序的,小端序的存取时最低位对应低地址 ,因此将会打印出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

    在这里插入图片描述
    在这里插入图片描述

    我们这里p=a[0]指的是取的二维数组第一行第一个元素的地址,我们要注意括号里的是逗号表达式,逗号表达式的结果就是表达式中最后一个表达式的结果,所以原来数组中存放的值就是{1,3,5}。所以我们这里的p[0]就相当于*(p+0),也就是*p,所以打印的结果为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

    在这里插入图片描述
    在这里插入图片描述

    在这里我们要知道指针减指针得到的是两个地址之间的元素个数,我们首先做出图像,我们发现&a[4][2]取的是第五行第三个元素的地址,而我们定义的*p数组指针,p=a我们就知道这单纯的把数组a的元素被p分为以四个元素为一行,所以我们的&p[4][2]就是我们刚得到的数组的第五行第三个元素的地址,所以两个相减得到-4,然而我们前面还得打印这个数的地址,那么我们首先就得知道地址是以16进制的形式存储的,我们首先得到的是-4的补码,因为负数里存储的是补码,我们给它取反加一得到原码,但我们这个时候是二进制,所以我们要给它转换成16进制,1111代表二进制的15,转换成16进制就是f,而1100代表的是二进制序列的12,所以转换成16进制就是c,所以地址就是fffffffc。

    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

    在这里插入图片描述
    在这里插入图片描述

    看了前几个题相信大家对ptr1已经有了更加深刻的理解,我们的ptr1指向的就是下个数据,ptr-1指向就是这个数组最后一个元素,得到的结果就是10,我们这里的aa+1就相当于aa[1],也就是&aa[1][0],所以指向的就是二维数组第二行第一个元素,那我们的ptr2-1指向的就是第一行最后一个元素的地址,所以得到的就是5。

    在今天的学习中大家一定都会有些许收货吧,我们下次见,谢谢大家。

  • 相关阅读:
    缓存失效方案
    Anaconda虚拟环境中打开Jupyter
    【ACM学习】【STL】多重集合multiset和多重映射multimap
    电子管是什么?
    理解 Linux backlog/somaxconn 内核参数
    Hadoop3教程(十五):MapReduce中的Combiner
    Flutter笔记:滚动之-无限滚动与动态加载的实现
    qemu笔记-代码导读
    微信小程序按需注入和用时注入
    深入剖析 RocketMQ 源码 - 负载均衡机制
  • 原文地址:https://blog.csdn.net/Lehjy/article/details/132999763