Читать не больше, чем размер строки с помощью scanf()

Изменить: для моего класса я должен использовать scanf. Поэтому рекомендовать другие способы ввода — это не то решение, которое я ищу (если есть такое, которое включает scanf).


Если я читаю пользовательский ввод для небольшого проекта (например, игры). Допустим, я спрашиваю would you like to play?. Это примет ответ yes или no. Итак, я пишу такой простой код:

#include <stdio.h>

int main(void)
{
     char string[3]; //The max number of letters for "yes".

     printf("Would you like to play?");
     scanf("%s", string);
}

Таким образом, этот код должен просто попросить их ввести yes или no. Я устанавливаю длину моего char array на размер 3. Таким образом, он достаточно большой, чтобы вместить yes, а также no. Но если кто-то введет недопустимый ввод, такой как yesss, я знаю, как впоследствии сравнить строку, чтобы обработать такое событие, но не будет ли это технически/возможно перезаписывать другие локальные переменные, которые я объявил, потому что они выходят за пределы длины моего множество? Если да, то есть ли способ справиться с этим, чтобы ограничить 3 входных символа или что-то в этом роде? А если нет, то почему/как он знает, что нужно вводить только размер 3?


person MrHappyAsthma    schedule 06.09.2012    source источник
comment
Вероятно, безопаснее делать это посимвольно. Я точно не уверен, есть ли в C что-нибудь, что делает это для вас.   -  person chris    schedule 06.09.2012
comment
Не могли бы вы объяснить, как это сделать? Могу ли я просто сделать кучу вещей %c в scanf, а затем как бы я присвоил их символу массива? [т.е. мне понадобится &string[0] или что-то в этом роде]. Кроме того, если они введут нет, я бы использовал только 2 из 3 %c.   -  person MrHappyAsthma    schedule 06.09.2012
comment
Выполнение этого самостоятельно для обработки любой длины влечет за собой массив, который может изменять размер во время выполнения и вставлять символы из ввода по мере их поступления, стараясь не переполнять массив. К счастью, кажется, что scanf имеет встроенную функцию.   -  person chris    schedule 06.09.2012


Ответы (4)


Ваш массив должен содержать четыре char, так как он также должен содержать 0-терминатор. С этим фиксированным указанием максимальной длины в формате,

scanf("%3s", string);

гарантирует, что scanf читает не более 3 символов.

person Daniel Fischer    schedule 06.09.2012
comment
Кроме того, поскольку спецификатор ширины указывает только максимальное количество символов для чтения, если вам нужно прочитать точное число, используйте описанный выше подход, а затем проверьте число потребляемых символов (через %n). - person sevko; 10.07.2015
comment
Я просто хочу знать, что это очень хорошая вещь, тогда почему люди продолжают говорить, что scanf небезопасен, очевидно, они могли бы сделать это, чтобы ограничить ввод и остановить эксплойт переполнения буфера. ?? - person Suraj Jain; 11.04.2017
comment
гарантирует, что scanf читает не более 3 символов. --> Не совсем. "%3s" сначала прочитает неограниченное количество начальных пробельных символов. Затем он прочитает и сохранит до 3 символов, отличных от пробелов. Наконец, добавление нулевого символа. - person chux - Reinstate Monica; 24.09.2018
comment
@SurajJain Люди обычно рекомендуют не использовать scanf не потому, что его нельзя безопасно использовать, а потому, что его сложно использовать. Когда люди впервые изучают C, им будет лучше научиться анализировать входные строки, чем тратить время на изучение слабостей языка формата scanf. scanf редко используется в производственном коде; в подавляющем большинстве мест это может быть уместно, C в любом случае неправильный язык. - person William Pursell; 05.05.2019

самый безопасный способ - использовать

fgets(string, 4, stdin);

здесь вы можете сохранить максимум 3 символа, включая одно место, зарезервированное для символа NULL ('\0').

person Timothy Malche    schedule 16.10.2012
comment
Точно! Лучший (и самый инновационный) способ, tbh! Спасибо - person Mrigank Pawagi; 08.06.2018
comment
Обычно последним из 3 максимальных читаемых символов является '\n'. - person chux - Reinstate Monica; 24.09.2018

Вы должны использовать модификатор width для scanf() и установить его быть на единицу меньше размера вашей строки, чтобы убедиться, что есть место для разделителя NULL.

Итак, если вы хотите сохранить «да», вам сначала понадобится массив большего размера, чем тот, который у вас есть; один размером 4, 3 символа плюс 1 для нулевого терминатора. Кроме того, вы должны указать scanf() читать не более size - 1 символов, где size — это длина вашего массива, то есть в данном случае 3, например:

#include <stdio.h>

int main(void)
{
     char string[4];
     scanf("%3s", string);
}
person gsamaras    schedule 20.06.2017
comment
Это будет сканировать цифру 3... вместо этого используйте "%3s" - person Jonathan Lidbeck; 28.02.2018
comment
Я даже не знаю, о чем я тогда думал... Спасибо, @JonathanLidbeck, исправлено! - person gsamaras; 04.03.2018