我已经在各种来源中读到,字符串字面量在程序的整个生命周期中都保留在内存中。那样的话,这两个功能有什么区别
char *f1() { return "hello"; }
char *f2() {
char str[] = "hello";
return str;
}
虽然f1
可以正常编译,但是f2
抱怨我正在返回堆栈分配的数据。这里会发生什么?
str
指向 actual 字符串文字(持续时间固定),为什么会出现错误?str
,那么原始字符串文字会放在哪里?它会保留在内存中而不对其进行引用吗?答案 0 :(得分:4)
我一直在阅读各种资料,其中字符串文字保留在其中 程序整个生命周期的内存。
是的
在这种情况下,什么是 这两个功能之间的区别
char *f1() { return "hello"; } char *f2() { char str[] = "hello"; return str; }
f1
返回一个指针,该指针指向由字符串文字表示的数组的第一个元素,该元素具有静态存储持续时间。 f2
返回指向 automatic 数组str
的第一个元素的指针。 str
具有用于初始化程序的字符串文字,但它是一个单独的对象。
虽然f1可以正常编译,但f2抱怨我正在返回堆栈 分配的数据。这里会发生什么?
- 如果str指向实际的字符串文字(具有静态持续时间),为什么会出现错误?
不是。实际上,它本身并不指向任何东西。它是一个数组,而不是指针。
- 如果字符串文字被复制到局部变量str,原始字符串文字会放在哪里?它是否保留在内存中而没有 引用吗?
C没有指定,但是实际上,是的,必须在程序的某个位置(可能是在函数实现中)存储字符串文字的某些表示形式,因为每次都需要使用它重新初始化str
f2
被调用。
答案 1 :(得分:3)
此
char str[] = "hello";
是由字符串文字"hello"
初始化的本地数组的声明。
实际上,这与您通过以下方式声明数组相同
char str[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
这是数组的自身内存区域(具有自动存储持续时间),它是由字符串文字初始化的。
退出函数后,该数组将不活动。
那是功能
char *f2() {
char str[] = "hello";
return str;
}
尝试返回一个指针,该指针指向具有自动存储持续时间的本地字符数组str
的第一个元素。
关于此函数定义
char *f1() { return "hello"; }
然后该函数返回一个指针,该指针指向确实具有静态存储持续时间的字符串文字"hello"
的第一个字符。
您可能会想到以下第一个函数定义
char literal[] = "hello";
char *f1() { return literal; }
现在比较在第一个函数定义和第二个函数定义中定义数组的位置。
在第一个函数定义中,数组literal
是全局定义的,而在第二个函数定义中,数组str
是局部定义的。
如果str指向实际的字符串文字(具有静态 时间),为什么会出现错误?
str
不是指针。它是由字符串文字初始化的命名内存范围。那就是数组的类型为char[6]
。
在return语句中
return str;
该数组被隐式转换为指向类型为char *
的第一个元素的指针。
C和C ++中的函数可能不返回数组。在C ++中,函数可能会返回对数组的引用。
答案 2 :(得分:1)
char str[] = "hello";
是一种特殊的语法,它复制字符串文字,并且您的函数返回一个指向此局部变量的指针,该指针在函数返回时将被销毁。
char *f1() { return "hello"; }
是正确的,但返回const char*
可能会更好。
答案 3 :(得分:1)
您将在堆栈上看到的字符串不是字符串文字的直接结果。在ELF
的情况下,该字符串与链接程序在链接过程中遇到的其他字符串文字一起存储在称为“字符串表部分”的可执行二进制文件的单独区域中。每当实例化实际上导致包含字符串的代码的堆栈上下文时,字符串表部分中的字符串内容就会实际复制到堆栈中。
您可能对以下内容感兴趣的简短阅读: http://refspecs.linuxbase.org/elf/gabi4+/ch4.strtab.html