九月的最后一天,首先祝我们的祖国生日快乐,让我们继续砥砺前行……

来到了指针系列的第三篇,我们来说说指针的运算以及变量在内存中的存储问题,重点在于后者。

首先看一下指针的算术运算:

int a = 1,*pa=&a,*pa1=&a;
double b=3.1415,*pb=&b;printf("before pa++,pb++:\n");
printf("&a=%#x,pa=%#x,pa1=%#x,&b=%#x,pb=%#x\n", &a,pa,pa1,&b,pb);pa++; pb++;
printf("after pa++,pb++:\n");
printf("&a=%#x,pa=%#x,pa1=%#x,&b=%#x,pb=%#x\n", &a, pa, pa1, &b, pb);
if (pa==pa1){printf("pa和pa1指向同一数据\n");}
else{printf("pa和pa1指向不同数据\n");}

我们定义了整型变量a以及指向它的两个指针pa和pa1,浮点型变量b以及指向它的指针pb,建议大家以后定义指针用这种形式,避免我上次犯的错误,误将pb定义成了int *型;

看结果:

在指针++前后做对比可以发现,整型指针pa++后值增加了4,而浮点型指针pb增加了8,这正是对应数据类型所占的内存大小,反映到图上大概是这样的:

因为一个整型变量a占据4个字节,而内存的分配基本单位为1个字节,所以pa++后pa应前进4个字节指向如上图所示位置,假如pa++后pa前进1个字节,那pa将把其后的四个字节当作一个整体,其中前三个字节属于变量a,最后一个字节并不知道是个啥,所以最终的输出也就很难保证了。最后的pa和pa1比较的是他们的值,即保存的地址,由于二者所保存的地址不一样,所以输出为pa和pa1指向不同的数据。

第二部分我们说一下变量在内存中的分配问题,其实这个东西在前两篇都已经提到了,我们这次再深入一些~

int g=0,x = 1, y = 2, z = 3;
int *m = &z;
for (int i = 0; i<20; i++) {printf("%d, ", *(m + i));
}
printf("\n");int g1=0,x1 = 4,  y1= 5, z1 = 6;
int *m1 = &z1;
for (int i1 = 0; i1<20; i1++) {printf("%d, ", *(m1 + i1));
}
printf("\n");int  g2=0,x2= 7, y2 = 8, z2 = 9;
int *m2 = &z2;
for (int i2 = 0; i2<20; i2++) {printf("%d, ", *(m2 + i2));
}
printf("\n");printf("m=%#x,m1=%#x,m2=%#x\n", m, m1, m2);
printf("*(m2 -3) = %#x,*(m2 -2) = %d,*(m2 -1) = %d\n",*(m2 - 3), *(m2 - 2), *(m2 - 1));

看着又是好大一坨,其实都是一种形式,这一块我做了多次试验,不断地添加东西,所以现在看着有些杂乱,咱们还是长话短说,从上述代码大家应该能看到,我们连着定义了很多变量,然后使用for循环输出,一开始的时候只有xyz三个变量,循环输出8个值,感觉不是很明显,之后又加到循环输出12个值,此时可以看出一些端倪:

当然这时候还没有写最后一条输出语句~大家可以先看最后的m、m1和m2,地址依次减小,从整体上符合我们之前讨论过的地址的分配原则(变量入栈,后进先出,所以后定义的变量先分配地址),然后再看上边输出的三行数据,依然是满足“后定义先分配”的原则,先输出z,之后依次是y和x,只不过这中间还有些其他数据,而且多次实验证明这个“其他数据”还是固定的-858993460,而且出现的很有规律,都在两个连续定义的变量中间出现两次,而这个值正是debug模式下编译器对未初始化的变量赋的默认值~~~

并且大家可以看到,m、m1和m2之间是有关系的,两两之差都为60,即60个内存单元(字节),而一个int型变量占据4个字节,每两个变量之间还有两个默认值共占8个字节,从上述代码可以看到我们定义了四个变量x-y-z-m-i,这样每一部分共占15字节大小(大家可以理解成每个变量后跟两个整型的默认值),正是每一部分起始地址之差~~

