C和C++对记忆的误解
C and C++ misunderstanding of memory
拜托,我想知道变量,数组和字符串如何在C语言中存储在内存中的现实。请在下面的示例中纠正我对内存的理解:
在 C 中,当我们声明一个字符串时,我们按如下方式进行:
char string[]="string";
内存中会发生什么?每个字符是否存储在内存中 每个内存案例都有其地址?
例如,地址
1600 char[0]='S'
1602 char[2]='t'
等等.这是真的吗?如果没有,请给我一个正确的模式,说明实际发生的事情。
我的第二个问题是关于C++: C++年,他们发明了一种新型数据,即string
。例如:
string variable("This is a string");
此文本("这是一个字符串")如何存储在内存中?
查看 String in Depth:
[...]字符串类的内存布局的确切实现不是由C++标准定义的。此体系结构旨在足够灵活,以允许编译器供应商进行不同的实现,同时保证用户的行为可预测。[...]
[...]在C++中,单个字符串对象可能会也可能不会占用内存的唯一物理区域,但如果使用引用计数来避免存储重复的数据副本,则各个对象的外观和行为必须像它们专门拥有唯一的存储区域一样。[...]
您可以了解编译器如何实现string
,如下所示。对我来说(在VS2010下测试),它将是
string variable("This is a string");
printf("%pn", &variable[0]); // 006751C0
printf("%pn", &variable[1]); // 006751C1
printf("%pn", &variable[2]); // 006751C2
printf("%pn", &variable[3]); // 006751C3
printf("%pn", &variable[4]); // 006751C4
printf("%pn", &variable[5]); // 006751C5
... ...
字符串都存储为以空结尾的字符数组(ASCII 代码中的每个字符都是 8 位宽的,这样它正好占用一个字节),因此它们需要多一个字节来存储"\0"字符("hi"需要三个字节的数组) 如果在 c++ 中使用 std::string,则用于存储数据的内存是相同的,但是在它周围有一个允许自动内存管理的包装器,因此当您这样做时:
string s("hello");
string t("world");
s+=t;
s 被扩展甚至移动到内存中的其他位置,如果有必要,以便找到更长的连续字节数组。 以同样的方式当您致电时
s.c_str();
你会得到一个指向包含在 s std::string 类实例中的 char 的 null 终止数组的指针,该指针只是一个临时指针,因此
char* text=s.c_str();
s="very long string that probably results in a complete reallocation of the array";
printf("%s",text);
可能导致未定义的行为(分段错误)
它们以字节的形式存储:char : 1 byte
short : 2 bytes
int : 4 bytes
long : 4 bytes
float : 4 bytes
double : 8 bytes
前言:
每次生成(编译和链接)项目时,都会创建一个可执行映像,分为三个部分:
-
代码部分
-
数据部分
-
叠
现在将涉及四种不同的方案:
场景 #1 - 一个本地数组(在函数内声明):
int func()
{
char array[]="string";
...
}
加载并运行程序后,每次调用函数时,堆栈上某处的 7 个字节将使用以下值初始化:">s"、"t"、"r"、"i"、"n"、"g"、0。堆栈上这些字节所在的地址是调用函数时 SP 寄存器的值。因此,每次调用该函数时,这 7 个字节可能驻留在内存中的不同地址中。
场景 #2 - 一个全局数组(在函数外部声明):
char array[]="string";
在编译期间(在加载和运行程序之前),数据部分中的 7 个字节使用以下值设置:">s"、"t"、"r"、"i"、"n"、"g"、0。这些字节被"硬编码"到可执行映像中,一旦它被加载到内存中(即,只要你运行程序),它们在整个程序执行过程中驻留在同一个地址。
场景 #3 - 指向本地数组的指针(在函数内声明):
int func()
{
char* array="string";
...
}
与场景 #2 相同,除了这 7 个字节位于代码部分(这是只读部分)而不是数据部分(读/写部分)中。此外,每次调用函数时,都会在堆栈上分配一个指针(array
)并初始化(设置为指向代码部分中"string"
的地址)。使用 32 位 RAM 时,此指针的大小通常为 4 个字节,使用 64 位 RAM 时,此指针的大小通常为 8 个字节。
场景 #4 - 指向全局数组的指针(在函数外部声明):
char* array="string";
与场景 #3 相同,除了指针 (array
) 位于数据部分而不是堆栈中并且初始化一次(编译期间)而不是每次调用函数时(在执行期间)。
- 松弛原子与无同步情况下的记忆连贯性
- 递归函数有效,但无法记忆
- 如何将记忆应用于此递归函数?
- #if 如何工作?我误解了 #if~#endif 的形式吗?
- 共享记忆:让我们谈谈它的特殊性
- 为什么nlohmann不释放记忆
- CPP 中的瓦尔格林德和记忆泄漏:"Conditional jump or move depends on uninitialised values"
- 毕达哥拉斯三重嵌套循环误解
- C++17 多态记忆资源不起作用
- 我是否漏了记忆?
- 关于记忆后这种递归关系的时间复杂度
- 记忆栅栏和记忆屏障是一样的吗
- 使用记忆在 C++ 中实现 Knapstack
- 无论如何可以将webm / mp4文件编译/记忆为.exe程序吗?(C++)
- 误解可变参数模板函数
- 如何在硬币兑换中添加记忆
- C++:误解内存地址和指针的复制值
- 动态记忆的删除是如何真正起作用的
- C++遗传,记忆问题
- C和C++对记忆的误解