C/C++内存模型
内存分区
操作系统以进程来分配和管理内存资源,一个进程的结构又可以分为5大部分:代码区、数据区、BSS段、堆、栈。
Stack(栈)
栈由编译器自动管理,由高地址向低地址生长。存放函数的实参,局部变量等信息。由于栈的后出先进(LOFI)的特性,故可以很好地对函数的调用和返回进行维护。关于ebp和esp如何维护栈空间可自行百度。
Heap(堆)
堆用于程序运行中动态申请空间,由低地址向高地址生长。空间大小大于栈。堆是先进先出(FIFO)。关于如何维护堆空间可自行百度。
注意:堆内存需要程序员手动管理内存,通常适用于较大的内存分配,如频繁的分配较小的内存,容易导致内存碎片化。
BSS(Block by symbol)
存放未初始化的全局和静态变量。(默认设为0)
Data Segment(数据段)
存放已初始化的全局和静态变量, 常量数据(如字符串常量)。
Code Segment(数据段)
存放可执行程序的机器码。
字符串字面量存储形式
首先必须清楚一点,字符串是按照ASCII码或Unicode按字节排列,并以’\0’结束。
- C语言字符串存储机制
特征:
- 字符指针类型会存储在字面量池(数据段)中,相同字符串的指针都指向该字符串
- 字符数组类型则会在该存储区中另外存储该字符串
const char* ptr1 = "Hello World";
int main()
{
const char* ptr2 = "Hello World";
char ch[] = "Hello World";
printf("ptr1:%p\n", ptr1);
printf("ptr2:%p\n", ptr2);
printf("ptr:%p\n", ch);
return 0;
}
可以看出ptr1和ptr2都指向了常量池中的”Hello World“字符串,而ch字符数组则是在main函数栈中的另一份字符串。
2. C++string机制
先介绍关于string的几个函数:
- c_str():指向动态分配空间的字符数组的第一个字符
- size():字符串长度(不包括’\0’)
- capacity():当前字符数组的最大存储能力,不包括’\0’
- malloc():
初始化的string size=5,capacity=15,sizeof结果=40;我们不断得向字符串中加入‘+’字符,当字符串长度达到15时仍然不会进行扩容,说明capacity指不包含\0所能包括的最长字符,当size<=capacity时不会扩容。下图为c++ primer 6说明。
对于capacity分配的内存块大小,根据程序结果应当不包含\0,但字符串一定是以\0为结尾的,所以\0位置还有待商讨。
当字符串长度超过capacity时进行扩容,大小为原来两倍。但sizeof的大小却始终为40,这是因为sizeof获取的是string对象所占的字节数,并不包括字符串。