我目前正在通过" C ++ Primer"。在一个练习题中,它问:
以下程序有什么作用?
const char ca[] = { 'h', 'e', 'l', 'l', 'o' };
const char *cp = ca;
while (*cp)
{
cout << *cp << endl;
cp++;
}
我很高兴我理解* cp将继续在ca []数组的最后一个字符后继续存在,因为数组中的最后一项没有空字符。
更多的是我自己的好奇心是什么让while循环变得虚假。它似乎总是在我的电脑上显示19个字符。 0-4是hello字符串,5-11总是相同,每次执行都会改变12-19。
#include <iostream>
using namespace std;
int main( )
{
const char ca[ ] = { 'h', 'e', 'l', 'l', 'o'/*, '\0'*/ };
const char *cp = ca;
int count = 0;
while ( *cp )
{
// {counter} {object-pointed-to} {number-equivalent}
cout << count << "\t" << *cp << "\t" << (int)*cp << endl;
count++;
cp++;
}
return 0;
}
问题:导致while循环失效的原因是什么?为什么5-11总是相同的角色?
答案 0 :(得分:3)
C ++允许您通过ca[0]
过去ca[4]
指向*
。您可以取消引用(即应用运算符ca[0]
)仅指向ca[4]
到ca[4]
的指针;指向过去cp
的指针是不受限制的。一旦取消引用指针就会发生什么未定义的行为。该程序可能会产生任何数据,甚至崩溃。
现实中发生的事情更简单:指针只是内存中的一个地址,因此取消引用它会继续为您的程序提供数字。在某些时候,地址包含一个零字节。这是你的程序停止的时候。
您的阵列已分配到自动内存中。大多数编译器都使用CPU堆栈。字节5..20的内容很可能包括count
和int
,因为编译器倾向于将局部变量放在一起。中间可能存在一些填充,因为指针和if (elem.hasClass(animationClass))
通常在可被4整除的地址上对齐。当然,您不能指望任何发生的事情,因为其他编译器会以不同的方式执行。
答案 1 :(得分:2)
因为对于语言而言,通过访问数组所发生的事情是不确定的,如果你想了解发生了什么,你就能理解你的“平台”是如何工作的。
对于大多数编译器,你的记忆可能是这样的:
|H|e|l|l|o|XXX|____cp___|__count__|
XXX是“填充字节”,必须与#8对齐。编译器 - 在调试版本中 - 通常使用0以外的固定值填充这些字节,只是为了使一个越界迭代不停止(这样你就可以发现它)
cp是指向“H”的指针,它逐个递增。它的值通常是流程本身的流程堆栈的地址映射。
这个地址通常有一个固定的前缀,一个偏移值随着嵌套调用的深入而增长。
由于指针(可能)长度为8个字节(最后四个字节位于第一个之前,因为x86处理器的低端),所以你得到的是一个打印的迭代:
cp
偏移量(总是相同,因为main始终与程序本身位于同一位置)此前缀在某个点上可能包含“0”,从而终止循环。
请注意 - 无论这种解释是否有意义 - 您不能以任何方式信任它为不同平台编译生产代码,甚至可能由不同的编译器,因为他们管理变量的方式也可能不同。
答案 2 :(得分:1)
重要的是要知道您正在体验Undefined behavior
。
所以无论你现在看到什么,当你使用不同的编译器或不同的编译器选项时,可能会有所不同。
5-11上'常量'值的最可解释的原因是你正在读取堆栈的一部分,它恰好每次都具有相同的值。