【问题标题】:Why does my C array remember old data from a previous function call?为什么我的 C 数组会记住以前函数调用的旧数据?
【发布时间】:2021-11-19 04:35:36
【问题描述】:

当我运行以下 C 代码时,我得到了值:

  • 222222222
  • 312222222
  • 102222222

我期待这些值:

  • 222222222
  • 31
  • 10

为什么我的 intToStr 函数中定义的 char number[] 会记住以前的值?我认为一旦函数调用结束,所有本地数据或多或少都会被破坏。

#include <stdio.h>

void intToStr(int n);

int main(void)
{
    intToStr(222222222);
    intToStr(31);
    intToStr(10);

    return 0;
}

void intToStr(int n)
{
    char number[10];

    int l = 0;
    if (n < 0)
    {
        l++;
        number[0] = '-';
        n *= -1;
    }
    int nCopy = n;

    while (nCopy > 9)
    {
        nCopy /= 10;
        l++;
    }

    int r;
    while (n > 9)
    {
        r = n % 10;
        n /= 10;
        number[l--] = r + '0';
    }
    number[l] = n + '0';

    printf("%s\n", number);
}

【问题讨论】:

  • 在 C 中,字符串必须以值 0 的字符结尾。你没有这样做。所以printf 一直运行,直到在你不打算打印的随机内存中找到一个零。
  • "或多或少被破坏" 不,因为你不是 null 终止字符串,你会打印超出你想要的,行为不是由任何标准定义的。您需要为number 分配更多字节。对于 10 位数字,您需要 11 个字节,否则您会遇到更多未定义的行为。
  • 我在数组的最后一个位置使用 '\0' 字符重新运行了代码,但仍然得到相同的结果。为什么当函数结束时数组仍然会记住以前的数据?
  • 可能是因为number 的存储在堆栈上,因为它是函数的局部变量,如果没有执行其他任何操作,并且您从同一个函数再次调用该函数,那么您' 可能在同一位置的堆栈上具有与以前相同的字节。关键是您没有初始化number 的字节,并且没有(最初)以空值终止您的字符串。
  • @Wyck 是的,我相信你是对的。我刚刚尝试再次运行它,但这次在函数调用之间插入随机代码,现在数组中填充了随机数据。

标签: arrays c


【解决方案1】:

数组不应该记住旧数据

对于每个程序,C 标准:

  • 指定程序应该做什么
  • 说没有指定程序应该做什么

它几乎从来没有说过程序应该做一些特别的事情。

在这种情况下,标准规定没有指定函数开头的数组中应包含哪些字符。它们可以是任何东西。上一次调用中的字符是“任何东西”的一种特殊情况。

【讨论】:

  • 而且修复起来很简单,只需初始化数组:char number[10] = {0};
【解决方案2】:

这是未定义的行为。如果只设置了前 3 个字符,则可能打印 312222222 或可能打印 312???????????????????

char number[10] 中的最后一个字符未初始化,这意味着编译器可能决定不理会它而保留旧值,或者发生其他情况。

否则printf 不知道字符串在哪里结束,它会一直打印直到随机命中零。

如果存在缓冲区溢出,printf 在内存中找到一组不同的字符(我们不应该访问它们)并且程序会继续打印这些相同的字符,直到它随机命中零并最终停止。

要修复它,只需确保末尾有'\0'。您还可以添加额外的检查以确保长度不超过缓冲区大小

工作示例:

char number[10];
int l = 0;
if (n < 0)
{
    l++;
    number[0] = '-';
    n *= -1;
}
if (n < 0) return;

int nCopy = n;
while (nCopy > 9)
{
    nCopy /= 10;
    l++;
}

int len = l;
if (len + 1 > sizeof(number))
    return;
number[len + 1] = '\0';

int r;
while (n > 9)
{
    r = n % 10;
    n /= 10;
    number[l--] = r + '0';
}
number[l] = n + '0';

printf("%s\n", number);

【讨论】:

  • 你是对的,我确实忘记在末尾添加 '\0' 字符,但我更困惑的是,下次调用函数时数组会记住所有 2 .据我了解,下次调用该函数时,数组不应该记住那里的旧数据。
  • 在这种特殊的简单情况下,使用您的特定编译器和设置,只是碰巧保留了这些值,但并非总是如此。您应该假设该数组不会被记住。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 2010-09-25
  • 2022-11-17
  • 2020-12-18
  • 1970-01-01
  • 2012-05-27
  • 1970-01-01
相关资源
最近更新 更多