假设我有一个以这种方式返回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 [] 基本上是一回事。看起来他们不是。
我错了吗?什么是两个版本之间的差异?
谢谢!
答案 0 :(得分:7)
写作时
const char *ptr = "blah blah";
然后发生以下情况:编译器生成一个带有内容char []
的常量字符串(类型为"blah blah"
)并将其存储在可执行文件的数据段中的某个位置(它基本上具有类似的存储持续时间)使用static
关键字声明的变量。
然后,该字符串的地址(在程序的整个生命周期内有效)存储在ptr
指针中,然后返回该指针。一切都很好。
这是否意味着
"blah blah"
不是getString()中的局部变量?
让我回答一个破碎的英语句子:是的,它不是。
但是,当您声明一个数组时,如
const char a[] = "blah blah";
然后编译器不生成静态字符串。 (实际上,这在初始化字符串时有点特殊。)然后生成代码,为a
数组分配足够大的堆栈内存(它不是指针!)并将用字符串的字节填充它。这里a
实际上是一个局部变量,并返回其地址导致未定义的行为。
因此...
但我认为
const char *ptr
和const 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 Programs和Variable 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
数组(正如警告所说,该返回不合法)。