如何在内存中分配C字符串?

时间:2012-12-22 16:05:05

标签: c

假设我有一个以这种方式返回C字符串的简单函数:

const char * getString()
{
  const char * ptr = "blah blah";
  return ptr; 
}

我以这种方式从main()调用getString():

  const char * s = getString();

1)根据gdb,变量 ptr 存储在堆栈中,但 ptr 指向的字符串不是:

(gdb) p &ptr
$1 = (const char **) 0x7fffffffe688

(gdb) p ptr
$2 = 0x4009fc "blah blah"

这是否意味着“blah blah”不是getString()中的局部变量?

我想如果它是一个局部变量,我将无法将它传递给我的main()函数... 但如果不是,它存储在哪里?在堆上?这是操作系统每次点击字符串时实现的“那种”动态内存分配,还是什么?

2)如果我使用数组而不是指针,这样:

const char *getString2()
{
  const char a[] = "blah blah blah";
  return a;
}

编译器警告我:

warning: address of local variable ‘a’ returned

(当然程序编译,但不起作用)。

实际上,如果我问gdb,我会

(gdb) p &a
$2 = (const char (*)[15]) 0x7fffffffe690

但我认为 const char * ptr const char a [] 基本上是一回事。看起来他们不是。

我错了吗?什么是两个版本之间的差异?

谢谢!

5 个答案:

答案 0 :(得分:7)

写作时

const char *ptr = "blah blah";

然后发生以下情况:编译器生成一个带有内容char []的常量字符串(类型为"blah blah")并将其存储在可执行文件的数据段中的某个位置(它基本上具有类似的存储持续时间)使用static关键字声明的变量。

然后,该字符串的地址(在程序的整个生命周期内有效)存储在ptr指针中,然后返回该指针。一切都很好。

  

这是否意味着"blah blah"不是getString()中的局部变量?

让我回答一个破碎的英语句子:是的,它不是。

但是,当您声明一个数组时,如

const char a[] = "blah blah";

然后编译器不生成静态字符串。 (实际上,这在初始化字符串时有点特殊。)然后生成代码,为a 数组分配足够大的堆栈内存(它不是指针!)并将用字符串的字节填充它。这里a 实际上是一个局部变量,并返回其地址导致未定义的行为。

因此...

  

但我认为const char *ptrconst char a[]基本相同。

不,完全没有,因为arrays are not pointers

答案 1 :(得分:3)

  

我想如果它是一个局部变量,我将无法通过   它到我的main()函数...但如果不是,它存储在哪里?

字符串文字通常存储在只读数据部分(.rodata)中。 C标准只是说它们有静态存储持续时间。因此,您可以返回指向此类文字的指针,但不是数组的情况。

在以下示例中,p1指向的对象具有静态存储持续时间,而数组p2具有自动存储持续时间。

char *f(void)
{
    const char *p1 = "hello, world";
    char p2[] = "hello, world";

    return p1; /* allowed */
    return p2, /* forbidden */
}

答案 2 :(得分:2)

在您的函数中,a[]数组的范围在函数getString2()内。它的本地数组变量

const char *getString2()
{
  const char a[] = "blah blah blah";
  return a;
}  

在上面的情况下,字符串"blah blah blah"将拳头复制到a[],并且您试图使用return a语句返回该数组,但不是常量字符串。

在第一个代码getString()中的位置:ptr = "blah blah"; ptr指向具有全局范围的内存。

const char * getString()
{
  const char * ptr = "blah blah";
  return ptr; 
}

在这种情况下,您将返回合法的常量字符串"blah blah"的地址。

实际上它的Scope问题。

了解C中的Memory Layout of C ProgramsVariable Scope会很有帮助。

答案 3 :(得分:2)

你说得对,他们不是一回事。 char a []是一个在堆栈上形成的数组,然后填充“blah ..” - 在函数内部,你基本上是`const char a [15]; strcpy(a,“blah blah blah”);“

另一方面,

The const char *ptr = "blah blah blah";只是一个指针(指针本身在堆栈上),指针指向字符串“blah blah blah”,它存储在其他地方[在“只读”数据中“ 最有可能的]。

如果你试图改变一些东西,你会注意到一个很大的不同,例如: a[2] = 'e'; vs ptr[2] = 'e'; - 第一个会成功,因为你正在修改堆栈值,第二个(可能)会失败,因为你正在修改一个只读内存,当然应该不行。

答案 4 :(得分:1)

他们不一样。

第一个是指向字符串文字的指针。指针本身处于自动存储中。该字符串位于静态只读内存中。这是不可改变的。

第二个是自动(堆栈)char数组(正如警告所说,该返回不合法)。