[英]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的內容很可能包括cp
和count
,因為編譯器傾向於將局部變量放在一起。 中間可能有一些填充,因為指針和int
通常在可被4整除的地址對齊。當然,你不能指望任何發生的事情,因為其他編譯器會以不同的方式做到這一點。
因為對於語言來說,通過訪問數組所發生的事情是不確定的,如果你想了解發生了什么,你就能理解你的“平台”是如何工作的。
對於大多數編譯器,你的記憶可能是這樣的:
|H|e|l|l|o|XXX|____cp___|__count__|
XXX是“填充字節”,必須與#8對齊。編譯器 - 在調試版本中 - 通常使用0以外的固定值填充這些字節,只是為了使一個越界迭代不停止(這樣你就可以發現它)
cp是指向“H”的指針,它逐一遞增。 它的值通常是進程本身的進程堆棧的地址映射。
這個地址通常有一個固定的前綴,以及一個隨着嵌套調用深入而增長的偏移值。
由於指針(可能)是8個字節長(最后四個字節放在第一個之前,因為x86處理器的低端),你得到的是一個打印的迭代:
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.