值超过C-Style字符串的有效指针

时间:2016-08-13 09:29:13

标签: c++ arrays pointers while-loop char

我目前正在通过" 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总是相同的角色?

3 个答案:

答案 0 :(得分:3)

C ++允许您通过ca[0]过去ca[4]指向*。您可以取消引用(即应用运算符ca[0])仅指向ca[4]ca[4]的指针;指向过去cp的指针是不受限制的。一旦取消引用指针就会发生什么未定义的行为。该程序可能会产生任何数据,甚至崩溃。

现实中发生的事情更简单:指针只是内存中的一个地址,因此取消引用它会继续为您的程序提供数字。在某些时候,地址包含一个零字节。这是你的程序停止的时候。

您的阵列已分配到自动内存中。大多数编译器都使用CPU堆栈。字节5..20的内容很可能包括countint,因为编译器倾向于将局部变量放在一起。中间可能存在一些填充,因为指针和if (elem.hasClass(animationClass))通常在可被4整除的地址上对齐。当然,您不能指望任何发生的事情,因为其他编译器会以不同的方式执行。

答案 1 :(得分:2)

因为对于语言而言,通过访问数组所发生的事情是不确定的,如果你想了解发生了什么,你就能理解你的“平台”是如何工作的。

对于大多数编译器,你的记忆可能是这样的:

|H|e|l|l|o|XXX|____cp___|__count__|

XXX是“填充字节”,必须与#8对齐。编译器 - 在调试版本中 - 通常使用0以外的固定值填充这些字节,只是为了使一个越界迭代不停止(这样你就可以发现它)

cp是指向“H”的指针,它逐个递增。它的值通常是流程本身的流程堆栈的地址映射。

这个地址通常有一个固定的前缀,一个偏移值随着嵌套调用的深入而增长。

由于指针(可能)长度为8个字节(最后四个字节位于第一个之前,因为x86处理器的低端),所以你得到的是一个打印的迭代:

  • 五个“Hello”字符
  • 三个填充字符(允许yare以某种方式打印)
  • 从堆栈开始的cp偏移量(总是相同,因为main始终与程序本身位于同一位置)
  • 部分进程前缀(每次调用时都会更改)

此前缀在某个点上可能包含“0”,从而终止循环。

请注意 - 无论这种解释是否有意义 - 您不能以任何方式信任它为不同平台编译生产代码,甚至可能由不同的编译器,因为他们管理变量的方式也可能不同。

答案 2 :(得分:1)

重要的是要知道您正在体验Undefined behavior。 所以无论你现在看到什么,当你使用不同的编译器或不同的编译器选项时,可能会有所不同。

5-11上'常量'值的最可解释的原因是你正在读取堆栈的一部分,它恰好每次都具有相同的值。