元素数量超过 c 中数组中声明的大小
number of elements exceed the size declared in array in c
int main(void)
{
int b[5] = {1,2,3,4,5,6,7,8,9,10};
int i;
for(i=0;i<9;i++)
{
printf(" %d ",b[i]);
}
printf("\n address : %u",b);
return 0;
}
这是一个 C 程序,其中的元素数量超过声明的大小。当我遍历数组时,它会打印以下输出-
1 2 3 4 5 5 6422284 3854336 6422352
address : 6422288
编译器-gcc
没看懂
- 为什么 5 被打印了两次
- 为什么只打印了 9 个值而不是 10 个
因为程序的行为没有定义,所以它会做什么。您对“5 不应打印两次”的期望与任何其他期望一样都是推测性的。为什么你认为 5 不 被打印两次?!
因为程序的行为没有定义。因此,您对循环行为的期望只是空想。
如果您进行发布(优化)构建,您会看到更多有趣的事情发生。如果 CPU 的 IP 被损坏或发送到“蓝色”,它可能什么都不做,或者崩溃,或者做同样的事情,或者突然做其他事情。
顺便说一下,您的原始程序也可以:)
C 语言规范包含以下约束 (C17 6.7.9/2):
No initializer shall attempt to provide a value for an object not
contained within the entity being initialized.
你的初始化 b
...
int b[5] = {1,2,3,4,5,6,7,8,9,10};
... 在 b
只有五个元素(均为标量)时,在 b
的初始化列表中包含十个值,从而违反了该约束。符合规范的编译器有义务对此进行诊断,如果 gcc
默认情况下不这样做,那么可能可以通过包含 -pedantic
标志来做到这一点。一般来说,对于 gcc
,您应该同时使用 -Wall
和 -pedantic
,至少在您了解足够多以做出自己的明智决定之前。
从技术上讲,您的程序的行为因此是未定义的,但这可能不是实践中的主要问题。我希望 gcc
只是忽略多余的初始化值。主要问题是,无论您提供了多少初始化元素,您已经指定 b
恰好有 5 个元素,但您试图访问索引高于 4 的元素。这些是越界数组访问及其行为未定义。您没有正当理由期待这些结果的任何特定结果,或者根本不会打印任何内容。
事实上,整个程序因此具有未定义的行为,因此假设一个程序执行除了异常之外的所有相同的事情是不安全的边界访问会产生错误程序输出的一个子集。
关于您的具体问题:
- why 5 is printed twice
语言规范没说。尝试打印 b[5]
的结果未定义。
- why only 9 values are printed instead of 10
可能是因为迭代界限,i=0;i<9;i++
。有了这些,如果程序在其他方面符合语言规范,人们会期望循环体被执行九次(特别是,当 i
的值为 9 时)。
另请注意,这...
printf("\n address : %u",b);
...是错误的。用于打印指针的 printf
指令是 %p
,从技术上讲,它要求参数是指向 void
的指针(例如,不是指向 int
的指针) .这是完全正确的:
printf("\n address : %p", (void *) b);
附录
如果你想要一个恰好有十个元素的数组,那么声明它:
int b[10] /* initializer optional */;
如果您想要一个根据其初始值设定项中的元素数量选择大小的对象,则省略显式大小:
int b[] = {1,2,3,4,5,6,7,8,9,10}; /* declares a 10-element array */
int main(void)
{
int b[5] = {1,2,3,4,5,6,7,8,9,10};
int i;
for(i=0;i<9;i++)
{
printf(" %d ",b[i]);
}
printf("\n address : %u",b);
return 0;
}
这是一个 C 程序,其中的元素数量超过声明的大小。当我遍历数组时,它会打印以下输出-
1 2 3 4 5 5 6422284 3854336 6422352
address : 6422288
编译器-gcc
没看懂
- 为什么 5 被打印了两次
- 为什么只打印了 9 个值而不是 10 个
因为程序的行为没有定义,所以它会做什么。您对“5 不应打印两次”的期望与任何其他期望一样都是推测性的。为什么你认为 5 不 被打印两次?!
因为程序的行为没有定义。因此,您对循环行为的期望只是空想。
如果您进行发布(优化)构建,您会看到更多有趣的事情发生。如果 CPU 的 IP 被损坏或发送到“蓝色”,它可能什么都不做,或者崩溃,或者做同样的事情,或者突然做其他事情。
顺便说一下,您的原始程序也可以:)
C 语言规范包含以下约束 (C17 6.7.9/2):
No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
你的初始化 b
...
int b[5] = {1,2,3,4,5,6,7,8,9,10};
... 在 b
只有五个元素(均为标量)时,在 b
的初始化列表中包含十个值,从而违反了该约束。符合规范的编译器有义务对此进行诊断,如果 gcc
默认情况下不这样做,那么可能可以通过包含 -pedantic
标志来做到这一点。一般来说,对于 gcc
,您应该同时使用 -Wall
和 -pedantic
,至少在您了解足够多以做出自己的明智决定之前。
从技术上讲,您的程序的行为因此是未定义的,但这可能不是实践中的主要问题。我希望 gcc
只是忽略多余的初始化值。主要问题是,无论您提供了多少初始化元素,您已经指定 b
恰好有 5 个元素,但您试图访问索引高于 4 的元素。这些是越界数组访问及其行为未定义。您没有正当理由期待这些结果的任何特定结果,或者根本不会打印任何内容。
事实上,整个程序因此具有未定义的行为,因此假设一个程序执行除了异常之外的所有相同的事情是不安全的边界访问会产生错误程序输出的一个子集。
关于您的具体问题:
- why 5 is printed twice
语言规范没说。尝试打印 b[5]
的结果未定义。
- why only 9 values are printed instead of 10
可能是因为迭代界限,i=0;i<9;i++
。有了这些,如果程序在其他方面符合语言规范,人们会期望循环体被执行九次(特别是,当 i
的值为 9 时)。
另请注意,这...
printf("\n address : %u",b);
...是错误的。用于打印指针的 printf
指令是 %p
,从技术上讲,它要求参数是指向 void
的指针(例如,不是指向 int
的指针) .这是完全正确的:
printf("\n address : %p", (void *) b);
附录
如果你想要一个恰好有十个元素的数组,那么声明它:
int b[10] /* initializer optional */;
如果您想要一个根据其初始值设定项中的元素数量选择大小的对象,则省略显式大小:
int b[] = {1,2,3,4,5,6,7,8,9,10}; /* declares a 10-element array */