get () и буфер в C - PullRequest
       33

get () и буфер в C

0 голосов
/ 17 марта 2020

Я знаю, что использование gets () - очень плохая идея, поскольку она может привести к переполнению буфера. Но у меня есть несколько запросов.

Предположим, что c программа имеет следующий код -

    char word[6];
    gets(word);
    puts(word);

Если я, например, введу - HELLO WORLD, правильно ли предположить, что gets() читает это как [H] [E] [L] [L] [O] [ ], а остальное идет в буфер ввода?

Если это произойдет, тогда как puts() получит данные для отображения полной строки?

Ответы [ 5 ]

4 голосов
/ 17 марта 2020

Ваш вопрос говорит о том, что вы думаете, gets может как-то знать, что word имеет длину всего 6 символов, поэтому он заполняет его всего 6 символами и оставляет остаток в буфере, связанном с входным потоком. Это не относится к делу. Вызов gets(word) передает только начальный адрес от word до gets. Это все, что он получает - стартовое место. Он не получает никакой информации о длине. gets читает из входного потока до тех пор, пока не будет прочитан символ новой строки или не будет обнаружен конец файла или произойдет ошибка.

Если вы ввели «HELLO WORLD» и программа напечатала это, это потому, что gets прочитал данные и записал их в память, превысив границы word. Не происходит какой-либо необычной буферизации или взаимодействия - просто записывается поверх памяти, которая не была назначена для этой цели. Это могло что-то сломать в вашей программе. Но, похоже, вам повезло, что ошибка не сразу сломала вашу программу, и данные находились там до тех пор, пока puts не смог прочитать ее из памяти и записать на выход.

Однако вам никогда не следует ожидать такого поведения. Одна из причин, которая работала так, как она работала, это то, что у вас есть очень простая программа, которая больше ничего не делала с памятью. В более сложных программах, где есть много объектов и действий, более вероятно, что переполнение буфера нарушит работу программы различными способами.

3 голосов
/ 17 марта 2020

Это точная проблема с gets; не остановится , когда прочитает 6 символов, продолжит чтение до тех пор, пока не увидит символ новой строки и не назначит эти символы в память сразу после конца буфера word. Это то, что переполнение буфера равно . Если нет ничего важного для нескольких байтов после буфера word (например, адрес возврата для стекового фрейма или другой локальной переменной), то перезапись этой памяти не вызывает очевидного проблем, и puts будет делать почти то же самое - читать из word и из памяти, следующей за ним , до тех пор, пока он не увидит терминатор строки.

3 голосов
/ 17 марта 2020

Правильно ли предположить, что gets () читает его как [H] [E] [L] [L] [O] [], а остальное идет во входной буфер?

Нет. неопределенное поведение - попытка переполнить буфер word[]. Все может случиться. Остальной код не имеет значения. При этом ничего не указывается в содержимом буфера.

2 голосов
/ 17 марта 2020

Функция gets читает всю строку за раз. Таким образом, в вашем примере он попытается прочитать «HELLO WORLD», который составляет 11 символов, в буфер, шириной всего 6 символов. Это переполняет буфер, вызывая неопределенное поведение .

И поскольку gets не может ограничить количество символов, которые он может читать, это делает его опасным, поэтому он был удален из C11 стандарт.

2 голосов
/ 17 марта 2020

Нет, неправильно полагать, что он просто останавливается, когда ему не хватает места; он не знает, сколько места доступно. gets просто продолжает чтение символов и запись в соседнюю память, вызывая неопределенное поведение. Вам может повезти, и эта соседняя память не используется (до или после gets), а puts «просто работает». Или это может перезаписать ваш указатель стека, и все взрывается. Или он может записать буфер правильно, но биты буфера перезаписываются до того, как туда попадет puts. Или что-нибудь еще; это неопределенное поведение.

Не делай этого. Никогда не используйте gets.

...