原创 【博客大赛】路人C++学习笔记——揭秘内存(1)

2013-1-24 15:56 2159 17 18 分类: 软件与OS 文集: 路人C++学习笔记

第一篇的学习笔记整理,一直在想应该从哪开始说起,仔细归纳下发现,其实软件学习最重要和最频繁的就是跟内存打交道了,所以决定先说一说内存。

曾经在一本大牛的著作里看到说,软件设计中绝大部分的bug都来自于程序员对代码中内存的使用不清楚而出现的“误操作”。而我觉得,高手与新手的区别就在于是否对程序所使用硬件资源的了如指掌了。

言归正传,我们要揭秘内存,我选择从sizeof说起(对它的重新认识让我觉得学校所讲的那些个编程课我都白听了…必须得好好弄清楚才行)。

首先,sizeof是一个运算符?对,是的,它不是函数,而是一个单目运算符。更严格的说,它是编译运算符,也就是说,在编译器编译时,它便得出了运算结果(也就是我们想知道的数据类型或变量所占用的内存空间)。

下面就来举例说明它的应用了,也许其中会有让你大吃一惊的地方。

1、各基础类型大小;

这个相对简单,字符型char为1个字节,其它的int、float、double等根据不同的编译环境而有所不同。如下图,博主在VS2010,win7-64bit环境下编译的结果。此处有两点需要说明,有的编译器会将‘*’这样的字符常量分配2个字节的大小,原因很简单,就是在末尾加入了一个‘\0’;还有一点就是我们可以看到,一个浮点常数是被默认当做double型来处理的。

qq截图01.jpg 

2、数组及指针;

直接先给出结果,如下图代码及结果。对于字符数组,需要注意‘/0’的添加,这常常会让我们忽略这个字节。而对于其它类型的数组则不会添加任何数据。指针类型的大小则更加依据程序的编译环境,这里需要注意的是,如本例中,虽然所使用的操作系统为64位的win7,但我们在VS2010中选用的编译环境仍然是Win32,所以此处指针类型的大小(也就是内存地址的大小)仍然是32位,4个字节。还有一点需要说明,sizeof运算符可以用于void的指针,却不能用于void类型,因为void属于不完全类型,即具有未知内存大小的数据类型,同样的还有:函数类型、未知大小的数组类型、未知内容的结构或联合类型等。

 qq截图03.jpg

qq截图02.jpg

3、结构体及联合体类型;

先来说明下结构体和联合体,结构体是将几个数据类型的变量结合起来形成一个整体,其中每个变量都是这个结构体的一个属性,都会被分配到相应的内存。而联合体,则是指几个数据类型的变量共用一片内存空间,只是名称指代不一样。有一个最好理解的例子:需要得到一个既可bit复制又可字节赋值的字节,先将八个bit型定义成一个字节的结构体,然后将这个结构体和一个char型定义为一个联合体,这样便可以达到我们的目的了。

两者的区别理解了以后,我们再来看sizeof运算两者的结果。对于联合体,得到的其所最大字节成员的大小,这个在了解了联合体的作用便很容易明白了,为了满足所有成员的使用,必须给它分配最大的那个成员的内存了。那我们便自然会觉得,对于结构体,不就是所有成员变量所占用空间的大小之和么?如下图的程序和结果,会发现,并不是这样的!而且都比我们预想的要大。这是为什么??简单来说,这是编译器对内存分配采用的对齐方式。
下面我们细说下这种对齐方式。在给结构体分配内存时,按照定义的顺序依次对变量进行分配,从第二个变量开始,就需要对地址进行对齐,我们的对齐数就是已经分配过的变量和正要分配变量中字节数最大的类型的大小,我们定义为N,则当我们每分配一个变量时,会得到一个对齐数,然后根据这个对齐数和上一个变量首字节地址A,来获得我们要分配变量的首字节地址B,如果(A+N)能被N整除则B=A+N,如不能则B往后移至可以整除为止。如本程序例子,对于st3这个结构体,c0分配到地址2095528;n分配时,对齐数N=4,n的地址为2095532,在c0后面则插入了三个空字节;c分配时,对齐数仍为4,才的地址为2095536,;d分配时,对齐数N变成了8,则需在c后面插入7个空字节,d的地址为2095544;c1分配时,同理,c1地址为2095552,但需在其后面再插入7个空字节来对齐,这样st3共占用32个字节,地址从2095528到2095560。(为什么编译器需要这样来做呢?下回详解)
另外还需要注意的是,对于结构体中的静态变量,sizeof是不计算它所占用的空间的,因为静态变量统一被分配与静态内存区,与结构体无关。而且,空的结构体也是需要占用1个字节大小的,因为每一个结构体实例都必须在内存中占有独一无二的地址。

