簡體   English   中英

值超過C-Style字符串的有效指針

[英]Values past valid pointer to C-Style string

我目前正在通過“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總是相同的角色?

C ++允許你通過一個過去的ca[4]來生成指向ca[0]指針。 但是,您可以取消引用(即應用operator * )指向ca[0]ca[4]指針; 指向過去ca[4]的指針是不受限制的。 取消引用指針后會發生什么是未定義的行為 該程序可能會產生任何數據,甚至崩潰。

現實中發生的事情更簡單:指針只是內存中的一個地址,因此取消引用它會繼續為您的程序提供數字。 在某些時候,地址包含一個零字節。 這是你的程序停止的時候。

您的陣列分配在自動內存中。 大多數編譯器都使用CPU堆棧。 字節5..20的內容很可能包括cpcount ,因為編譯器傾向於將局部變量放在一起。 中間可能有一些填充,因為指針和int通常在可被4整除的地址對齊。當然,你不能指望任何發生的事情,因為其他編譯器會以不同的方式做到這一點。

因為對於語言來說,通過訪問數組所發生的事情是不確定的,如果你想了解發生了什么,你就能理解你的“平台”是如何工作的。

對於大多數編譯器,你的記憶可能是這樣的:

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

XXX是“填充字節”,必須與#8對齊。編譯器 - 在調試版本中 - 通常使用0以外的固定值填充這些字節,只是為了使一個越界迭代不停止(這樣你就可以發現它)

cp是指向“H”的指針,它逐一遞增。 它的值通常是進程本身的進程堆棧的地址映射。

這個地址通常有一個固定的前綴,以及一個隨着嵌套調用深入而增長的偏移值。

由於指針(可能)是8個字節長(最后四個字節放在第一個之前,因為x86處理器的低端),你得到的是一個打印的迭代:

  • 五個“你好”字符
  • 三個填充字符(以某種方式允許yare打印)
  • 從堆棧開始的cp偏移量(總是相同的,因為main總是在程序本身的相同位置)
  • 進程前綴的一部分(每次調用時都會更改)

該前綴可以在某個點上包括“0”,從而終止循環。

請注意 - 無論這種解釋是否有意義 - 您無法以任何方式信任它為不同平台編譯生產代碼,甚至可能由不同的編譯器,因為他們管理變量的方式也可能不同。

重要的是要知道您正在經歷Undefined behavior 所以無論你現在看到什么,當你使用不同的編譯器或不同的編譯器選項時可能會有所不同。

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

對於初學者:

這:存儲一個包含\\0 null終止符的字符數組(可修改的字符串)

const char ca[] = "hello";

這不包括null終止符。 它從初始化列表初始化數組

const char ca[] = { 'h', 'e', 'l', 'l', 'o' };

以與您相同的方式工作:

const int ib[] = {2, 5, 7, 9};

這里有意義,因為編譯器不應該向您的數組添加額外的東西。


const char ca[] = { 'h', 'e', 'l', 'l', 'o' };
const char *cp = ca;
while (*cp){
    cout << *cp << endl;
    cp++;
}

好吧,你的代碼中有一個未定義的行為 ,因為你的數組將取消引用,因為數組中沒有\\0 null終止符。

是什么原因導致while循環失效?

那么在打印數組中的最后一個字符后會發生的事情是,程序會從未定義 (未知)的內存位置繼續讀取和打印,直到找到0並且循環退出為止。

為什么5-11總是相同的角色?

至於為什么它們看起來一樣:堆棧變量按編譯器的意願線性排列; 記憶也被填充 ; 再次, 內存被重用 ,因此你從東西的地址讀取,你沒有合法的業務。


腳注:您的程序可能會在int main()之前調用其他函數。 (這不是你的事,它所謂的)。 這些函數初始化靜態變量,包括std::cout東西

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM