繁体   English   中英

为什么溢出数组初始化会发出警告但溢出的赋值不会?

[英]Why does overflowing array initialization give warning but overflowing assignment does not?

为什么int a[5] = {1,2,3,4,5,6}int a[5] = {1,2,3,4,5}; a[5] = 6;发出警告int a[5] = {1,2,3,4,5}; a[5] = 6; int a[5] = {1,2,3,4,5}; a[5] = 6; 才不是?

当我最初声明数组大小为5时,这样做是否是一个好习惯?

如果我不知道阵列的大小怎么办? 我可以像这样在int a[]声明它吗?

为什么int a [5] = {1,2,3,4,5,6}在int [5] = {1,2,3,4,5}时发出警告; a [5] = 6; 才不是?

赋值会给出一个警告,因为您知道初始化语句中变量的大小,并且它显然违反了声明的大小。 你不必数组的大小从a在该行a[6] = 6 ,所以编译器似乎确定。 当然,警告的级别从编译器变为编译器,对于某些编译器,您可以指定额外的警告。

例如,使用gcc,您可以使用标志-Wextra-Wall来获取大量警告。 接收警告是一件好事,因为编译器可以帮助您找到可能的警告而无需调试代码。 当然,如果你解决它们,它们只会很好:-)

当我最初声明数组大小为5时,这样做是否是一个好习惯?

将一个整数分配给你未声明的内存中的位置绝对不是一个好习惯 - 你无法确定这个值的写入位置,它可以覆盖另一个变量,或者更糟糕的是,部分覆盖其他变量变量或堆栈。 由于这种东西在编译器和编译器之间是不同的,正如@PascalCuoq指出的那样,它被称为未定义的行为 ,并且是你想要不惜一切代价避免的东西。 当然,因为它是未定义的,所以你的程序可能会在这个声明之后执行得很好,但这是一个非常糟糕的做法。

但是,初始化具有固定大小的数组没有任何问题,如果它不会改变的话。 您应该避免使用幻数并使用常量,例如MAX_NUMBER_OF_PERMUTATIONSCURRENCIES_SIZE

我可以这样声明:int a []?

在初始化固定数组时,将它声明为int a[]是一种简写,编译器可以指定元素的数量。 例如:

int a[] = {1,2,3}; //this is good
int b[3] = {1,2,3}; //same from above

在过去通常声明int a[]; 但它不适用于每个编译器,因此应该避免。 (感谢@PascalCuoq指出这一点)

如果我不知道阵列的大小怎么办?

如果您不知道数组的大小,则应将其声明为指针,如int * a并使用mallocrealloccalloc和类似的系统调用calloc管理内存。 请做好工作并free学习 - 世界将在以后感谢你。 如果您正在寻找动态内存分配,您应该阅读指针而不是数组。

为什么int a [5] = {1,2,3,4,5,6}在int [5] = {1,2,3,4,5}时发出警告; a [6] = 6; 才不是?

警告只是编译器试图帮助您。 每次做错事时,编译器都不必发出警告。 编写错误程序的方法太多了,编译器无法对所有程序发出警告。

当我最初声明数组大小为5时,这样做是否是一个好习惯?

不。当a是大小为5的数组时,访问a[6]a[5]调用未定义的行为(翻译:非常糟糕)。 关于未定义行为的传统说法是它允许编译器使守护进程从你的鼻子中飞出:

在1992年初对该组进行讨论时,常规评论“当编译器遇到[给定的未定义构造]时,让恶魔飞出你的鼻子是合法的”(这意味着编译器可能会选择任意奇怪的在不违反ANSI C标准的情况下解释代码的方法)。

因此,简而言之,始终要避免 C程序中未定义的行为。

如果我不知道阵列的大小怎么办? 我可以像这样在一个[]中声明它吗?

不,你不能。 在声明数组时,您必须知道数组的大小。 int a[]; 会声明一个不完整的数组,这不是你想要的( 这里是关于不完整类型的链接,但如果你问的是访问五元素数组的第六个元素,你只是不想听到不完整的类型)。 如果您不知道最终需要的大小,请了解malloc()realloc()

在第二个示例中,编译器正在执行指针数学运算以确定放置整数的位置。 在较旧的C实现中,数组不是第一类,因此没有可用的范围检查。 一些较新的可以检测到越界错误。

如果需要动态分配数组,这是正确的模式:

int *a;
// calloc( elements, size)
// create an array of 6 elements, 0..5
a = calloc(6, sizeof(int));
// use like a[5]=6, be sure to free(a) later. 

检查calloc免费参考。

问题:为什么

int a[5] = {1,2,3,4,5,6};

一边发出警告

 int a[5] = {1,2,3,4,5};
 a[5] = 6;

才不是?

这实际上是一个非常好的问题,我没有一个非常好的答案。

至于C语言标准所说的,初始化是一种约束违规 ,这意味着一致的编译器必须发出诊断,并且可能拒绝该程序。 (gcc使用-pedantic-errors选项,我建议使用)。

在第二种情况下, a[5] = 6; 未定义的行为 该语言不需要诊断,但它肯定允许一个,并且一个足够聪明的编译器可以警告它。 当编译器看到a[5]的赋值时,它知道(或者可能知道) a只有5个元素而你正试图访问第6个元素。 gcc,至少没有这样做,至少没有我尝试过的选项。

为什么标准要求对第一种情况进行诊断而不对第二种情况进行诊断? 因为始终可以在编译时检测到第一个错误。 编译器必须知道a有多大,因为声明正在创建它; 它必须为它分配内存。 在这样的声明中,大小总是在编译时知道。 (有可变长度的数组,但你不能使用那种初始化器。)

a[5] = 6; ,编译器必须执行更多分析来检测错误,分析并非总是可行。 你可以很容易地写出来:

a[n] = 6;

如果n碰巧是5 ,那就差一点 - 但是编译器必须在编译时确定n 在运行时将要诊断它的值。 编译器有时可以执行这种分析,但有些情况下理论上是不可能的。

那么为什么gcc不能诊断a[5] = 6;的特定情况a[5] = 6; 这可能只是gcc开发人员选择投入时间和其他资源的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM