带你详细理解数组与指针(包含二维数组)

作者博客主页:谦逊码农的旅程

1. sizeof中单独放一个数组名,此时的数组名表示整个数组。

2. &数组名,表示整个数组的地址

3. 在 C 语言中,变量的地址通常是由一个指针来表示,而指针的大小取决于计算机架构和操作系统。一般来说,在32位系统中,指针的大小为4个字节(32位),在64位系统中,指针的大小通常为8个字节(64位)。因此,变量的地址在内存中占据的字节数取决于系统的位数。

4. sizeof 运算符用于计算数据类型或变量在内存中所占的字节数,不关注内存中放的是什么数据。

5. sizeof是一个操作符,不是函数。

6. 指针的加法会根据其指向的数据类型进行适当的偏移,确保指针指向正确的内存位置。


一维数组

一维数组的每个元素的地址类型为int*

整型数组

定义一个数组:

int a[] = { 1,2,3,4 };

一、 a

printf("%d\n", sizeof(a))

sizeof括号内的a表示整个数组,所以sizeof返回的是a数组的大小,结果是16。


二、a+0

printf("%d\n", sizeof(a+0));

  a + 0是一个表达式,a没有单独出现在sizeof内,所以此时的a只能表示数组首元素的地址,a + 0是数组第一个元素的地址,在32位环境下地址的大小是4,64位环境下地址的大小是8。所以结果是4 / 8


三、*a

printf("%d\n", sizeof(*a));

*a表示解引用数组首元素的地址,得到的是一个整型的数1,它在内存中的大小是4个字节。

相当于 *(a+0)


四、a+1

printf("%d\n", sizeof(a + 1));

此处的a表示数组首元素的地址,加1表示跳过一个数组元素所占的空间,即数组第2个元素的地址。是地址结果就是4/8


五、a[1]

printf("%d\n", sizeof(a[1]));

a[1] 表示数组下标为1的元素,也可以表示成 *(a + 1) ,是一个整型,在内存中占4个字节。


六、&a

printf("%d\n", sizeof(&a));

&a表示整个数组的地址,整个数组的地址与数组首元素的地址相同,其次数组的地址也是地址,是地址大小就是4/8个字节。


七、*&a

printf("%d\n", sizeof(*&a));

*与&符号相抵消,所以此处表示整个数组,最后的结果是整个数组所占空间的大小,为16个字节


八、&a+1

printf("%d\n", sizeof(&a + 1));

&a表示数组a的地址,加1表示跳过整个数组所占的内存空间。是一个地址,结果为4/8


九、&a[0]

printf("%d\n", sizeof(&a[0]));

表示下标为0的元素的地址,结果为4/8


十、&a[0]+1

printf("%d\n", sizeof(&a[0] + 1));

&a[0]表示首元素的地址,加1表示a[1]的地址,结果为4/8



字符数组

代码1:

char arr[] = { 'a','b','c','d','e','f' };

一、arr
printf("%d\n", sizeof(arr));

此处的 arr表示整个数组,结果为 6


二、arr+0
printf("%d\n", sizeof(arr + 0));

此处的arr表示数组首元素的地址,加0也是数组首元素的地址,结果为4/8


三、*arr
printf("%d\n", sizeof(*arr));

首先,此处的arr表示数组首元素的地址,*arr表示解引用首元素的地址,即arr[0],也可以表示为

*(arr + 0),表示的是一个具体的数据,结果为1


四、arr[1]
printf("%d\n", sizeof(arr[1]));

arr[1]表示下标为1的数组元素,是一个数,结果为1


五、&arr
printf("%d\n", sizeof(&arr));

&arr表示数组的地址,数组的地址与数组首元素的地址相同,地址的大小为4/8


六、&arr+1
printf("%d\n", sizeof(&arr + 1));

&arr 表示arr数组的地址,加1表示跳过整个数组所占的内存空间大小,是一个地址,结果为4/8


七、&arr[0]+1
printf("%d\n", sizeof(&arr[0] + 1));

&arr[0]表示数组首元素的地址,加1表示跳过了数组中第一个元素的内存空间,即移动到了数组中下一个元素的地址,是arr[1]的地址,即&arr[1],大小为4/8


代码2:strlen函数统计字符串的长度

strlen函数接收的参数是个地址,它顺着这个地址往后统计字符的个数,直到遇到'\0'结束。

char arr[] = { 'a','b','c','d','e','f' };

一、arr
printf("%d\n", strlen(arr));

strlen是计算长度,它统计 '\0' 之前的字符个数。上述arr数组中没有'\0',会持续往后找,直到在内存中遇到 '\0' ,所以最终的结果是一个随机值。


