【问题标题】:Unable to predict the ouput of the following program [duplicate]无法预测以下程序的输出[重复]
【发布时间】:2015-04-02 15:08:34
【问题描述】:

我对悬空指针有一个想法。我知道下面的程序会产生一个悬空指针。但是我无法理解程序的输出

char *getString()
{
        char str[] = "Stack Overflow ";
        return str;
}
int main()
{
        char *s=getString();
        printf("%c\n",s[1]);
        printf("%s",s);    // Statement -1
        printf("%s\n",s);  // Statement -2
        return 0;
}

以下程序的输出是 吨 如果只有 Statement-1,则输出是一些抓取值 如果只有 Statement-2 则输出是新行

【问题讨论】:

  • 消化完下面的答案后,请考虑一下为什么只更改程序中的一些内容,然后works。提示:char *varchar var[] 在函数参数的上下文之外同义。

标签: c arrays pointers


【解决方案1】:

您的代码显示undefined behaviour,因为您正在返回一个局部变量的地址。

一旦getString()函数执行完毕并返回,str就不存在了。

至于问题,

如果只有 Statement-1 则输出是一些抓取值 如果只有 Statement-2 则输出是新行

没有解释。一旦您的程序表现出未定义的行为,就无法预测输出,仅此而已。 [谁知道呢,它也可能会打印你的手机号码,或者一个守护进程可能会从我的鼻子里飞出来]

对于简单的逻辑部分,在printf() 中添加\n 将导致输出缓冲区立即刷新到输出。 [提示:stdout 是行缓冲的。]

解决方案:

您可以通过以下两种方式之一完成您的工作

  • 获取一个指针,在getString() 内动态分配内存并返回该指针。 (我会推荐这个)。另外,完成后,free() 稍后在main() 中发送。
  • 使char str[]static 的作用域不限于函数的生命周期。 (不太好,但仍能胜任)

【讨论】:

  • 我只是想知道 statement-1 和 statement-2 答案的区别,也想知道为什么 printf("%c\n",s[1]);是t
  • @user3673490 当函数结束时,变量(以及您返回的指针)超出范围。由于该内存是在 stack 上分配的,因此会损坏。因此它可以打印t 或任何东西。
  • @Sunil 这里发生的事情是数组的第二个元素是 t,当我尝试打印第三个元素时,我得到了正确的答案
【解决方案2】:

你在getString中的str是一个局部变量,在栈上分配,当函数返回时,它就不存在了。

我建议你像这样重写getString()

char *getString()
{
        char str[] = "Stack Overflow ";
        char *tmp = (char*)malloc(sizeof(char)*strlen(str));
        memcpy(tmp, str, strlen(str));
        return tmp;
}

你需要添加

free(s);

return 0;之前

在我的例子中,指针tmp 指向堆上的一块内存,它会一直存在到你的程序结束

你需要了解更多关于stack and heap

另外,还有一种方法,用静态变量代替

char *getString()
{
        static char str[] = "Stack Overflow ";
        return str;
}

PS:你得到以下陈述printf("%c\n",s[1]);的正确答案只是一个巧合。当您从函数返回时,Opera System 没有时间做一些干净的工作。但它会

【讨论】:

  • 但是为什么我得到以下语句 printf("%c\n",s[1]); 的正确答案;
  • @Teja 你不明白这一点。你得到任何东西 是无关紧要的。您的程序调用了未定义的行为,因此格式错误。您不能依赖、预测或从中得出任何没有行为定义的结论。不要将观察到的行为与定义的行为混淆。
【解决方案3】:

数组作为指针返回,但数组本身是函数返回后的垃圾。只需使用静态修饰符。

关于 s[1] 的事情没问题。关键是,它是获得悬空指针后的 first printf。因此,此时的堆栈仍然(可能)完好无损。您应该记得堆栈仅用于函数调用和局部变量(在 DOS 中它可以被系统中断使用,但现在情况并非如此)。因此,在第一个 printf 之前(计算 s[1] 时),s[] 是可以的,但之后 - 它不是(printf' 代码搞砸了)。我希望,现在一切都清楚了。

【讨论】:

  • 顺便说一句。要确切知道发生了什么,应该使用反汇编程序。没有它,上面写的一切都只是猜测。例如,如果编译器出于任何可能的原因决定在第一个 printf 之前再使用一个本地(即堆栈)变量,则 s[1] 也可能被破坏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-13
  • 2014-06-29
相关资源
最近更新 更多