2015-07-13 2 views
1

Я решал проблему, связанную с приращением счетчика и его отображением. Способ, которым я инициализировал и увеличил переменную, выглядел довольно нормально. См счетчик переменнойС ++ программа, скомпилированная в windows, производит разные выходные данные

#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 

Но когда я попытался скомпилировать и запустить его через http://www.tutorialspoint.com/compile_cpp_online.php, который использует Linux, она производила правильные результаты. Программа также была принята онлайн-судьей.

Case 1: Hajj-e-Akbar 
Case 2: Hajj-e-Asghar 
Case 3: Hajj-e-Akbar 
Case 4: Hajj-e-Asghar 

Любой может указать на тайну за этим? Почему скомпилированный код Windows создает странные результаты? Большое спасибо!

+6

Как долго строки вы читаете в массив 's'? Все, что превышает 4 символа (плюс терминатор NUL), переполнит массив и уничтожит следующую память, возможно, включая вашу переменную 'counter'. – Blastfurnace

ответ

7

Это переполнение буфера. Скорее всего, при компиляции на 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 является большой обратный порядок байт, который будет означать, что память вместо выкладывается так:

+----+----+----+----+----+----+----+----+----+ 
| ?? | ?? | ?? | ?? | ?? | 00 | 00 | 00 | 01 | 
+----+----+----+----+----+----+----+----+----+ 

Таким образом, даже если вы читаете в 5 символов, конечный нулевой ограничитель просто заменяет 0, который уже был там. Конечно, если это причина, то чтение в 6 персонажах действительно испортит ситуацию.

И как вы его исправите? Проблема в том, что для хранения строки длиной n массив символов должен иметь длину n+1. Таким образом, вы можете сделать это:

char s[6]; 

Или еще лучше, используйте строку:

std::string s; 

(Для этого вам нужно #include <string>.)

+1

Хорошее использование искусства ASCII. :-) –

Смежные вопросы