返回C中的字符串。为什么这样做有效?
很抱歉,如果类似的东西已经被张贴在这里,但我真的找不到它 我有以下代码,即使我会说这是不正确的,我收到了正确的答案返回C中的字符串。为什么这样做有效?,c,string,memory,parameter-passing,C,String,Memory,Parameter Passing,很抱歉,如果类似的东西已经被张贴在这里,但我真的找不到它 我有以下代码,即使我会说这是不正确的,我收到了正确的答案 char *selectStr(int index){ char *str[] = { "hello", "hola", "epa", "alright", }; return str[index]; } int main() { printf("String: %s\n", sele
char *selectStr(int index){
char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
return str[index];
}
int main() {
printf("String: %s\n", selectStr(2));
return 0;
}
有人能告诉我为什么这真的有效吗?我的看法是:字符串数组str
是selectStr函数中的局部变量。此函数返回此数组中包含的字符串。但是由于这个字符串数组str
是一个局部变量,所以在它返回后应该从内存中清除它(对吗?),所以我希望得到某种内存访问错误
<> P>我应该觉得自己是幸运的吗?这个代码是有效的(也就是说,这是一个未定义的行为)?或者这实际上是一个很好的做事方式(在这种情况下,为什么?)
我的猜测是,指向数组str
的指针在函数返回后会被清除,而不是它所指向的实际内容,它会一直保留在内存中,直到有其他内容写入。如果有人能证实这一点,或者告诉我到底发生了什么,我将不胜感激
提前谢谢
PS:我的方法是将缓冲区作为参数传递,但我只是想知道为什么,令人惊讶的是——至少对我来说——这实际上是可行的
有人能告诉我为什么这真的有效吗
您假设这是未定义的行为,UB并不意味着“您的代码将以明显的方式崩溃或失败”,它意味着任何事情都可能发生
在这种情况下,您可以设想用于存储本地数据的堆栈空间可能尚未被重用,并且可能仍然包含原始值。它可能会在未来的某个时候失败,但你不能指望它会以明显的方式失败
但是,在这里您并没有调用UB,因为您返回的是一个指向静态分配的字符串文本的指针(可能存储在只读内存中,所以您确实应该返回一个常量char*
)。阵列是本地的;字符串不是
PS:我要做的是将缓冲区作为参数传递
您还可以在函数中使数组保持静态。这是否是一个好主意取决于您的总体设计。字符串常量,如“anywhere”,不会存储在堆栈中。堆栈(在selectStr()中)包含指针数组,您返回的是指针,而不是堆栈上指针的地址。在这种情况下,指针将始终有效
我是否应该认为自己是幸运的,这个代码是有效的(也就是说)
或者这实际上是一种很好的做事方式
(在这种情况下,原因是什么)
可能=)不过,从你提出的论点来看,很难说。出于各种目的,它可能出于技术原因而起作用,但这不是一个好主意
我会使数组在函数中保持静态,但是如果这仍然让这里的人不安,为什么不增加范围呢
static const char *str[] = {
"hello",
"hola",
"epa",
"alright"
};
const char *selectStr(int index){
return str[index];
}
当您将此函数与main
…放在同一个文件中时,与全局函数相关的程序设计注意事项实际上并不存在。。。如果将其拆分为一个模块,则将该数组设置为源文件的私有数组,并导出selectStr
函数。不用担心
我要做的唯一调整是将数组命名为比str
更明显的全局性。此代码是正确的
char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
这不会创建字符串数组
它创建一个指向字符串的指针数组。字符串本身具有静态存储持续时间。指针数组具有自动存储持续时间。当函数返回时,指针数组将被禁用,但字符串仍然存在
return str[index];
这将取消对数组的引用以检索指向其中一个字符串的指针,并返回该指针str
超出范围,但指针仍指向静态存储中的字符串
将str
标记为static
没有害处。优化器可能已经在这样做了。所以你可以写:
static char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
如果这能让您更舒适。阵列是本地的。但实际情况并非如此。您正在返回文本。使数组
静态
(或者更好的静态常量
)将消除未定义的行为const
会更好,因为它可以防止有人弄乱函数返回的字符串。@威尔:我在底部提到了一个静态数组,但在这种情况下,没有UB。字符串不是函数的本地字符串,这是一种特殊情况。不,我想不是。不过,如果要将常量定义为函数的一部分,最好使用const。否则,使用strdup()
返回副本可能是个好主意。你永远不知道什么样的虫子会被唤醒。@will:哦,是的,我不反对。返回类型显然应该是const char*
或返回一个副本,数组也应该是静态的。在C中没有堆栈或只读内存的概念。因此,这个答案是无效的。@RichardJ.RossIII:我同意“自动存储持续时间”是一个更好的说法,但是,来吧;事实上,我使用过的每一个C编译器都使用一个堆栈作为局部变量。函数当然有一个堆栈,堆栈上有一个指针数组。这些指针指向只读内存,所以本质上你同意我的答案,但方式很奇怪。@mahH不,堆栈是一种实现细节,通常用于实现具有自动存储持续时间的变量的存储机制。C规范并不要求使用堆栈(或任何其他)结构,只要求语言定义的语义保持正确。Richard是正确的,尽管有点迂腐。@Ed-如果我只使用selectStr()函数创建一个文件,并将其传递给gcc-S
,反汇编将显示一个包含16个字节的堆栈;每个指针4个字节。我个人希望范围尽可能窄。没有