使用字符串文字处理char * init时崩溃,但不使用malloc处理崩溃

我今天正在读一本关于C的书,它提到以下是真的; 我很好奇为什么要让这个程序validation; 然后最终在这里发布,所以比我聪明的人可以教我为什么这两个案例在运行时是不同的。

该问题的细节与运行时之间的差异有关,如何处理(char *)是基于它是否指向创建为文字的字符串与使用malloc和手动填充创建的字符串。

为什么内存分配的内存更像这样保护? 另外,答案是否解释了“总线错误”的含义?

这是我写的一个程序,询问用户是否想要崩溃,以说明程序编译正常; 并强调在我的脑海中,两个选项中的代码在概念上是相同的 ; 但那就是为什么我在这里,要明白为什么他们不是。

// demonstrate the difference between initializing a (char *) // with a literal, vs malloc // and the mutability of the contents thereafter #include  #include  #include  int main() { char cause_crash; char *myString; printf("Cause crash? "); scanf("%c", &cause_crash); if(cause_crash == 'y') { myString = "ab"; printf("%s\n", myString); // ab *myString = 'x'; // CRASH! printf("%s\n", myString); } else { myString = malloc(3 * sizeof(char)); myString[0] = 'a'; myString[1] = 'b'; myString[2] = '\0'; printf("%s\n", myString); // ab *myString = 'x'; printf("%s\n", myString); // xb } return 0; } 

编辑:结论

下面有几个很好的答案,但我想总结一下我在这里简明扼要地理解的内容。

基本答案似乎是这样的:

当编译器看到一个“字符串文字”分配给(char *)变量时,指针将指向静态的内存(实际上可能是二进制文件的一部分,但通常只能由低级系统执行,而不是换句话说,内存可能不是在程序的那一部分动态分配的,而是简单地将指针设置为指向包含文字内容的静态内存区域。

关于这个决议,我想说几件事:

1.优化可能是一个可能的动机:使用我的编译器,用相同的字符串文字初始化的两个不同的(char *)变量实际上指向相同的地址:

 char *myString = "hello"; char *mySecond = "hello"; // the pointers are identical! This is a cool optimization. 

2 Interstingly,如果变量实际上是一个chars数组(而不是(char *)),则此(#1)不为真。 这对我来说很有趣,因为我的印象是(编译后)数组与指向字符相同。

 char myArString[] = "hello"; char myArSecond[] = "hello"; // the pointers are NOT the same 

3总结了几个答案的暗示: char *myString = "Hello, World!" 分配新的内存,它只是将myString设置为指向已经存在的内存; 也许在二进制文件中,也许在一个特殊的只读内存块…等等

4我通过测试发现char myString[] = "Hello, World!" 确实分配了新的记忆; 我想……我所知道的是,这种方式创建时字符串是可变的

将变量设置为字符串文字时,将其设置为存储在汇编程序的只读数据部分中的值。 这些数据项是不变的,尝试以不同方式使用它们很可能会崩溃。

当您使用malloc获取内存时,您将获得一个指向读/写堆内存的指针,您可以执行任何操作。

这是由几个原因造成的。 首先, "Hello, world"的实际类型是char[13] ,或者是指向13个字符的常量指针。 您不能为常量字符赋值。 但是,当你做的事情就像你做的那样,这就是抛弃了常量。 这意味着编译器不会阻止您更改内存,但C标准调用是未定义的行为。 未定义的行为可以是任何东西,但通常是崩溃。

如果要为char*内存分配文字值,请执行以下操作:

 char* data = malloc (42); memcpy(data, "Hi!", 4); 

你真的应该将myString声明为const char* 。 文字存储在只读内存中,不能修改。 如果需要修改它,请使用char[]

什么

 myString = "ab"; 

确实将生成在只读内存中的常量字符串文字的地址赋给char指针myString

如果你现在写入这个内存,你就会崩溃。

OTOH,你当然可以愉快地写在malloc() ed内存上,这样才行。

C标准指定文字字符串是静态的 ,并且尝试修改它们会导致未定义的行为。 换句话说,它们应该被认为是只读的

您使用malloc分配的malloc属于您,您可以以任何您喜欢的方式对其进行修改。

实际差异可能与实现有关,但通常每种类型的字符串都位于两种不同类型/区域的内存中:

  • 在使用malloc获得的数据的情况下的堆,和
  • 字符串文字的(只读)数据部分。

如果你这样写怎么办:

 &mystring = &"ab"; 

这对你意味着什么?

你认为你可以以某种方式修改“ab”吗? &ab是哪里?

ANS:&“ab”在只读内存中。 当编译器看到QUOTE时,它将该字符串放在不可变的内存中。 为什么? 如果运行时没有必要检查并检查段错等,可能会更快。 对于真正永远不会改变的字符串数据。