C++的内存分布
1. 四大区域
通用的是数据区(.data;.bss;常量区)和代码区(.text)。在程序的执行过程中,我们需要创建变量,以及调用函数,从而产生了堆和栈。
- 数据区:
比如:全局变量,静态变量。包括静态局部变量。- .data:用于存储初始化的全局变量、静态变量。这些变量在程序开始执行前就已经被分配和初始化了,它们的值在程序执行过程中可以被修改。
- .bss:区域用于存储未初始化的全局变量和静态变量。当全局变量以及静态变量被初始化为0或者
nullptr
的时候也会存放在.bss
区。
- 代码区(.text区):
比如:字符串常量。
.text
t区域存储程序的执行代码,即编译后的机器语言指令。这个区域通常是只读的,以防止程序在运行时被意外或恶意修改。 - 堆区:
就是那些由new
和malloc
分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new
就要对应一个delete
。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 - 栈区:
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
2. 例题
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = {1, 2, 3, 4};
char char2[] = "abcd";
char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof (int)*4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int)*4);
free (ptr1);
free (ptr3);
}
1. 选择题:
选项: A.栈 B.堆 C.数据段 D.代码段
globalVar在哪里?__C__ staticGlobalVar在哪里?__C__
staticVar在哪里?__C__ localVar在哪里?__A__
num1 在哪里?__A__char2在哪里?__A__
pChar3在哪里?__A__ ptr1在哪里?__A__
2. 填空题:
sizeof(num1) = ____; 40
*char2在哪里?_A__ *pChar3在哪里?__D__ *ptr1在哪里?__B__
sizeof(char2) = ____; 5 strlen(char2) = ____; 4
sizeof(pChar3) = ____; 4 strlen(pChar3) = ____; 4
sizeof(ptr1) = ____; 4
3. 字符串常量、string、char[]
#include <iostream>
int main() {
// 字符串常量定义在代码中
const char* str1 = "Hello, World!";
// 尝试修改字符串常量的内容,这是不允许的
// str[0] = 'h'; //error
std::cout << "Address of the const char constant: " << (void*)str1 << std::endl;
std::cout << "Content of the const char constant: " << str1 << std::endl;
cout << endl; cout << endl; cout << endl;
string str2 = "Hello, World!asfdsgefdgqwertyuioasdfghjkzxcvbnm,qwertyuisdfghjkxcvbnm,ertyuidfghjkftgasyhdifjnia";
std::cout << "Address of the string constant: " << &str2 << std::endl;
std::cout << "Content of the string constant: " << str2 << std::endl;
cout << endl;
str2[0] = 'h';
std::cout << "Address of the string constant: " << &str2 << std::endl;
std::cout << "Content of the string constant: " << str2 << std::endl;
cout << endl; cout << endl; cout << endl;
char str3[100] = "Hello, World!";
std::cout << "Address of the char[] constant: " << &str3 << std::endl;
std::cout << "Content of the char[] constant: " << str3 << std::endl;
return 0;
}
str2这么长的原因是因为字符串长度较短,std::string
会使用小字符串优化(SSO),这意味着字符串的内容可能直接存储在 str2
对象内部,而不是堆上。
显示结果如下:
发现const char*的类型地址和string,char[]的地址差距过大。
由此可见他们直接是有区别的。
区别如下:
- const char*:
const char* str = "Hello, World!";
这行代码中的"Hello, World!"
是一个字符串常量,存放在程序的只读数据段。 - string:
- 在函数内部定义的
std::string
对象通常存储在栈上。std::string
是一个类类型,其实例会在栈上分配内存空间。但是,std::string
内部通常会动态分配内存来存储实际的字符串数据,这部分数据是存放在堆上的。 - 例如,当你在
main()
函数中创建一个std::string str = "Hello, World!"
;,str
对象的控制结构(如指针、长度和容量等)会存放在栈上,而字符串"Hello, World!"
的字符数据会通过堆分配存放。
- 在函数内部定义的
- char[]:
- 在函数内定义的
char[]
数组,如char arr[] = "Hello, World!"
;,数组的内容直接存储在栈上。这包括数组的所有元素,即字符序列。 - 数组
arr
的所有字符(包括终结符\0
)都会在栈上分配,且在函数执行期间持续存在,直到函数返回。
- 在函数内定义的
tips:
小字符串优化(SSO):
SSO是一种用于减少存储短字符串时的内存分配开销的优化技术。在C++中,这种优化通常在实现std::string
等字符串类时使用,其中包含一个固定大小的内部缓冲区,用于存储较短的字符串。当字符串长度不超过这个内部缓冲区的容量时,字符串的内容就可以直接存储在这个缓冲区中,而不需要进行堆分配。