怎么样,是不是感觉已经乱了,这一块真的是好说不好写啊,我们还是直接看图吧:

为了方便我直接将上图中的一小块写成4字节,这样看起来比较直观,大家可以发现每一部分的样式是相同的,从m2开始依次存储,其中XX代表默认值-858993460;(以下这一部分实在惭愧,大家可以直接跳到最后看总结)

这里边最大的亮点就是我们上图标出的m1,由于这个值是以十进制输出的,并且每次运行都会改变,所以我立即就想到了这是不是某个地址,因为我们定义的这些变量在不同批次的运行时所分配的内存空间都不一样,果不其然,十进制转十六进制,就是下一个部分的起始地址,而大家需要注意的是这个地址是在每一部分开始前的内存空间中,基于这样的原理我们可以假设最开始分配空间的m2的地址在其后方三个整型存储空间大小的位置,于是我们使用上述代码的最后一行依次输出:

不出所料,m2-3所指向的内存空间的值正是m2的值,这里需要说明的是(m2 - 3)是个指针,大家要分清指针的值和指针所指向数据的值的区别,即m2 - 3和 *(m2 - 3)的不同,对应于上边的手工画图,前者为0x73f91c,后者为0x73f928

为了更加直观我们可以看一下上述代码最终的输出效果,看看每一部分输出20次并着增加一个变量g之后是怎么样的结果:

不难看出,变量的输出顺序和我们想象的一样,并且这些空间可以理解成是在一定基础上连续的,比如倒数第二行,这是第三部分的内容,当输出到后边出现了“6”,而这正是第二部分开始输出的内容,这样三部分内容就连起来了~~~

这其中还有一个问题就是第一行的输出并不按套路出牌,i的值20没有正常输出,而是显示的11795016,再往后也是一塌糊涂,并且每次运行所得结果都在变化,由此可以推想这一块也是系统随机分配的~

当然这一块内容细说起来还是挺多的,大家可以尝试修改数据类型为double,看看会有什么变化,那个默认值-858993460会以怎样的形态出现,自己动手运行一下,会有惊喜。。

大概就这些了,又是相当啰嗦,总结一下吧:

1. 指针的算术运算所移动的单位量取决于所指向的数据类型,这也体现了定义指针时的类型要和所指数据类型一致的重要性;

2. 连续定义的变量之间地址是不连续的(通常情况是这样,如果有例外还请大家不吝赐教),中间会有一些辅助性的数据(通常为两个四字节的默认值);并且越先定义的变量分配的地址越靠后,这其中需要注意的是比如我们定义int a=1,b=2,c=3;   int d=4;那么d的地址是最先分配的,其次是c、b、a~

ok,现在说一下刚刚发现的一个问题,就在刚才我试着运行上边定义的abcd,结果跟想象的不一样,本以为按照前边的输出,d的地址应该是靠后的,木有想到其地址是最先分配的,此刻突然想到前边提到的第一行中的变量i没有按套路出牌输出20,因为这里根本就不是第一部分的变量i!!!!大家看一下我们定义变量的顺序,按照先定义后分配的原则应该是先分配给i地址,之后是指针m,再往后是zyx,这个原则不管是在全局还是局部都是成立的,也就是说我的手工画图中的那个变量i不是第三部分的而是第二部分的!!!这么重要而浅显的一点我竟然没有意识到。。。总之就是我们定义的这三部分正确的打开方式应该是从变量i开始,依次存储的是i-m-z-y-x。。

好了,就这样吧,老了老了,脑子是真的反应迟钝,让我缓缓,各位午安……

—如果文章对您有一点点帮助,还请打赏一二,您的鼓励将是我前进的不竭动力—

公众号为“非著名IT表演艺术家”,比较中二的名字,就是灵光一闪,然后这个名字就冒出来了……

