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

时间:2012-07-07 23:16:24

标签: c string memory runtime string-literals

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

问题的细节与在运行时之间的差异有关,如何根据是否指向创建为文字的字符串与使用malloc和手册创建的字符串来处理(char *)人口。

为什么内存分配的内存会受到更多这样的保护?另外,答案是否解释了"总线错误"的意思?

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

// demonstrate the difference between initializing a (char *) 
// with a literal, vs malloc
// and the mutability of the contents thereafter
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
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;
}

编辑:结论

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

基本答案似乎是:

  

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

我想提出一些关于这个决议的事情:

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

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

2 在中间,如果变量实际上是一个字符数组(而不是(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!" 确实分配新内存;我想......我所知道的是,当以这种方式创建时,字符串是可变的

5 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

什么

myString = "ab";

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

如果您现在写入此内存,则会崩溃。

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

答案 2 :(得分:1)

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

您使用malloc分配的内存属于您,您可以通过任何方式对其进行修改。

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

  • 使用malloc
  • 获取数据时的堆
  • 字符串文字的(只读)数据部分。

答案 3 :(得分:1)

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

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

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

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

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

答案 4 :(得分:0)

如果你写了这个怎么办:

&mystring = &"ab";

这对你意味着什么?

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

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