我今天正在读一本关于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!"
确实分配新内存;我想......我所知道的是,当以这种方式创建时,字符串是可变的。
答案 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时,它将该字符串放在不可变的内存中。为什么?如果运行时不必检查并检查段错等,可能会更快。对于真正永远不会改变的字符串数据。