手绘知识点——指针运算变量的内存分配原理相关推荐

  1. 手绘知识点——指针入门

    距离上篇博客整整一个月了,秋招的黄金期,感觉自己的节奏和去年此时的师兄师姐完全不在一个频道上,找工作真的是玄学,真的是有缘千里来相聚啊,不多说了,祝福每位毕业季的同学(比心)- 一直以来都想搞一个手工 ...

  2. 手绘知识点——数组指针

    各位老铁国庆节过的可还好,前天看了大阅兵,很激动,国富民强,我等也应该感到自豪- 来到指针系列第四篇,我们聊聊数组指针,即指向数组的指针.那您可能会问了,这东西有啥好说的,前边不都提了嘛,最多就是指针 ...

  3. C语言——指针篇(二)指针和数组之内存分配和初始化

    前言:在上一篇文章中说到了指针变量和普通变量的区别,那么这一篇文章中就来说说指针和数组的关联和区别,它们在很多应用场合中可以互相取代,但也在很多场合中有着自己的无法替代的作用和地位. 数组和指针的内存 ...

  4. 内存泄漏的原因及解决办法_编程基础 | C++片段 指针、多态和内存分配

    本片段将介绍运行期而不是编译期的内存分配 1.变量的内存分配和方法的前期绑定 函数中声明的局部变量与其参数以及簿记数据一起被放置在一个活动记录中.活动记录存储在名为运行期栈(run-time stac ...

  5. JAVA中堆栈和内存分配原理

    JAVA中堆栈和内存分配原理 1.栈.堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...

  6. 深入Java核心 Java内存分配原理精讲

    深入Java核心 Java内存分配原理精讲 Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详 ...

  7. C/C++语言变量声明内存分配

    [cpp] view plaincopy <span style="font-family: Verdana, Arial, Helvetica, sans-serif; " ...

  8. 【C/C++】变量的内存分配

    一个由C/C++编译的程序占用的内存分为以下几个部分: 1.栈区(stack)-- 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.程序结束时由编译器自动 ...

  9. C语言的变量的内存分配

    今晚看了人家写的一个关于C语言内存分配的帖子,发现真是自己想找的,于是乎就收藏了... 先看一下两段代码: char* toStr() {char *s = "abcdefghijkl&qu ...

最新文章

  1. java+js上传图片_java+ jsp+js 实现富文本编辑和上传图片功能
  2. 老段mysql,老段视频汇总
  3. 【转】从3个科技公司里学到的57条经验
  4. 吴恩达深度学习课程deeplearning.ai课程作业:Class 2 Week 1 1.Initialization
  5. CSDN博主排名更新公告
  6. ansible(自动化运维上)——ansible部署,添加主机组,连通性测试
  7. hdu1176 免费馅饼 动态规划 二维数组实现
  8. 互联网躺平学 ,从后端到前端有多吃香?
  9. hdu4857 拓扑排序
  10. 老掉牙的ArrayList解析它它它又来了
  11. 计算机usb接口电压不稳定,如何处理笔记本电脑USB接口的电源不足或电压不稳定?...
  12. 使用域名访问服务器网站,使用域名访问网站是啥意思
  13. Linux 中的 fold 命令详解及C/C++代码实现
  14. vue+croppr.js 裁剪圆形图片
  15. win7浏览器主页修改不过来_win7系统浏览器主页修改不了的解决方法
  16. 怀想集——高中众生相
  17. 【技术推荐】WebLogic 反序列化漏洞深入分析
  18. linux自动启动 oracle
  19. 操作系统 实验报告 linux 内核,linux操作系统内核实验报告.doc
  20. mysqlbinlog 加-v -vv 的区别

热门文章

  1. 面试题06:一串英文数字转换成阿拉伯数字
  2. 机械手 c语言,51单片机机械手控制C程序
  3. Qt程序异常结束以及crashed的解决办法
  4. java中Integer.parseInt用法详细分析(全)
  5. 医疗健康数据安全合规论坛召开 落实合规提升数据安全水平
  6. 华为鸿蒙和麒麟的区别,华为麒麟、凌霄、鸿鹄三大芯片有什么区别?
  7. HIbernate中的事务
  8. 组织及其IT部门的职责划分
  9. junit中log4j日志不打印到控制台
  10. 一文带你用Python玩转线性回归模型《加利福尼亚房价预测》回归模型评估指标介绍