3

抱歉,如果这里已经发布了类似的内容,但我真的找不到。

我有以下代码,即使我会说这不正确,我也会收到正确的答案。

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是一个局部变量,它应该在它返回后从内存中清除(对吗?),所以我期待得到某种内存访问错误。

我应该认为自己很幸运这段代码可以工作(即这是一个未定义的行为吗?)或者这实际上是一种很好的做事方式(在这种情况下,为什么)?

我的猜测是,在函数返回后,指向数组的指针str会被清除,但它指向的实际内容不会被清除,它会一直保留在内存中,直到有其他内容写入它为止。如果有人能证实这一点,或者告诉我实际发生了什么,我将不胜感激。

提前致谢!

PS:我会这样做的方式是将缓冲区作为参数传递,但我只是想知道为什么,令人惊讶的是——至少对我来说——这确实有效。

4

4 回答 4

4

谁能告诉我为什么这实际上有效?

您假设这是未定义的行为,并且 UB 并不意味着“您的代码将以明显的方式崩溃或失败”,这意味着任何事情都可能发生。

在这种情况下,您可以设想用于存储本地的堆栈空间可能尚未被重用,并且可能仍包含原始值。它可能会在某些时候失败,但你不能指望它会以明显的方式失败。

但是,您没有在此处调用 UB,因为您正在返回指向静态分配的字符串文字的指针(并且可能存储在只读内存中,因此您确实应该返回 a const char*)。数组是本地的;字符串不是。

PS:我会这样做的方式是将缓冲区作为参数传递......

您还可以在函数中使数组成为静态的。这是否是一个好主意取决于您的整体设计。

于 2012-10-01T22:21:30.850 回答
2

字符串常量,例如“anything”,不存储在堆栈中。您的堆栈(在 selectStr() 中)包含一个指针数组,并且您正在返回一个指针,而不是堆栈上指针的地址。在这种情况下,您的指针将始终有效。

于 2012-10-01T22:22:50.973 回答
2

这段代码是正确的。

char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright",
};

这不会创建字符串数组。

它创建一个指向字符串的指针数组。字符串本身具有静态存储持续时间。指针数组具有自动存储持续时间。当函数返回时,指针数组变为禁区,但字符串仍然存在。

return str[index];

这将取消对数组的引用以检索指向其中一个字符串的指针,并返回该指针。 str超出范围,但指针仍指向静态存储中的字符串。

str标记为没有害处static。优化器可能已经这样做了。所以你可以写:

static char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright",
};

如果这让你更舒服。

于 2012-10-01T23:18:37.147 回答
1

我应该认为自己很幸运这段代码可以工作(即这是一个未定义的行为吗?)或者这实际上是一种很好的做事方式(在这种情况下,为什么)?

可能 =) 虽然,从你提出的论点来看,这很难说。出于所有意图和目的,它可能出于技术原因工作,但不是一个好主意。

我会在函数内部将数组设为静态,但如果这仍然让这里的人感到不安,为什么不增加范围呢?

static const char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright"
};

const char *selectStr(int index){
    return str[index];
}

当你在同一个文件中得到这个函数时,关于全局变量的程序设计考虑并没有真正考虑到它mainselectStr功能。不用担心。

我要做的唯一调整是将数组命名为比str.

于 2012-10-01T22:45:59.100 回答