处理char*init'时崩溃;使用字符串文字,但不使用malloc
我今天读了一本关于C的书,书中提到了以下事实:;我很好奇为什么我做这个程序来验证;然后最终在这里发布,这样比我聪明的人可以教我为什么这两种情况在运行时是不同的 问题的具体内容与(char*)在运行时的处理方式(基于它是否指向作为文本创建的字符串)与使用malloc和手动填充创建的字符串)之间的差异有关 为什么由内存分配的内存会受到这样的保护?另外,答案是否解释了“总线错误”的含义 下面是我编写的一个程序,它询问用户是否希望崩溃,以说明该程序编译得很好;要强调的是,在我的脑海中,两个选项中的代码在概念上是相同的;但这就是为什么我在这里,去理解为什么他们不在处理char*init'时崩溃;使用字符串文字,但不使用malloc,c,string,memory,runtime,string-literals,C,String,Memory,Runtime,String Literals,我今天读了一本关于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”
ischar[13]
,noconst
。历史上的意外,可能最初没有const
。我怀疑您提到的汇编程序的只读数据部分正是我想要的。如果编译器看到一个文本,它可以将其包含在实际的程序数据中,而不需要动态分配它“在运行时调用内存。@DanielFischer:但数组是c
&mystring = &"ab";