3

我今天正在读一本关于 C 的书,它提到以下内容是正确的;我很好奇为什么要制作这个程序来验证;然后最终将其发布在这里,以便比我聪明的人可以教我为什么这两种情况在运行时不同。

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

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

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

// 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;
}

编辑:结论

下面有几个很好的答案,但我想在这里简洁地总结一下我所理解的。

基本答案似乎是这样的:

当编译器看到将“字符串文字”分配给 (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!" 确实分配了新的内存;我想......我所知道的是,以这种方式创建的字符串是可变的。

4

5 回答 5

2

你真的应该声明myStringconst char*. 文字存储在只读内存中,无法修改。char[]如果您需要修改它,请使用 a 。

于 2012-07-07T23:18:22.150 回答
2

什么

myString = "ab";

所做的是将位于只读内存中的常量字符串文字的地址分配给char 指针myString

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

OTOH,当然,您可以愉快地在malloc()ed 内存上书写,这样就可以了。

于 2012-07-07T23:20:07.610 回答
1

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

当你malloc用来获取内存时,你会得到一个指向读/写堆内存的指针,你可以做任何事情。

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

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

char* data = malloc (42);
memcpy(data, "Hi!", 4);
于 2012-07-07T23:25:41.517 回答
1

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

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

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

  • 使用 获取数据的情况下的堆malloc,以及
  • 在字符串文字的情况下(只读)数据部分。
于 2012-07-07T23:22:32.390 回答
0

如果你这样写:

&mystring = &"ab";

这对你意味着什么?

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

ANS: &"ab" 在只读存储器中。当编译器看到 QUOTE 时,它会将该字符串放入不可变内存中。为什么?如果运行时不必进行边界检查和检查段错误等,可能会以某种方式更快。在真正不应该改变的字符串数据上。

于 2012-07-07T23:34:12.553 回答