二、arr+0
printf("%d\n", strlen(arr + 0));

strlen函数接收的是字符串的地址,arr+0表示数组arr的首地址,strlen函数会顺着这个地址往后统计字符的个数直到遇到'\0',所以结果是一个随机值。


三、*arr
printf("%d\n", strlen(*arr));

*arr是字符'a',ASCII码值是97,相当于将97作为地址传给了strlen,97这个地址指针无法访问,所以strlen得到的是一个野指针,结果会报错。


四、arr[1]
printf("%d\n", strlen(arr[1]));

arr[1] 是字符'b',ASCII码值是98,相当于将98作为地址传给了strlen,98这个地址指针无法访问,所以strlen得到的是一个野指针,结果会报错。


五、&arr
printf("%d\n", strlen(&arr));

&arr表示整个数组的地址,整个数组的地址是在数组首元素的地址处开始,strlen会一个一个的往后找,直到遇到'\0',结果为随机值。


六、&arr+1
printf("%d\n", strlen(&arr + 1));

&arr + 1表示跳过整个数组所占的空间长度,结果为随机值。


七、&arr[0] + 1
printf("%d\n", strlen(&arr[0] + 1));

&arr[0]是数组首元素的地址,加1表示arr[1]的地址,所以strlen会从arr[1]的地址开始往后找'\0',

结果为随机值。


代码3:

char arr[] = "abcdef";

一、arr
printf("%d\n", sizeof(arr));

在sizeof中arr表示整个数组,此时sizeof计算的是整个数组所占的空间,双引号会在结尾处自动添加'\0',所以结果是7


二、arr+0
printf("%d\n", sizeof(arr + 0));

此处的arr表示数组的首元素的地址,+0也是数组的首元素,地址在内存中的大小为4/8,结果为4/8


三、*arr
printf("%d\n", sizeof(*arr));

*arr表示数组中第一个元素,这个数组是char类型的,所以第一个元素占1个字节。


四、arr[1]
printf("%d\n", sizeof(arr[1]));

arr[1]是数组中的第2个元素,是char类型,所以结果为1。


五、&arr
printf("%d\n", sizeof(&arr));

&arr是整个数组的地址,是地址大小就是4/8


六、&arr+1
printf("%d\n", sizeof(&arr + 1));

&arr+1也是一个地址,大小是4/8


七、&arr[0]+1
printf("%d\n", sizeof(&arr[0] + 1));

&arr[0]是数组首元素的地址,加1是数组第二个元素的地址,大小为4/8


代码4:指针变量

char* p = "abcdef";

一、p
printf("%d\n", sizeof(p));

此处的p是指针变量,它存放的是字符串的首地址,也就是'a'的地址,大小为4/8


二、p+1
printf("%d\n", sizeof(p+1));

p+1是字符串中第二个元素的地址,即'b',大小为4/8


三、*p
printf("%d\n", sizeof(*p));

*p是字符'a',占1个字节


四、p[0]
printf("%d\n", sizeof(p[0]));

p[0]表示*(p+0),是字符a,大小为1


五、&p
printf("%d\n", sizeof(&p));

&p表示指针变量p的地址,大小为4/8


六、&p+1
printf("%d\n", sizeof(&p+1));

&p+1是跳过一个char大小的空间后的地址,大小为4/8


七、&p[0]+1
printf("%d\n", sizeof(&p[0]+1));

p[0]表示*(p+0),表示字符'a',&p[0]表示字符'a'的地址,再加1表示字符'b'的地址,大小为4/8



二维数组

int a[3][4] = { 0 };

 

每一排是一个一维数组。

a[0]、a[1]、a[2] 相当于二维数组a的三个元素

二维数组相当于数组的数组,传到子函数变成数组的指针,上述二维数组每个元素的类型是int*[4]

所以二维数组首元素的类型就是int*[4]

二维数组在内存中是连续存放的,上述图只是便于理解和观察。

二维数组实际在内存中的存放:


一、a

printf("%d\n", sizeof(a));

此处的数组名a表示整个数组,sizeof计算整个数组所占空间的大小,总共有12个元素,每个元素为int类型,所以结果为48


二、a[0][0]

printf("%d\n", sizeof(a[0][0]));

a[0][0]表示第一个元素,结果为4


三、a[0]

printf("%d\n", sizeof(a[0]));

a[0]表示二维数组中的第一排的数组的数组名,单独放sizeof中表示这一排的整个数组,第一排数组中有4个元素,每个占4个字节,所以结果为16


四、a[0]+1