qq截图05.jpg

qq截图06.jpg

qq截图04.jpg

4、在函数中,数组等做形参时;

这样的情况我们需要把握一点,数组做形参时,函数调用实际传递的是地址。如下面的例子,得到的结果正是说明函数所传递的只是数组的首地址而已,把数组当做指针来用。
还有种情况,如果是函数做形参呢??其实,还是传递的地址,只不过是代码的地址。

qq截图09.jpg

qq截图08.jpg

qq截图07.jpg

5、sizeof与strlen的对比;

对于字符串的长度计算我们常常用strlen,需要注意的是它是一个函数,而不是运算符。其函数原型如下图。可见,它会在遇到0x00时返回。

qq截图10.jpg

对于上例中的s5,我们使用strlen计算得到的是21,为什么呢?而且,为什么我们输出s5这个字符串时显示的是“123456烫烫烫烫烫Hello”,这里面的“Hello”显然是我们s4中定义的那个“Hello”吧?这又是怎么回事呢?(同样的,下回详解)

 

文章评论1条评论)

登录后参与讨论

用户593939 2013-1-28 22:57

学习了,参考了
相关推荐阅读
jlx_cuc 2014-06-06 18:19
你真的会socket编程吗(1)
最近的项目都围绕着TCP socket在进行着,VC下的socket,Linux下的socket,感觉很简单,但是却发现其实下面的几个同事对于socket这个东西还只是“会”,但并不一定懂。 ...
jlx_cuc 2014-05-16 18:44
操作系统-读书笔记(1)
最近在业余阅读时找到一本《自己动手编写操作系统》觉得不错,视角很新颖,是有关操作系统书籍中为数不多的看了不想睡觉的读本。   由于这本书的出版时间较早,书中引导盘还使用的是软盘,所以在跟随...
jlx_cuc 2014-05-08 17:13
“改变”后的一丝体会
有两个月没写博客了,现在正是开学之际,有必要对前面两个月的工作做做记录。   经历过从北京到苏州的工作地点转换,生活和工作上的体会和收获颇丰。到苏州来以后会觉得,原来的一些看法还是太过狭隘...
jlx_cuc 2014-05-08 17:13
最终我又不要脸的回来了——成为一名“管理者”后的心得
之前的很长一段时间都没再更新过这个博客,一直在EDN潜水,一直在做伸手党。原因有两个,一个是忙,一个是懒。 最终我还是不要脸的回来了。还是想以后好好把这个博客经营下去,也好等咱们的娃长大了给它...
jlx_cuc 2013-07-11 17:13
【博客大赛】写给“即将入学”的硕士研究生们
原本题目定的是《写给即将入学的硕士研究生们》,后来想了想便加上了双引号。先来说说这个双引号。   早在一个多月前全国考研的最后结果便出来了,对于考上研的同学们来说,马上就要开始自己的研究生...
jlx_cuc 2013-04-08 23:22
【博客大赛】老罗和他的锤子之我的见解
事先说明,个人感觉我的观点还算是中立观点,并不是要感叹老罗和锤子有多好,也不想批评它们是否一无是处。只是想在时隔这么就没来EDN,恰巧又遇到锤子的发布这个时间点,发表些个人的感想和见解。 ...
我要评论
1
17
关闭 站长推荐上一条 /2 下一条