我很困惑何时将内存分配给char *以及何时将其指向const字符串。
是的,据我所知,如果我想修改字符串,我需要分配内存。
但是,如果我不想修改我指向的字符串并且只需要传递该值,我应该执行以下操作吗?与使用malloc
分配内存相比,以下步骤有哪些缺点?
char *str = NULL;
str = "This is a test";
str = "Now I am pointing here";
答案 0 :(得分:19)
让我们再次尝试使用-Wwrite-strings
编译器警告标志的示例,您将看到警告:
warning: initialization discards 'const' qualifier from pointer target type
这是因为“这是一项测试”的类型是const char *
,而不是char *
。因此,当您将文字地址分配给指针时,您将丢失constness信息。
由于历史原因,编译器将允许您存储在非const变量中作为常量的字符串文字。
然而,这是一种不良行为,我建议您始终使用-Wwrite-strings
。
如果您想自己证明,请尝试修改字符串:
char *str = "foo";
str[0] = 'a';
此程序行为未定义,但您可能会在许多系统上看到分段错误。 使用Valgrind运行此示例,您将看到以下内容:
Process terminating with default action of signal 11 (SIGSEGV)
Bad permissions for mapped region at address 0x4005E4
问题是编译器生成的二进制文件会将字符串文字存储在内存位置which is read-only中。通过尝试在其中写入,您将生成segmentation fault。
重要的是要理解的是,您在这里处理两个不同的系统:
C打字系统可帮助您编写正确的代码,并可轻松“静音”(通过演员等)
内核内存页面权限,用于保护您的系统,并始终受到尊重。
同样,由于历史原因,这是1.和2.不同意的一点。或者更清楚一点,1。比2.更宽松(导致你的程序被内核杀死)。
所以不要被编译器欺骗,你声明的字符串文字真的是不变的,你不能对它做任何事情!
考虑你的指针str
读写是正常的。
但是,要编写正确的代码,它应该是const char *
而不是char *
。通过以下更改,您的示例是C:
const char *str = "some string";
str = "some other string";
(const char *
指向const字符串的指针)
在这种情况下,编译器不会发出任何警告。执行代码后,您编写的内容以及内存中的内容将匹配。
注意:const字符串指向const char *const
:
const char *const str = "foo";
经验法则是:始终尽可能保持不变。
如果你需要修改字符串,使用动态分配(malloc()或更好,一些更高级别的字符串操作函数,如来自libc的strdup等),如果你不需要,使用字符串文字
答案 1 :(得分:5)
如果你知道str
将永远是只读的,为什么不这样声明呢?
char const * str = NULL;
/* OR */
const char * str = NULL;
嗯,实际上有一个原因可能是这很困难 - 当你将字符串传递给一个不会声明自己的只读函数时。假设您正在使用声明此函数的外部库:
int countLettersInString(char c, char * str);
/* returns the number of times `c` occurs in `str`, or -1 if `str` is NULL. */
此函数已有详细记录,您知道它不会尝试更改字符串str
- 但如果您使用常量字符串调用它,您的编译器可能会给您一个警告!你知道没有什么危险,但你的编译器没有。
为什么呢?因为就编译器而言,也许这个函数 尝试修改字符串的内容,这会导致程序崩溃。也许你非常依赖这个库,并且有很多函数都像这样。然后,首先可能更容易不将字符串声明为const
- 但是这一切都取决于你,以确保你不会尝试修改它。< / p>
另一方面,如果您是{em>正在编写 countLettersInString
函数,那么只需确保编译器知道您不会通过声明{来修改字符串'来修改字符串{1}}:
const
这样它就会同时接受常量和非常量字符串。
答案 2 :(得分:4)
使用字符串文字的一个缺点是它们有长度限制。 所以你应该记住ISO / IEC:9899号文件 (强调我的)
5.2.4.1翻译限制
1实现应能够翻译和执行至少一个包含以下每个限制的至少一个实例的程序:
[...]
- 字符串文字或宽字符串文字中的4095个字符(连接后)
因此,如果你的常量文本超过了这个数量(特别是如果你用C语言编写动态网络服务器,那么有时可能会禁止你使用字符串文字方法,如果你想保持系统独立。
答案 3 :(得分:3)
只要您没有计划修改该字符串的内容,代码就没有问题。此外,此类字符串文字的内存将保留该程序的整个生命周期。 malloc
分配的内存为读写,因此您可以操作该内存的内容。
答案 4 :(得分:2)
如果您有一个不想修改的字符串文字,那么您正在做的是:
char *str = NULL;
str = "This is a test";
str = "Now I am pointing here";
这里str
指针有一个指向的内存。在第二行,你写入内存"This is a test"
,然后在3行中再次写入内存"Now I am pointing here"
。这在C中是合法的。
您可能会发现它有点矛盾,但您无法修改类似这样的字符串 -
str[0]='X' // will give a problem.
但是,如果您希望能够修改它,使用它作为缓冲区来保存一行输入等等,请使用malloc
:
char *str=malloc(BUFSIZE); // BUFSIZE size what you want to allocate
free(str); // freeing memory
如果您不知道编译期间所需的内存量,请使用malloc()
。
答案 5 :(得分:1)
不幸的是,它在C 中是合法的,但是任何通过指针修改字符串文字的尝试都会导致 undefined 行为。
说
Person
答案 6 :(得分:1)
它运行正常,但编译器可能会收到警告,因为你指的是一个常量字符串。
P.S。:只有在不修改它时它才会运行。因此,不使用malloc
的唯一缺点是您将无法修改它。