почему это происходит (см. изображение)? - PullRequest
6 голосов
/ 13 ноября 2008

Почему следующее дает такой эффект - он печатает терминал, полный случайных символов, а затем завершает работу, оставляя командную строку, которая выдает мусор при вводе. (Я попробовал это, потому что я думал, что это вызовет ошибку сегмента).

http://oi38.tinypic.com/r9qxbt.jpg

#include <stdio.h>

int main(){
    char* s = "lololololololol";
    while(1){
        printf("%c", *s);
        s++;
    }
}

было скомпилировано с:

gcc -std=c99 hello.c

Ответы [ 7 ]

20 голосов
/ 13 ноября 2008

Это в конечном итоге вызовет ошибку, но перед этим она распечатает все байты на той же странице. Вот почему вы видите случайные символы на экране.

Это может включать escape-последовательности для изменения (скажем) кодировки символов консоли. Вот почему вы получаете в итоге тарабарщину, когда печатаете на консоли и после ее выхода.

7 голосов
/ 13 ноября 2008

В дополнение к тому, что все остальные говорили о том, что вы игнорируете символ строкового терминала и просто невольно печатаете то, что находится в памяти после строки, причина, по которой ваша командная строка также является «мусором», заключается в том, что вы печатаете определенный « «непечатный» символ, ваша терминальная сессия была оставлена ​​в странном символьном режиме. (Я не знаю, какой это персонаж или какое изменение режима он делает, но, может быть, кто-то другой может рассказать об этом лучше, чем я.)

7 голосов
/ 13 ноября 2008

Поскольку у вас есть бесконечный цикл (while(1)), и вы продолжаете получать текущее значение указателя (*s), а затем перемещаете указатель на один символ вперед (s++). Это приводит к тому, что за конец строки проходит марш «мусора» (неинициализированная память), который в результате выводится на консоль.

7 голосов
/ 13 ноября 2008

Вы просто распечатываете то, что находится в памяти, потому что ваш цикл не останавливается в конце строки. Каждый случайный байт интерпретируется как символ. Это приведет к ошибке, когда вы достигнете конца страницы памяти (и попадете на нечитаемую территорию).

2 голосов
/ 13 ноября 2008

Немного расширив ответы, данные здесь (которые все превосходны) ... Я сам сталкивался с этим не раз, когда только начинал с C, и сделать легкую ошибку.

Быстрая настройка вашей петли while исправит это. Все остальные объяснили вам, почему, а я подскажу, как:

#include <stdio.h>

int main() {
    char *s = "lolololololololol";
    while (*s != '\0') {
        printf("%c", *s);
        s++;
    }
}

Обратите внимание, что вместо бесконечного цикла (while(1)), мы делаем проверку цикла, чтобы убедиться, что указатель, который мы вытащим, не является нулевым ограничителем для строки, таким образом, избегая переполнения встречая.

Если вы застряли, абсолютно нуждаясь в while(1) (например, если это домашняя работа, и инструктор хочет, чтобы вы ее использовали), используйте ключевое слово break, чтобы выйти из цикла. Следующий код пахнет, по крайней мере для меня, но это работает:

#include <stdio.h>

int main() {
    char *s = "lolololololololol";
    while (1) {
        if (*s == '\0')
            break;
        printf("%c", *s);
        s++;
    }
}

Оба выдают одинаковый вывод на консоль без разрыва строки в конце:

lolololololololol

1 голос
/ 19 ноября 2008

Ваш цикл не завершается, поэтому println печатает все, что находится в памяти, после текста, который вы пишете; в конечном итоге он получит доступ к памяти, которую ему запрещено читать, что приведет к его сбою.

Вы можете изменить цикл, как предложили другие, или воспользоваться тем, что в c ноль равен false, а null (который завершает все строки) также равен нулю, поэтому вы можете построить цикл следующим образом:

while (*s) {

Вместо:

while (*s != '\0')

Первый может быть более сложным для понимания, но он обладает преимуществом краткости, поэтому его часто используют для экономии текста.

0 голосов
/ 03 декабря 2008

Кроме того, вы обычно можете вернуться в командную строку, используя команду «reset», набрав, конечно, вслепую. (введите Enter, сброс, Enter)

...