news 2026/6/10 0:46:09

深入理解指针(7)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入理解指针(7)

一、数组和指针笔试题解析(2)

(一)二维数组

int main() { int a[3][4] = { 0 }; printf("%d\n", sizeof(a)); //48 a是数组名,单独放在sizeof内部,代表整个数组,3*4*4 printf("%d\n", sizeof(a[0][0])); //4 第一个元素,即第一行的第一个元素,为int型 printf("%d\n", sizeof(a[0])); //16 a[0]本来是第一行的数组名,但是数组名单独放在sizeof内部,代表整个数组的大小,1*4*4 printf("%d\n", sizeof(a[0] + 1)); //4 or 8 a[0]代表的是第一行数组名,也就是&a[0][0],+1后也就代表a[0][1]的地址,是地址就是4 or 8 printf("%d\n", sizeof(*(a[0] + 1))); //4 a[0] + 1是第一行第二个元素的地址,解引用完就代表第二个元素,也就是a[0][1] printf("%d\n", sizeof(a + 1)); //4 or 8 a代表二维数组首元素的地址,因为二维数组首元素是第一行所代表的一维数组 //所以a也就是第一行的地址,+跳过一行,所以a+1就是第二行的地址,是地址就是4 or 8 printf("%d\n", sizeof(*(a + 1))); //16 ——1—— 对a+1解引用得到的就是第二行,1*4*4 //——2—— *(a+1)-->a[1] ,a[1]是第二行的数组名,所以sizeof(*(a + 1))就相当于 //sizeof(a[1]),此时a[1]代表的是第二行整个的一维数组,1*4*4 printf("%d\n", sizeof(&a[0] + 1)); //4 or 8 &a[0]代表取出第一行的地址,+1代表现在是第二行的地址,是地址大小就是4 or 8 printf("%d\n", sizeof(*(&a[0] + 1))); //16 解引用后代表第二行,1*4*4 printf("%d\n", sizeof(*a)); //16 a代表首元素地址,即第一行的地址,1*4*4 printf("%d\n", sizeof(a[3])); //16 a[3]无需真实存在,仅仅通过类型就能推断出长度 //a[3]是第四行的数组名,单独放在sizeof内部,代表整个第四行的一维数组,1*4*4 //这里如果还不理解,我们不妨看sizeof(int)这里我们仅仅给出了类型,并没有什么具体占据了 //内存空间的数据,所以sizeof()中的内容没必要真实存在 return 0; }

二、指针运算笔试题解析

(一)题目1

#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); //整个数组的类型是int(*)[5],所以我们需要进行强制类型转换为int型 printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; }

(二)题目2

//在X86(32位)环境下 //假设结构体的大小是20个字节 //程序输出的结果是啥? struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; } * p = (struct Test*)0x100000; //这里定义了一个结构体指针,用来存放0x100000这个地址 //指针+-整数 int main() { printf("%p\n", p + 0x1); //这里是结构体指针+1,跳过的是整个结构体指针 //又因为结构体的大小是20个字节,所以 //0x100000+20,这里的20是10进制的20 //所以转换为16进制的最终输出结构为 //00100014 printf("%p\n", (unsigned long)p + 0x1); //这里强制类型转换为整型,所以就是普通+1 //当然,或许有人会注意到这里的占位符还是%p //所以实际上在这里VS会报警告 printf("%p\n", (unsigned int*)p + 0x1); //这里强制类型转换为整形指针 return 0; }

(三)题目3

int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) };//初始化 //数组a的定义是本题的理解关键 //注意到,0,1等数字都是用小括号括起来的,说明这并不是普通的二维数组 //(0,1)本质上是一个逗号表达式,而逗号表达式只取决于最后一个结果; //所以此二维数组的值为1,3,5,0,0,0 int* p; p = a[0]; //a[0]是二维数组第一行的地址 printf("%d", p[0]); //p[0]=*(p+0)=*(a[0]+0)=a[0][0],所以是第一个元素的值 return 0; }

(四)题目4

