我有以下代码。它接受从1到52的任何卡值。

char* formatCard( int card )
{
    char suit[4][4] = {"♠", "♥", "♣", "♦"};
    char number[13][6] = {"2", "3", "4", "5", "6", "7",
        "8", "9", "10", "Jack", "Queen", "King", "Ace"};

    char* s = malloc(1);
    sprintf(s, "%s of %s", number[card%13], suit[card/13]);
    return s;
}

代码工作良好,所有的,但当我动态分配C字符串char* s = malloc(1);它可以采取任何数量的内存,无论它是多么小,尽管事实上,C字符串可以达到最大的大小为10(12),如果你认为西装符号的大小为3…现在我想起来了,这是另一件我不明白的事,让我困惑。
有人能解释一下我觉得奇怪的事情吗?也许这只是在我的电脑/操作系统上发生的事情?我正在使用Ubuntu。

最佳答案

你的程序错了,你知道的。但是编译器不知道,所以程序仍然在运行。给什么?

char* s = malloc(1);
sprintf(s, "%s of %s", number[card%13], suit[card/13]);

这就调用了一种叫做“未定义行为”的东西。这意味着你的程序是错误的,它会做一些意想不到的事情。也许它会崩溃,也许它不会崩溃,也许它会写错答案,也许它会格式化你的硬盘。
在这种情况下,sprintf()可能是在您分配的缓冲区结束后写入,写入内存的其他部分。当这种情况发生时,有时内存将不会被映射,从而导致分段错误(崩溃)。有时内存会被用来做其他的事情,程序的其他部分也会表现不好。当损坏的内存被程序的其他部分使用时,程序可能会在稍后崩溃。
修复
您想改用snprintf()snprintf()函数接受第二个参数,即缓冲区的大小。snprintf()函数更安全,因为一旦到达缓冲区的末尾,它将停止写入数据。
size_t sz = 1;
char *s = malloc(sz);
snprintf(s, sz, "%s of %s", number[card % 13], suit[card / 13]);

如果您使用的是最近的Clang或GCC,也可以尝试使用地址消毒剂。

09-05 23:56