我正在研究一个主要使用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)结尾的字符序列。
<<操作符实际上是从第一个字符位置开始循环,直到找到一个空字符。