【问题标题】:Converting int to string still works even when causing buffer overflow即使导致缓冲区溢出,将 int 转换为字符串仍然有效
【发布时间】:2020-04-16 17:31:20
【问题描述】:

我正在尝试使用以下代码将 int 转换为 C 字符串:

static char* copyString(const char* str)  
{
    char* new_String = malloc(strlen(str) + 1);
    return strcpy(new_String, str);
}
static char* mallocIntToString(const int num)
{
    char s[10]; // *************
    sprintf(s, "%d", num);
    char* copy = copyString(s);

    return copy;
}

我在徘徊我应该在行中插入的最大数字是多少 char s[10];.

我使用 10 是因为它是整数的最大位数。但是,当我使用char s[9];,尝试将数字 2147483647 转换为字符串时,此代码也适用于我,这怎么可能?

【问题讨论】:

  • 看看<limits.h>。例如,INT_MININT_MAX 可以分别定义为 -2147483648+2147483647
  • 两者都是错误的,代码恰好可以工作。一个 10 位数字需要 11 个字符,因为必须有空间用于终止 '\0'。即使这样,您也会遇到 -2147483648 的麻烦,您需要一个额外的字符来作为符号。
  • 未定义行为未定义。任何事情都可能发生,包括今天“工作”和下周休息。
  • 仅供参考:已经有 strdup 完全按照您的 copyString 函数正在执行的操作(并进行了适当的错误检查)。
  • 为什么还要复制结果字符串呢?只需在堆上分配一个适当大小的缓冲区并使用sprintf() 将结果写入其中。

标签: c string int


【解决方案1】:

我在想应该在char s[10]; 行中插入的最大数字是多少。

您应该在INT_MAXINT_MIN 之间插入<limits.h> 中定义的最大长度。 INT_MIN 应该是 -2147483648,所以需要 11 + 1 = 12 个字符(另外一个是字符串终止符 \0)。

正确的实现应该是:

static char* mallocIntToString(const int num)
{
    char *s;

    s = malloc(12);
    if (s == NULL)
        return NULL;

    sprintf(s, "%d", num);    
    // Should probably also check for error here.

    return s;
}

但是,当我使用char s[9]; 时,这段代码也适用于我,试图将数字2147483647 转换为字符串,这怎么可能?

您正在调用未定义的行为,因为写到数组末尾之后是未定义的行为。这样做时,任何事情都可能发生。该程序不能保证正常工作,但纯属巧合,它仍然可以似乎工作。您的代码中发生的情况是,由于变量是在堆栈上定义的,并且堆栈是可写的,因此再写入一两个字节并没有太大变化,因为程序仍在写入有效内存。话虽如此,它仍然是未定义的行为,应该不惜一切代价避免!

为了 100% 清楚,即使使用 char s[10];char s[11];,您也会调用未定义的行为,因为在 INT_MIN 的情况下,终止符将被写入数组边界之外。

【讨论】:

  • 嘿,Marco,谢谢你非常详细的回答,你说得很清楚:)
  • @NivBehar 不客气。如果我回答了您的问题,您可以使用左侧的复选标记按钮接受我的回答,以便将您的帖子标记为已解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 2013-08-31
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
相关资源
最近更新 更多