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

处理char*init'时崩溃;使用字符串文字,但不使用malloc,c,string,memory,runtime,string-literals,C,String,Memory,Runtime,String Literals,我今天读了一本关于C的书,书中提到了以下事实:;我很好奇为什么我做这个程序来验证;然后最终在这里发布,这样比我聪明的人可以教我为什么这两种情况在运行时是不同的 问题的具体内容与(char*)在运行时的处理方式(基于它是否指向作为文本创建的字符串)与使用malloc和手动填充创建的字符串)之间的差异有关 为什么由内存分配的内存会受到这样的保护?另外,答案是否解释了“总线错误”的含义 下面是我编写的一个程序,它询问用户是否希望崩溃,以说明该程序编译得很好;要强调的是,在我的脑海中,两个选项中的代码在

我今天读了一本关于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;
}
2有趣的是,如果变量实际上是一个字符数组(而不是一个(char*)),那么这(#1)就不是真的我对此很感兴趣,因为我的印象是(编译后)数组与指向字符的指针相同

char myArString[] = "hello";
char myArSecond[] = "hello"; // the pointers are NOT the same
3总结几个答案所暗示的:
char*myString=“Hello,World!”
不分配新内存,它只是将myString设置为指向已经存在的内存;也许在二进制中,也许在一个特殊的只读内存块中。。。等等


4我通过测试发现
char myString[]=“你好,世界!”
确实分配了新内存;我想。。。我所知道的是,当以这种方式创建字符串时,字符串是可变的。

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

什么

myString = "ab";
does是将驻留在只读内存中的常量字符串文本的地址分配给char指针
myString

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


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

C标准规定文本字符串是静态的,试图修改它们会导致未定义的行为。换句话说,它们应该被视为只读的

使用
malloc
分配的内存属于您,您可以用任何方式修改它

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

  • 使用
    malloc
    获取数据时的堆,以及
  • 字符串文本情况下的(只读)数据部分

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

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

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

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

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

如果你写了这样的话:

&mystring = &"ab";
那对你意味着什么

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


ANS:&“ab”位于只读存储器中。当编译器看到该引号时,它会将该字符串放入不可变内存中。为什么?如果运行时不必对真正不应该更改的字符串数据进行边界检查和segfault等检查,速度可能会更快。

谢谢您的评论;然而,我完全理解其中的区别。我来这里是为了了解为什么文字会像这样在受保护的内存中,特别是当它们没有被赋予使用
const
@ctrahey声明的LVAR时:因为当数据存储在二进制文件中并且无法修改时,可能会执行某些优化。例如,所有引用
“某些只读字符串”
的指针都可以引用相同的地址。@ctrahey:也就是说,它是在标准中指定的,所以这并不重要。不必执行任何优化;简单地说,字符串文字存储在静态内存中,任何试图修改字符串文字的行为都会导致未定义的行为。.C标准规定,可以将字符串文字分配给只读内存,并且在不调用未定义的行为的情况下,不能对其进行修改(§C2011标准中的§6.4.2¨7)。+1提及不可修改性的可能动机(共享该常数)。此处的注释确实是我在回答中所要的。您是否可以编辑您的答案以包含这些注释,以便将来发现此线程?尝试修改字符串文字会导致未定义的行为。它不需要崩溃,也可以按需工作。C中的可能重复,类型为
“Hello,world”
is
char[13]
,no
const
。历史上的意外,可能最初没有
const
。我怀疑您提到的汇编程序的只读数据部分正是我想要的。如果编译器看到一个文本,它可以将其包含在实际的程序数据中,而不需要动态分配它“在运行时调用内存。@DanielFischer:但数组是c
&mystring = &"ab";