C和C++对记忆的误解

C and C++ misunderstanding of memory

本文关键字:误解 记忆 C++      更新时间:2023-10-16

拜托,我想知道变量,数组和字符串如何在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 byteshort : 2 bytesint : 4 byteslong : 4 bytesfloat : 4 bytesdouble : 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) 位于数据部分而不是堆栈中并且初始化一次(编译期间)而不是每次调用函数时(在执行期间)。