C通过for循环为长度为两个数组的数组赋值时的意外行为



我在编程时遇到了以下意外行为,我不明白为什么会发生这种情况,甚至不明白以下两种情况之间的区别。

考虑以下两个代码片段

#include <stdint.h>
#include <stdio.h>
typedef uint64_t* bitset;
int main(int argc, char ** argv) {
bitset list[2];
list[0] = (uint64_t[2]) {(uint64_t) 0LL, (uint64_t) 0LL};
list[1] = (uint64_t[2]) {(uint64_t) 0LL, (uint64_t) 0LL};
printf("%pn", &list[0][0]);
printf("%pn", &list[1][0]);
return 0;
}

#include <stdint.h>
#include <stdio.h>
typedef uint64_t* bitset;
int main(int argc, char ** argv) {
bitset list[2];
for(int i = 0; i < 2 ; i++) {
list[i] = (uint64_t[2]) {(uint64_t) 0LL, (uint64_t) 0LL};
}
printf("%pn", &list[0][0]);
printf("%pn", &list[1][0]);
return 0;
}

在第一个示例中,两个值都指向内存中的不同位置,但当通过for循环初始化list[0]和list[1]时。list[0][0]和list[1][0]都指向内存中的同一位置。

造成这种情况的原因是,为什么两种方法在执行上存在差异。我在Ubuntu机器上编译,这发生在gcc和clan上。

当您编写(uint64_t[2]){0, 0}时,该表达式被称为";复合文字";它创建的数组的范围是您定义它的块,所以在您离开块后,访问它是无效的。

第一个例子看起来不错,因为您只访问创建数组的块内的数组。第二个例子很糟糕(导致未定义的行为(,因为复合文字是在循环迭代中创建的,并且在创建后,当程序到达循环块的末尾时,几乎立即超出范围。

如果它能帮助你理解:我认为复合文字基本上只是没有名称的局部变量。局部变量在其块结束时超出范围。

您可以使用malloc或其他方法来分配内存,如果您希望它能持续更长时间的话。或者,不使用指针,只需将bitset本身定义为包含两个数字的struct。然后,数组将直接包含要存储的数据,而不是只包含指向存储在其他地方的数据的指针。

最新更新