[英]Where C++ really stores a string if the char array that stores it is smaller than a string is?
我正在從“C ++ Premiere”一書中測試一個關於C ++中字符串的例子。
const int size = 9;
char name1[size];
char name2[size] = "C++owboy"; // 8 characters here
cout << "Howdy! I'm " << name2 << "! What's your name?" << endl;
cin >> name1; // I input "Qwertyuiop" - 11 chars. It is more than the size of name1 array;
// now I do cout
cout << "Well, your name has " << strlen(name1) << " letters"; // "Your name has 11 letters".
cout << " and is stored in an array of " << size(name1) << " bytes"; // ...stored in an array of 9 bytes.
怎樣才能將11個字符存儲在一個數組中,僅用於8個字符+'\\ 0'char? 它在編譯時變寬了嗎? 或者字符串存儲在其他地方?
另外,我做不到:
const int size = 9;
char name2[size] = "C++owboy_12345"; // assign 14 characters to 9 chars array
但是可以做我上面寫的:
cin >> name1; // any length string into an array of smaller size
這里的訣竅是什么? 我使用NetBeans和Cygwin g ++編譯器。
將更多條目寫入數組而不是數組大小允許調用未定義的行為 。 計算機可能會將數據存儲在任何位置,或者根本不存儲它。
通常,數據存儲在內存中接下來發生的任何事情中。 這可能是另一個變量,指令流,甚至是椅子下方炸彈的控制寄存器。
簡單地說:你已編寫了一個緩沖區溢出錯誤。 不要那樣做。
在一個特殊情況下,這種行為使我的銀行余額從10美元增加到18億美元: http : //ideone.com/35FQW
你能明白為什么那個程序可能會這樣嗎?
name1在內存中被賦予一個地址。 如果你寫80個字節,它將從該位置開始在內存中寫入超過80個字節。 如果存在一個存儲在name1的地址+20的變量,那么它將通過向name1寫入80個字節來覆蓋其數據。 這就是C / C ++中的工作方式,這些被稱為緩沖區溢出,可用於破解程序。
這里沒有技巧:)你在緩沖區之外的內存寫,這是一個未定義的bahaviour
這是典型的緩沖區溢出。 這就是為什么你總是應該檢查輸入的大小,如果你把它放在緩沖區。 這是發生了什么:
在C ++(和C)中,數組名稱只是指向數組第一個元素的指針。 編譯器知道數組的大小,並將進行一些編譯時檢查。 但是,在運行時,它只會將其視為char *。
當您執行cin >> name1
,您將char *傳遞給cin
。 cin
不知道分配的空間有多大 - 它只是一個指向某個內存的指針。 因此,它假設您分配了足夠的空間,寫入所有內容,並超過了數組的末尾。 這是一張圖片:
Bytes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Before |-----name1 array-------| |--- other data-|
After Q w e r t y u i o p \0 |-er data-|
如您所見,您已覆蓋在陣列之后存儲的其他數據。 有時這個其他數據只是垃圾,但有時它很重要,可能意味着一個棘手的錯誤。 更不用說,這是一個安全漏洞,因為攻擊者可以用用戶輸入覆蓋程序內存。
關於大小的混淆是因為strlen
會計算字節,直到找到'\\0'
(空終止符),這意味着它找到10個字符。 另一方面, size(name1)
使用編譯器提供的數組的實際大小。
由於這些問題,每當您看到一個以數組作為參數的C函數時,它也會占用數組大小。 否則無法分辨出它有多大。 為了避免這些問題,使用像std :: string這樣的C ++對象要好得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.