基本的c风格字符串内存分配

Basic c-style string memory allocation

本文关键字:字符串 内存 分配 风格      更新时间:2023-10-16

我正在研究一个主要使用c++但带有C风格字符串的现有代码的项目。例如:

#include <iostream>
int main(int argc, char *argv[])
{
    char* myString = "this is a test";
    myString = "this is a very very very very very very very very very very very long string";
    cout << myString << endl;
    return 0;
}

当输出为长字符串时,编译和运行良好。

然而,我不明白为什么它的工作。我的理解是

char* myString 

是一个指针,指向一个足够大的内存区域,可以容纳字符串字面量"this is a test"。如果是这样的话,那么我如何能够在相同的位置存储一个更长的字符串呢?我预计它会崩溃,当这样做的时候,因为试图把一个长字符串塞进一个为短字符串留出的空间。

很明显,这里发生的事情有一个基本的误解,所以我感谢任何帮助理解这一点。

你没有改变内存的内容,你改变了指针的值,指向一个不同的存储"this is a very very very very very very very very very very very long string"的内存区域。

注意,char* myString只为指针分配足够的字节(通常是4或8字节)。当您执行char* myString = "this is a test";时,实际发生的情况是,在程序启动之前,编译器在可执行映像中分配空间,并将"this is a test"放在该内存中。然后当你执行char* myString = "this is a test";时,它实际上只是为指针分配足够的字节,并使指针指向它在编译时已经在可执行文件中分配的内存。

如果你喜欢图表:

char* myString = "this is a test";
(allocate memory for myString)
              ---> "this is a test"
            / 
myString---
                   "this is a very very very very very very very very very very very long string"
然后

myString = "this is a very very very very very very very very very very very long string";
                   "this is a test"
myString---
            
              ---> "this is a very very very very very very very very very very very long string"

内存中有两个字符串。首先是"this is a test",假设它从地址0x1000开始。第二个是"this is a very very ... test",它从地址0x1200开始。

char* myString = "this is a test";

创建一个名为myString的变量,并为其分配地址0x1000。然后,通过

myString = "this is a very very ... test";

您分配0x1200。

cout << myString << endl;

只打印从0x1200开始的字符串。

您有两个类型为const char[n]的字符串字面值。这些变量可以赋值给类型为char*的变量,该变量只不过是一个指向char的指针。当你声明一个类型为pointer-to- t的变量时,你只是声明了指针,而不是它所指向的内存。

编译器为这两个字面值保留内存,你只需将指针变量一个接一个地指向这些字面值。字符串字面值是只读的,它们的分配由编译器负责。通常它们存储在受保护的只读内存中的可执行映像中。字符串字面值的生命周期通常等于程序本身的生命周期。

现在,如果您试图修改文字的内容,它将是UB,但您没有这样做。为了防止自己在错误中尝试修改,明智的做法是将变量声明为const char* .

在程序执行期间,分配一个包含"这是一个测试"的内存块,并将该内存块中第一个字符的地址分配给myString变量。在下一行中,分配了一个单独的内存块,其中包含"this is a very very…",并且该内存块中第一个字符的地址现在被分配给myString变量,用"very very long"字符串的新地址替换它用于存储的地址。

为了便于说明,我们假设第一块内存是这样的:

[t][h][s][i][s][a][t][e][s][t]我们假设这个序列/字符数组中第一个't'字符的地址是0x100。因此,在myString变量的第一次赋值之后,myString变量包含地址0x100,它指向"这是一个测试"的第一个字母。

那么,一个完全不同的内存块包含:

[t] [h][我][s][][我][s] [] [] [] [v] [e] [r] [r] [y]…假设第一个t的地址是0x200。因此,在myString变量的第二次赋值之后,myString变量NOW包含地址0x200,它指向"this is a very very very…"的第一个字母。

因为myString只是一个指向字符的指针(因此:"char *"是它的类型),它只存储字符的地址;它不关心数组应该有多大,它甚至不知道它指向一个"数组",只知道它正在存储字符的地址…

例如

,你可以合法地这样做:

    char myChar = 'C';
/* assign the address of the location in 
   memory in which 'C' is stored to 
   the myString variable. */
    myString = &myChar; 

希望这足够清楚。如果是,请投票/接受答案。如果没有,请评论以便我澄清。

字符串字面值不需要分配-它们按原样存储并且可以直接使用。从本质上讲,myString是指向一个字符串文字的指针,并被更改为指向另一个字符串文字。

char*表示指向存储字符的内存块的指针。

C风格的字符串函数得到一个指向字符串开头的指针。它们假设存在一个以0-null字符(n)结尾的字符序列。

<<操作符实际上是从第一个字符位置开始循环,直到找到一个空字符。