printf("%d\n", sizeof(a[0] + 1));

 此时的a[0]没有单独放在sizeof中,所以不表示第一排的整个数组。此处的a[0]表示第一排数组的数组名,是第一排数组的首元素的地址即&arr[0][0],加1表示跳过一个int空间的大小,
即是&arr[0][1],大小为4/8


五、*(a[0]+1)

printf("%d\n", sizeof(*(a[0] + 1)));

 a[0]是第一排数组的数组名,表示数组首元素的地址,它的类型是一个指针,指向一个地址,加1是第一排第二个元素的地址&arr[0][1],再解引用是第二个元素的值arr[0][1],大小为4个字节。


六、a+1

printf("%d\n", sizeof(a + 1));

此处的a表示二维数组的数组名,是二维数组首元素的地址,也就是第一排数组的地址加1跳过一行,表示第二排数组的地址a+1是一个数组指针,指向的是一个数组地址,结果为4/8


七、*(a+1)

printf("%d\n", sizeof(*(a + 1)));

两种理解方式:

1.  a+1是第二排数组的地址,类型是一个数组指针,解引用就是第二排数组,大小为16个字节

2. *(a+1)是 a[1] ,单独放在sizeof中,表示第二排数组


八、&a[0]+1

printf("%d\n", sizeof(&a[0] + 1));

此处的a[0]是第一排数组的数组名,&a[0]表示的是第一排数组的地址,它的类型是一个数组指针,加1跳过一个数组所占的空间大小,所以&a[0] + 1表示第二排数组的地址,等价于 a+1,大小为4/8


九、*(&a[0]+1)

printf("%d\n", sizeof(*(&a[0] + 1)));

*(&a[0] + 1)表示第二排数组的地址解引用,是第二排数组,大小为16字节


十、*a

printf("%d\n", sizeof(*a));

此处的a没有单独放在sizeof中,所以表示二维数组首元素的地址,是第一排数组的地址,解引用后表示第一排数组a[0],大小为16个字节


十一、a[3]

printf("%d\n", sizeof(a[3]));

a[3]虽然不是二维数组a中的元素,但sizeof只是计算所占空间的大小,并没有去访问这个元素。a[3]无需真实存在,仅仅通过类型的推断就能算出大小。a[3]是第四排的数组名,单独放在sizeof内表示第四排数组,大小为16个字节。


创作不易,觉得还不错的话,点个赞吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/725310.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL·SQL优化

目录 一 . 前言 二 . 优化方法 1 . 索引 (1)数据构造 (2)单索引 (3)explain (4)组合索引 (5)索引总结 2 . 避免使用select * 3 . 用union all代替u…

Linux之cd、pwd、mkdir 命令

cd命令,切换目录 1)当Linux终端(命令行)打开的时候,会默认以用户的HOME目录作为当前的工作目录。 2)我们可以通过cd命令,更改当前所在的工作目录。 3)cd命令来自英文:C…

使用nvidia-ml-py事实监控GPU状态

平时监控GPU状态最常用的是watch配合nvidia-smi指令,但有时可能不仅仅需要监控,还需要记录状态数据,比如GPU的显存变化以及利用率变化等等。本文提供了一个使用nvidia-ml-py包编写的简易Demo,该Demo能够实现简易版的nvidia-smi功能…

C++之获取Windows系统信息

目录 1. 操作系统版本 2. 获取CPU信息 3. 获取内存信息 4. 获取硬盘信息 5.获取网络接口信息 6.获取计算机名称、用户名 在C中,你可以使用Windows API函数来获取Windows系统的各种信息。以下是一些常见的API函数和示例代码,用于获取Windows系统信息…

STM32使用标准库编写外部时钟控制oled显示计数(proteus仿真)

这节课的结果是在上节课的基础上更改的:电路图为:用一个开关来模拟外部时钟的高低电平的变化。 当然也可以配置一个外部时钟来模拟,也是可以的: 由于这节课的代码是在上节课的基础上有一点修改而来的,所以就只把更改的…

【python高级编程教程】笔记(python教程、python进阶)第三节:(1)多态与鸭子类型(Polymorphism and Duck Typing)

