为什么我们需要使用strdup()函数?

13

我在做作业的时候,了解到我们不应该使用以下形式的赋值语句:

 char *s="HELLO WORLD";
程序使用这些语法的情况容易崩溃。
我尝试并使用了:
 int fun(char *temp)
 {
    // do sum operation on temp
    // print temp.
  }
  fun("HELLO WORLD");

即使上面的代码可以工作(尽管输出可能与编译器和标准相关),但我们应该尝试使用strdup()或者使用const char *。

我已经尝试阅读博客上其他类似的问题,但是我无法理解为什么上面的代码不能工作。

内存是否被分配??而const有什么区别??


1
提示:'const char*'相对于'char*'有什么意义,为什么在上述情况下使用它会有益处(例如,如何通过访问修改 s1 "导致崩溃")? 'strdup'允许使用'const char*'做什么? - user166390
char *s="HELLO WORLD" 是一种初始化,而不是赋值。无论如何,你为什么认为它不好? - qrdl
5个回答

21
让我们澄清一下。你不需要特别使用strdup函数。它只是在堆上分配一个char*的副本的函数,可以通过许多不同的方式实现,包括基于栈的缓冲区。你需要的是结果,即一个可变的char*的副本。
所列出的代码之所以危险,是因为它将真正的常量字符串作为字符串字面值传递到期望可变字符串的位置。这在C标准中是被允许的,但是内在上是危险的。写入常量字符串会产生意外的结果,并经常导致崩溃。 strdup函数修复了这个问题,因为它创建了一个可变的副本,放置在期望可变字符串的位置。

那么,如果我不尝试修改字符串(例如,只是打印输出),那么使用这样的字面量而不使用const是安全的吗? - letsc
@smartmuki 根据标准,这是合法的,但仅限于向后兼容的原因,并且仍然是一种危险的转换。如果您定义一个不会改变字符串的函数,则最好将其声明为“const char *”。 - JaredPar
我只尝试过使用gcc编译器,并且它显示了预期的输出。但是编译器会因为上述原因导致分段错误吗?如果确实如此,那么为什么?:( - letsc

7

字符串字面量存储在程序的数据段中。操纵它们的指针会修改字符串字面量,这可能会导致最好的情况下出现奇怪的结果。相反,使用strdup()将它们复制到堆或栈分配的空间中。


即使 const char *s="hello" 在堆栈上分配了字面量的空间。我们使用这样的语法来解决问题(甚至在 printf(const char *s, VLA ) 中也是如此)。 - letsc
3
这并不会在栈上分配文字的空间,只有指向该文字的指针位于栈上。 - Darron
@Darron 抱歉,但那是什么?如果我将其用作 const char *s,则如果空间未在堆栈上分配(也未在堆上分配),那么它是否实际分配了空间?(或者甚至已分配) - letsc
1
@smartmuki:在堆栈上分配了一个单一指针。字符串字面量仍然存在于数据段中,指针指向它。 - Ignacio Vazquez-Abrams

3

字符串字面量可能存储在没有写权限的内存部分中。尝试对其进行写操作将导致未定义行为。const表示编译器确保指针不被写入,保证您不会以这种方式调用未定义的行为。


2

这是C语言中的一个问题。虽然字符串字面值是char *类型,但您无法修改它们,因此它们实际上是const char*类型。

如果您使用的是gcc编译器,可以使用-Wwrite-strings选项检查您是否正确使用了字符串字面值。


1

阅读我的回答 (数组和字符串) Java与C之间的区别。它在关于字符串的部分包含了你问题的答案。

你需要理解静态和内存分配之间的区别,并且不要使用相同的内存空间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接