//假设环境是x86环境,程序输出的结果是啥? int main() { int a[5][5]; int (*p)[4]; //p是一个数组指针,p指向的是含有4个整型元素的数组 p = a; //将二维数组第一行的地址赋给p //但是我们会发现,这里a的类型为int(*)[5],与p并不一样 //所以这里其实会报警告,但是来做题是没问题的 printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); // &a[4][2]的值我们很容易确定,那&p[4][2]又代表什么呢? //首先我们要明确p=a保证了p的首元素地址就是二维数组第一个元素的地址; //这里的p[4][2]与*(*(p+4)+2)是等价的,然后我们看下面那个图来理解一下 return 0; }

(五)题目5

int main() { int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int* ptr1 = (int*)(&aa + 1); //&aa是取出整个二维数组的地址,+1说明跳过了整个二维数组 int* ptr2 = (int*)(*(aa + 1)); //这里aa代表的是第一行数组的地址,+1后代表第二行数组的地址 //*(aa + 1)等价于aa[1]也就是第二行首元素地址 printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); return 0; }

(六)题目6

int main() { char* a[] = { "work","at","alibaba" }; //这里是指针数组,每一个元素都是一个字符串的首地址 //可以类比char*p="abcdef"中的p就是a的地址 char** pa = a; //因为a是数组首元素的地址,即&a[0],所以pa是二级指针 //指向&a[0] pa++; //pa++后,指向的是&a[1] printf("%s\n", *pa); //【这里一定要注意】,printf的占位符为%s的时候,逗号后面 //跟的一定是该字符串首元素的地址!!! return 0; }

(七)题目7

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; }

本道题是以上指针题目中,分析最繁琐,逻辑链最长的一道题。

想要搞懂这道题,我们就要画出以下的空间(地址)指示关系图。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 11:12:20

谁懂啊!别再说零基础学不了网安,电脑小白 4 阶段路线直接冲

别再说 “零基础学不了网安”&#xff01;电脑小白也能入门的 4 阶段路线. 总有人问&#xff1a;“我连代码都不会写&#xff0c;能学网络安全吗&#xff1f;” 其实真不用怕&#xff0c;哪怕你是只会用电脑刷视频的纯小白&#xff0c;跟着清晰的路线一步步学&#xff0c;照样…

作者头像 李华
网站建设 2026/6/9 22:40:19

技术陷阱揭秘:Vitest中then函数引发的模块加载异常

技术陷阱揭秘&#xff1a;Vitest中then函数引发的模块加载异常 【免费下载链接】vitest Next generation testing framework powered by Vite. 项目地址: https://gitcode.com/GitHub_Trending/vi/vitest 在JavaScript测试开发中&#xff0c;函数命名看似简单&#xff0…

作者头像 李华
网站建设 2026/6/5 14:22:24

RQ分布式任务日志集中化管理实战指南

RQ分布式任务日志集中化管理实战指南 【免费下载链接】rq 项目地址: https://gitcode.com/gh_mirrors/rq/rq 还在为RQ任务日志分散在各个Worker节点而头疼&#xff1f;&#x1f914; 是否因为无法统一监控任务执行状态而错失问题排查的最佳时机&#xff1f;别担心&…

作者头像 李华
网站建设 2026/6/8 13:32:08

java_base_(抽象类与接口区别篇)

我相信大家面对什么时候用抽象类&#xff0c;什么时候用接口会犯糊涂甚至手足无措。那么下面我将结合原神场景介绍一下它们各自的区别和特点&#xff0c;让你更了解何时用抽象类和接口。一、先明确核心&#xff1a;抽象类与接口到底是什么&#xff1f;在讲区别前&#xff0c;我…

作者头像 李华
网站建设 2026/6/9 22:49:17

开源游戏宝库终极指南:awesome-open-source-games

开源游戏宝库终极指南&#xff1a;awesome-open-source-games 【免费下载链接】awesome-open-source-games Collection of Games that have the source code available on GitHub 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-open-source-games awesome-open-…

作者头像 李华
网站建设 2026/6/9 4:16:03

【C++】--红黑树的概念和实现

前言&#xff1a;在计算机科学的浩瀚领域中&#xff0c;数据结构是构建高效算法的基石&#xff0c;而树结构因其出色的层次性和查找效率&#xff0c;成为处理动态数据集合的核心选择。二叉搜索树作为基础的树结构&#xff0c;虽能实现快速的插入、删除与查找操作&#xff0c;但…

作者头像 李华