[英]C++ program compiled in windows produces different output
我正在解決一個涉及增加計數器並顯示它的問題。 我初始化和遞增變量的方式似乎很正常。 請參閱計數器變量
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[5];
int counter = 1;
while (cin >> s && (strcmp(s, "*") != 0))
{
cout << "Case " << counter++ << ": Hajj-e-A";
if (s[0] == 'H')
{
cout << "kbar\n";
}
else if (s[0] == 'U')
{
cout << "sghar\n";
}
}
}
但是該程序神秘地顯示了錯誤的結果。 它沒有適當增加從1開始的值。 查看輸出。
Case 1: Hajj-e-Akbar
Case 0: Hajj-e-Asghar
Case 1: Hajj-e-Akbar
Case 0: Hajj-e-Asghar
但是,當我嘗試通過使用Linux的http://www.tutorialspoint.com/compile_cpp_online.php進行編譯和運行時,它產生了正確的結果。 該程序也被在線法官接受。
Case 1: Hajj-e-Akbar
Case 2: Hajj-e-Asghar
Case 3: Hajj-e-Akbar
Case 4: Hajj-e-Asghar
任何人都可以指出其背后的奧秘嗎? 為什么Windows編譯的代碼會產生奇怪的結果? 非常感謝!
這是緩沖區溢出。 最有可能的是,當您在Windows上進行編譯時, counter
變量將緊隨內存中的s[5]
變量,如下所示:
+----+----+----+----+----+----+----+----+----+
| ?? | ?? | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
\________ s[5] ________/ \____ counter ____/
由於Windows是低位優先的,因此它存儲為01 00 00 00
而不是您期望的00 00 00 01
。 ??
只是表明我們尚不知道那里是什么-可能是任何東西。
現在,假設您輸入“ Hardy”,然后按Enter。 在ASCII中,它轉換為字節序列48 61 72 64 79 0D 0A
(最后兩個是行尾,在UNIX上, 0D
將被省略)。 這是cin >> s
對內存的作用:
1. Read in 'H':
+----+----+----+----+----+----+----+----+----+
| 48 | ?? | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
2. Read in 'a':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
3. Read in 'r':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
4. Read in 'd':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
5. Read in 'y':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | 79 | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
6. Read in '\r\n' (or on UNIX, just '\n'), but this isn't put into the memory.
Instead, cin realizes that it has finished reading, and closes off the string with a '\0':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | 79 | 00 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
\________ s[5] ________/ \____ counter ____/
哎呀! 它覆蓋了櫃台!
為什么在Linux上可以正常使用? Linux不會在內存中將兩個變量相鄰放置,或者Linux系統是big-endian,這意味着內存的布局應如下所示:
+----+----+----+----+----+----+----+----+----+
| ?? | ?? | ?? | ?? | ?? | 00 | 00 | 00 | 01 |
+----+----+----+----+----+----+----+----+----+
因此,即使您讀了5個字符,最終的空終止符也只會替換已經存在的0。 當然,如果這是原因,那么用6個字符讀起來確實會使事情搞砸。
以及如何解決? 問題在於,要容納長度為n
的字符串,字符數組的長度必須為n+1
。 因此,您可以這樣做:
char s[6];
甚至更好,使用字符串:
std::string s;
(為此,您需要#include <string>
。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.