【问题标题】:In which manner array of characters is allocated memory locally? [duplicate]字符数组以哪种方式在本地分配内存? [复制]
【发布时间】:2013-09-19 06:49:04
【问题描述】:

这是我写的代码,

    char *foo();

    void main()
    {
      char *str=foo();
      strcpy(str,"Holy sweet moses! I blew my stack!!");
      printf("%s",str);
    }

    char * foo()
    {
      char str[256];
      return str;
    }

当我在函数 foo() 中使用 char 数组时,main() 函数中的 strcpy 不会将字符串复制到 str。但是,当我在函数 foo() 中使用 int 数组时,main() strcpy 复制成功。

   int str[256]; //in function foo

输出

   Holy sweet moses! I blew my stack!!

如果

   char str[256]; //in foo()

输出:什么都没有!

【问题讨论】:

  • 您将获得相同的输出。再次检查!
  • 不..我确定..我已经测试了一个小时!
  • 无论你在函数中使用int还是char数组,你所做的都是错误的。当foo() 返回时,数组超出范围。所以你正在返回一个指向未分配内存的指针。
  • @Alderath 请正确阅读问题..这只是我们的问题..
  • @mahesh 我是说你正在返回一个指向未分配内存的指针。笼统地回答正在发生的事情是不可能的。你正在做的是未定义的行为。不同的编译器可能会产生不同的结果。

标签: c


【解决方案1】:

您所做的显然是 UNDEF,但是.. 让我们尝试了解为什么它适用于 int 而不是 chars..

TL;DR:printf 使用堆栈,覆盖 str 指向的一些空间,但由于 int 数组在内存中比 char 数组大,因此它在堆栈中“遥遥领先”并且不会不会被覆盖。

一个 int 是 4 个字节,所以 256 个 int 将是 1024 个字节。

如果数组在堆栈中,这将指向 RBP - 例如 1024。

对于字符,一个字符是 1 个字节,256 个字符是 256 个字节。

如果数组在堆栈中,这将指向 RBP - 例如 256。

这是什么意思?当 foo 返回时,str 指针将指向当前堆栈指针“提前”的 1024 或 256 个字节。

SO.. 当你调用 strcpy(str, "yourstring");该内存可能会被 strcpy 和 printf 使用的堆栈覆盖。这里的问题是它被覆盖但不是所有堆栈,只是一点点,但足以覆盖 256 个字节,因此,该函数可以覆盖复制的字符串,这不会发生在您的 int 数组中,因为字符串会在堆栈指针之前复制 1024 位,strcpy 和 printf 不会使用太多堆栈。

让我告诉你你的堆栈将如何结束:

如果您更改 char 数组的大小,它可能会起作用。

所有这些都是未定义的行为,完全取决于您的架构、计算机和编译器。我目前正在使用 Linux x86_64。

【讨论】:

  • 感谢您抽出宝贵的时间来做这件事。我觉得这真的让我们明白了这一点,当人们仍在以某种方式让他的代码“工作”时,OP 可能会被人们谈论未定义的行为所迷惑..这确实解决了问题。
【解决方案2】:

你知道Scope and Lifetime Of Variables Concept 吗?如果是,那么您确实知道您正在尝试执行的操作会调用 "Undefined Behavior"。您很幸运,您的代码甚至打印出某些内容或根本不打印,而不是引用未分配的内存并由于堆损坏而崩溃。

来自SO Soln::

操作系统或语言在多大程度上控制堆栈/堆 运行时间?

操作系统在创建线程时为每个系统级线程分配堆栈。通常,语言运行时会调用操作系统来为应用程序分配堆。

他们的范围是什么?

堆栈附加到一个线程,因此当线程退出时堆栈被回收。 堆通常由运行时在应用程序启动时分配,并在应用程序(技术处理)时回收退出。

什么决定了它们的大小?

堆栈的大小在创建线程时设置。堆的大小在应用程序启动时设置,但可以随着空间的需要而增长(分配器向操作系统请求更多内存)。

【讨论】:

    【解决方案3】:

    当你函数foo()返回时,它会从栈中返回一个字符串的地址。当函数退出时,您的指针是无用的,因为当 foo() 停止时,您的字符串会从堆栈中删除。所以你有一个指向内存中某个地方的指针,但不知道那里有什么

    阅读编译器警告,我敢打赌,至少有一个告诉您您的函数返回指向局部变量的指针。(我这样做了,我也这样做了几次)。

    【讨论】:

      【解决方案4】:

      从你关于炸毁堆栈的字符串中,我得出结论,你知道你在做什么是错误的。因此我的回答是:未定义的行为是未定义的。当写入不属于您的内存时,可能会发生任何事情,包括您可能期望的事情和您可能不期望的事情。探索其他未定义的行为可能有点有趣,写入不属于您的内存则不是。它总是错的,它总是会做一些你意想不到的事情,而且没有任何情况下正确的解决方案就是不再做。

      当您将数组从 char 更改为 int 时,您会更改数组的大小,并且由于堆栈很可能在您的体系结构上增长,它会更改您不应该首先覆盖的内存地址。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-27
        • 2013-11-06
        • 1970-01-01
        • 2012-10-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多