内存管理,预处理,结构体

1.数据段       .bss   .data     .rodata)段

 

.bss

用来存放那些没有初始化和初始化为0的全局变量

bss类型的全局变量只占运行时的内存空间,而不占用文件空间

现在大多数操作系统,在加载程序时,会把所有的bss全局变量清0.但为保证程序的可以移植性,手工把这些变量初始化为0也是一个好习惯,这样这些变量都有个确定的初始值。当然作为全局变量,在这个程序的运行周期内,bss数据是一直存在的。

 

.data

data段用来存放那些初始化非零的全局变量

data类型的全局变量既占文件空间,又占用运行时的内存空间。同样作为全局变量,在整个程序的运行周期内,data数据是一直存在的。

 

.rodata

ro代表 read only rodata就是用来存放常量数据的。

在运行过程中不会改变的数据设为rodata类型,在多个进程间共享,可以大大提高空间利用率,甚至不占用RAM空间。同时由于rodata在只读的内存页面(page)中是受保护的,可以提高程序的稳定性。

字符串会被编译器自动放到rodata中,其他数据要放到rodata中,只需要加const关键字修饰。

 

 

2.代码段              .text段)

text段存放代码和部分整数常量,它与rodata段很相似,主要不同的在于这个段是可以执行的。

 

 

3.                  stack

栈用于存放临时变量和函数参数。栈作为一种基本数据结构,可以用来实现函数的调用。

尽管大多数编译器在优化时,会把常用的参数或者局部变量放入寄存器中。但用栈来管理函数的调用时的临时变量是通用做法,前者只是辅助手段,且只在当前函数中使用,一旦调用下一层函数,这些值任然要存入栈中才行。

通常情况下,栈向下增长,每向栈中PUSH一个元素,栈顶就向低地址扩展,每从栈中POP一个元素,栈顶就向高地址回退。

 

 

4.                 heap

 

堆是最灵活的一种内存,它的生命周期完全由使用者控制。标准的C语言提供以下几个函数:

· malloc 用来分配一块指定大小的内存

· realloc 用来调整/重分配一块存在的内存

· free     用来释放不在使用的内存

 

malloc/free 要配对使用。内存分配了不释放我们称为内存泄漏,内存泄漏多了迟早会出现 Out of memory的错误,再分配内存就会失败。

当然释放时也只能释放分配出来的内存,释放无效的内存或者重复free都是不行的,会造成程序crash。分配多少内存用多少,不管是读还是写,都只能在这个范围 ,读多了会读到随机数据,写多了会造成随机的破坏,这种情况称为缓冲区溢出,这是非常严重的,大部分安全问题都是由缓冲区溢出引起的。

 

注:

r-p 存放于 rodata

rw-p 存放于 bss

r-xp 存放于 text

没有文件名的内存空间,表示用mmap映射的匿名空间

文件名为【stack】的内存区间表示的是栈

文件名为【heap】的内存区间表示的是堆



5.内存分配的方式

有三种

 

1)从静态存储区域分配。内存在程序编译时就已经分配好了,这块内存在程序的整个运行期间都存在,如全局变量,static变量等。

2)在栈上创建。执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算使用内置于处理器的指令集,效率很高,但分配的内存容量有限。

3)从堆上分配,亦称动态内存分配。程序在运行时用mallocnew申请所需要的内存,程序员自己负责在何时用freedelete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也做多

全局变量和static变量是程序整个程序需要用到的,单独分出一块存储区保存,在程序的整个运行期间该存储区存储的数据不清空;局部变量在函数退出时自动清空,放在栈里进行临时存储。用指令newmalloc分配的内存需要自己在堆中手动申请并用freedelete指令手动释放。

 

6.指针和数组的对比

 

数组要么在静态存储区被创建,不么在栈上被创建。数组名对应着一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。

 

指针可以随时指向任意类型的内存块,它的特性是可变,所以常用指针来操作动态内存。指针远比数组灵活,但也更危险。

 

7.带参函数宏定义与自定义函数区别

 

1)在带参宏定义中,形式参数不分配内存空间,因此不必作类型定义;而宏调用中的实参有具体的值,要用它们去代换形参,因此必须作类型说明。这与函数中的情况是不同的,在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行值传递。而在带参宏,只是符号代换,不存在值传递的问题。

2)在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

 

注:在宏定义中,字符串内的形参通常要用括号括起来以避免出错。

 

 

8.#definetypedef 的区别

 

typedef只是为了增加可读性而为标志符另起的新名字,而#define原本在C语言中是为了定义常量。

宏定义只是简单的字符串代换,而typedef则不是原地扩展,它的新名字具有一定封装性,以致新名字的标识符具有更易定义变量的功能。

 

9.结构体和联合体的区别

 

structunion都是由多个不同的数据类型成员组成的,但在任何同一时刻,union中只存放了一个被选中的成员,而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,他们是同时存在的,一个struct变量的总长度等于所有成员长度之和;在union中,所有成员不能同时占有它的内存空间,他们不能同时存在,union变量的长度等于最长的成员的长度。

对于union的不同成员赋值,将会对其他成员重写,原来的成员的值就不存在了,而对于struct的不同成员赋值是互不影响的。

 

10.位段的使用

 

·位段的类型只能是intunsigned intsignedint三种类型,不能是char型或者浮点型。

·位段占的二进制位数不能超过该基本类型所能表达的最大位数,比如在VCint 4个字节,那么做多只能是32位。

·无名位段不能被访问,但会占据空间。

·不能对位段进行取地址操作。

·若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元开始存放。

·若位段出现在表达式中,则会自动进行整型升级,自动转化为int型或者unsigned int

·对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果。

·位段不能出现数组的形式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值