Как предотвратить переполнение буфера, когда мы рекурсивно запрашиваем ввод, если ввод недействителен

Необходимо взять входную строку размером 5. Также необходимо проверить достоверность в каком-то несвязанном смысле. Если ввод недействителен, пользователю будет предложено ввести его еще раз.

Используя scanf("%4s", input); Но если пользовательский ввод предполагает строку из 8 символов, scanf просто сканирует последние 4 символа, все еще находящиеся в буфере, прежде чем запрашивать фактический пользовательский ввод.

Я попытался создать буферную переменную, в которой будут храниться входные данные перед передачей их целевой переменной.

Не используйте рекурсию, используйте цикл.

NathanOliver 31.08.2024 05:05

Среди других соответствующих вопросов см. scanf() оставляет символ новой строки в буфере.

Jonathan Leffler 31.08.2024 07:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Просто: всегда получайте от пользователя полную строку текста (используя fgets()).

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

Это связано с простым принципом:

⟶ Пользователь всегда нажимает Enter в конце каждого запрошенного ввода ⟵

Как только будет получена полная строка текста, попытайтесь преобразовать ее в int или что-то еще.

«Пользователь всегда нажимает Enter в конце каждого запрошенного ввода» -> это, безусловно, распространенное явление. Другие возможности: 1) Вход закрыт - финала нет '\n'. например ввод был "abc", а затем был сигнализирован конец файла без '\n'. 2) Редко: при вводе имеется ошибка ввода.

chux - Reinstate Monica 31.08.2024 06:04

И то, и другое можно считать ненормальной реакцией (и, следовательно, ошибочной) на такие вещи, как «What is your age? ». Если TTY задает вам вопрос, он всегда должен ввести ответ, а затем нажать Enter, чтобы подтвердить его. Также следует ожидать, что конвейерные процессы или файлы, притворяющиеся людьми в этом контексте, будут отвечать как человек; файл, заканчивающийся без новой строки, здесь считается ошибкой.

Dúthomhas 31.08.2024 06:12

Я мог видеть, как идти этим путем. Тем не менее, по моему опыту, я обнаружил, что терпимость к вводу, заканчивающемуся концом файла (и отсутствие обязательного '\n'), делает программное обеспечение более полезным и требует меньше обслуживания. Ваш звонок.

chux - Reinstate Monica 31.08.2024 06:18
Ответ принят как подходящий

Как предотвратить переполнение буфера, когда мы рекурсивно запрашиваем ввод, если ввод недействителен?

  1. При поиске ввода до n символов (что составляет n + 1 символов, если считать Enter или '\n'), прочитайте хотя бы строку, содержащую не менее n + 1 символов. При использовании fgets() это должно поместиться в буфер размером n + 2. Дополнительная единица предназначена для хранения добавленного нулевого символа.
#define STRING_LENGTH_MAX 5

char buf[STRING_LENGTH_MAX + 2];
for (;;) {
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    // There is no more input from stdin.
    // TBD code - perhaps quit?
  }
  ...
  1. Найдите строку, сохраненную для '\n'. Если нашли, отрежьте его и продолжайте. Если он не найден и строка длинная, прочитайте оставшуюся часть строки. Отбросить все и вернуться (не рекурсивно) к шагу 1.
  buf[strcspn(buf, "\n")] == '\0'; // Lop off a potential '\n'.
  if (strlen(buf) <= STRING_LENGTH_MAX) {
    // Perform other validation tests on `buf`.
    // Otherwise ...
    break;
  }
  // Read and toss rest of line.
  int ch;
  while ((ch = getchar()) != '\n' && ch != EOF) {
    ;
  }
}
  1. Подумайте о том, чтобы поместить все это во вспомогательную функцию.

Определите буфер гораздо большей длины, например #define STRING_MAX_LENGTH 2048. Затем обработайте введенные строки слишком большой (или недостаточной) длины. Высоки шансы, что таким образом вам не удастся получить частичную линию.

Jonathan Leffler 31.08.2024 07:38

@JonathanLeffler Да, больший буфер снижает вероятность необходимости очистки while ((ch = getchar()) != '\n' && ch != EOF), но не устраняет ее. Как правило, когда буфер n является ожидаемым максимальным, я кодирую 2*n.

chux - Reinstate Monica 31.08.2024 16:25

Другие вопросы по теме