参考文章1:【比刷剧还爽】清华大佬耗时128小时讲完的Python高级教程!全套200集!学不会退出IT界! 参考文章2:清华教授大力打造的Python高级核心技术!整整100集,强烈建议学习(Python3…

C++_程序流程结构_跳转语句_break

break 作用 用于跳出选择结构或循环结构 break使用的时机 出现在switch条件语句中,作用是终止case并跳出switch出现在循环语句中,作用是跳出当前的循环语句出现在嵌套循环中,跳出最近的内层循环语句 示例1 示例2 示例3

C语言结构体的大小,结构体内存对齐

1. 结构体的大小 在自己正真了解过之前&#xff0c;一直认为结构体的大小就是结构体内部成员大小的总和。 但当你去尝试打印结构体的大小时&#xff0c;会发现事实并非如此&#xff0c;也不会像你想的那样简单。 #include <stdio.h>struct S1 {char c1;char c2;int i;…

什么原因导致了电视大国的国内市场萎缩1300台?2024最值得购买的随身WiFi

近日&#xff0c;全国人大代表&#xff0c;TCL的创始人兼董事长就提出了一个问题&#xff1a;中国生产了世界上75%的电视机&#xff0c;但是国内市场的销量&#xff0c;在5年内缩水了1300万台&#xff0c;这究竟是为什么呢&#xff1f; 对此网友们纷纷解答&#xff1a; 电视能…

Android开发者值得深入思考的几个问题,看完必懂

程序员的劫 最近&#xff0c;又被程序员年龄的事情刷屏了。37岁被公司优化&#xff0c;找工作几个月都没有很好的归属&#xff0c;所谓的小公司还看不上。等等类似的话题变成了程序员的吐槽固定标题&#xff0c;无论是程序员&#xff0c;还是其他行业人员&#xff0c;都可以就…

Stable Diffusion V3测评

1.引言 3月5号&#xff0c;Stability AI发布了介绍Stable Diffusion V3的研究论文&#xff0c;链接地址&#xff1a;戳我 这是目前他们发布的最先进、功能最强大的图像生成器&#xff0c;与一年多前发布的令人印象深刻的 Stable Diffusion V2.1 相比有了大幅升级。SD3所带来的…

LINUX重定向的原理

1.利用文件描述符规则实现重定向 文件描述的分配规则:最小没有使用的下标会分给最新打开的文件 正常printf打印是在stdin标准输出显示器打印&#xff0c;stdin标准输出显示器的fd是1。 所以只要把显示器文件stdin给关闭&#xff0c;再打开一个文件&#xff0c;这个文件的 fd…

HTML静态网页成品作业(HTML+CSS)——新年春节介绍网页设计制作(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示1、首页2、子页13、子页2 三、代码目录四、网站代码HTML部分代码CSS部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0…

【InternLM 笔记】使用InternStudio 体验书生·浦语2-chat-1.8b随记

书生浦语2-chat-1.8b 介绍 书生浦语-1.8B (InternLM2-1.8B) 是第二代浦语模型系列的18亿参数版本。为了方便用户使用和研究&#xff0c;书生浦语-1.8B (InternLM2-1.8B) 共有三个版本的开源模型&#xff0c;他们分别是&#xff1a; InternLM2-1.8B: 具有高质量和高适应灵活性…

双指针算法(2)

611.有效三角形的个数 一、题目描述 OJ题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09; 二、思路讲解 首先我们能想到的一定是暴力枚举&#xff0c;它的时间复杂度是(O^3)。 我们可以固定一个最长边&#xff0c;然后在比这条边小的有序数组中找出一个二元组&…

八、西瓜书——特征选择与稀疏学习

1.子集搜索与评价 对于1个学习任务来说,给定属性集,其中有些属性可能很关键、很有用&#xff0c;另一些属性则可能没什么用&#xff0c;我们将属性称为“特征”(feature),对当前学习任务有用的属性称为“相关特征”(relevant feature)、没什么用的属性称为“无关特征”(irrelev…

Vue:双token无感刷新

文章目录 初次授权与发放Token&#xff1a;Access Token的作用&#xff1a;Refresh Token的作用&#xff1a;无感刷新&#xff1a;安全机制&#xff1a;后端创建nest项目AppController 添加login、refresh、getinfo接口创建user.dto.tsAppController添加模拟数据 前端Hbuilder创…

Pytest中实现自动生成测试用例脚本代码!

前言 在Python的测试框架中&#xff0c;我们通常会针对某个系统进行测试用例的维护&#xff0c;在对庞大系统进行用例维护时&#xff0c;往往会发现很多测试用例是差不多的&#xff0c;甚至大多数代码是一样的。 故为了提高我们测试用例维护的效率&#xff0c;在本文中&#…

Redis缓存知识总结

图解缓存 what&how problems&strategy 缓存更新 缓存穿透 缓存雪崩 缓存击穿 &#xff08;图源自黑马教育&#xff09;

3.5日常学习

matlab处理数据 自己写了关于detect_data的函数&#xff0c;让它帮我改了&#xff0c;哈哈哈 %改正前function data_chuli(path1,savepath)[num]xlsread(path1,1,B18:F23);a num;ba;cb(:);xlswrite(savepath,c) end%改正后function data_chuli(path1, savepath)num xlsread…