我是C ++的初学者,试图通过编写尽可能多的各种小程序(程序)来了解我遇到的每个新概念。 所以我刚刚编造了下面这段代码:
#include <iostream>
using namespace std;
int main(){
int inumbers[] = {1 ,2 , 3, 4, 5};
int *p;
int i;
p = inumbers;
for(i = 0; p[i]; i++) cout << p[i] << '\n';
return 0;
}
我无法理解一个看似简单的事情:编译器如何知道&#34;何时停止增加循环变量&#34; i&#34;?令人惊讶的是,代码确实按照预期的方式工作。
答案 0 :(得分:10)
编译器不知道何时停止。
for(i = 0; p[i]; i++)
仅在p[i]
为0
时停止。你很幸运,p[5]
碰巧是0
。没有什么可以说它必须如此,它可以像this example一样继续前进。只要您i >= array size
访问内存,阵列就不会拥有,您进入undefined behavior的世界。
此外,如果数组中有0
,例如
int inumbers[] = {1 ,2 , 0, 4, 5};
然后程序将只打印
1
2
它不会访问阵列的其余部分。
在处理数组或标准容器时,您可以使用ranged based for loop之类的
for (const auto & e : inumbers)
std::cout << e << '\n';
迭代它的内容。然后在这种情况下并不真正需要const &
,因为我们正在处理一个int,但是通过引用传递避免复制并使它const
阻止你意外地修改元素是一个好习惯在进行只读操作时。
处理指针时,需要提供类似
的大小for (int i = 0; i < size_of_pointed_to_array, i++)
std::cout << p[i] << '\n';
答案 1 :(得分:3)
你很幸运。通过随机机会,似乎在inumbers
数组中的最后一个元素之后内存中存在零。
您的程序实际上并不正确。相反,您可能希望通过计算数组成员来限制循环:
for(i = 0; i < sizeof(inumbers)/sizeof(int); i++) cout << p[i] << '\n';
答案 2 :(得分:2)
程序的行为未定义。根据您编写程序的方式,循环应该在p[i]
求值为false时终止,在这种情况下应该表示p[i] == 0
。
显然,你的数组中没有0
,因此程序会将指针从数组的边界中取出,并取消引用4个连续的内存字节,并将这4个字节解释为整数,直到找到{{ 1}}。在你的情况下,你很幸运,在记忆中存在这样的0
。
如果没有0
,程序最终会遇到分段错误。
一个有趣的实验是在0
退出循环后打印它的值。
答案 3 :(得分:2)
上述代码依赖于未定义的行为。
特别是,它读取数组的末尾。碰巧,int大小的四字节为零(在您的特定构建和硬件中)。这会导致循环结束(for
循环的中间子句读取while p[i] is non-zero
)。
当存在未定义的行为时,C ++语言不会约束运行时的行为。 &#34;工作&#34;是一种有效的行为,就像格式化硬盘一样。
答案 4 :(得分:1)
您正在迭代数组的最后一个成员并且超出范围。你很幸运,因为其中 i 为5的p [i]正在评估为false或0.例如,将数组中的第二个值更改为0并检查循环何时停止。