calloc(10,4) 和 calloc(1,40) 有什么区别?
我看到了这种行为:
Thing** things = (Thing**)calloc(1, 10 * sizeof(Thing*));
// things[0] != 0
Thing** things = (Thing**)calloc(10, sizeof(Thing*));
// things[0] == 0
我想知道为什么。编辑:失去理智的原因是,现在两者似乎都为零......为了至少让这个问题变得有趣,为什么 calloc 不像 malloc 那样只接受一个参数?
实际上是一样的。但是这为您提供了一项重要功能。
假设您正在从网络接收一些数据,并且协议(protocol)有一个字段指定一个数组将包含多少个元素,这些元素将被发送给您。你做这样的事情:
uint32_t n = read_number_of_array_elements_from_network(conn);
struct element *el = malloc(n * sizeof(*el));
if (el == NULL)
return -1;
read_array_elements_from_network(conn, el, n);
这看起来无害,不是吗?好吧,没那么快。连接的另一端是邪恶的,实际上向您发送了一个非常大的数字作为元素的数量,以便乘法环绕。假设 sizeof(*el)
是 4,n
读作 2^30+1
。乘法 2^30+1 * 4
换行,结果变为 4,这就是您在告诉函数读取 2^30+1 元素时分配的内容。 read_array_elements_from_network
函数将快速溢出您分配的数组。
calloc
的任何体面的实现都会检查该乘法是否溢出,并会防止这种攻击(这种错误很常见)。