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

lau*_*ids 12 c

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

const char * getString()
{
  const char * ptr = "blah blah";
  return ptr; 
}
Run Code Online (Sandbox Code Playgroud)

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

  const char * s = getString();
Run Code Online (Sandbox Code Playgroud)

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

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

(gdb) p ptr
$2 = 0x4009fc "blah blah"
Run Code Online (Sandbox Code Playgroud)

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

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

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

const char *getString2()
{
  const char a[] = "blah blah blah";
  return a;
}
Run Code Online (Sandbox Code Playgroud)

编译器警告我:

warning: address of local variable ‘a’ returned

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

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

(gdb) p &a
$2 = (const char (*)[15]) 0x7fffffffe690
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!

小智 7

当你写作

const char *ptr = "blah blah";
Run Code Online (Sandbox Code Playgroud)

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

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

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

让我用一句破碎的英语句子回答:是的,事实并非如此.

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

const char a[] = "blah blah";
Run Code Online (Sandbox Code Playgroud)

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

所以...

但我认为,const char *ptrconst char a[]基本上是同样的事情.

不,完全没有,因为数组不是指针.


md5*_*md5 6

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

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

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

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

    return p1; /* allowed */
    return p2, /* forbidden */
}
Run Code Online (Sandbox Code Playgroud)