Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
返回C中的字符串。为什么这样做有效?_C_String_Memory_Parameter Passing - Fatal编程技术网

返回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个字节。我个人希望范围尽可能窄。没有