2016-01-29 3 views
1

Все, что я пытаюсь сделать, это попросить пароль и распечатать сообщение об ошибке, если ввод длиннее 10 символов. Он работает, если первый вход короче 10 символов. Он просто распечатывает вход и выходит из программы. Если ввод длиннее 10 символов, сообщение об ошибке печатается, и он запрашивает новый пароль, но если на входе меньше 10 символов, во второй попытке он распечатывает вход, а затем программа прерывается с помощью сигнала «Thread: 1» SIGABRT ". Я знаю, что я не должен использовать get, но я пытаюсь найти способ заставить мой код работать с ним.C проверить ошибку ввода пользователя

#include <stdio.h> 

#define BUFFER_LENGTH 11 

int main() { 
    int cont; 
    while (1) { 
     char line[BUFFER_LENGTH]; 
     char *p; 
     printf("Enter Password: "); 
     p = gets (line); 
     if (strlen(p)>10) { 
      printf("Error! Password must be shorter than 10 characters! \n"); 
     }else{ 
      printf(p); 
      printf("\n"); 
      break; 
     } 
    } 
} 
+4

Не используйте 'gets()', который был удален из C-стандарта. вместо этого используйте 'fgets()'. –

+1

Вы выделили минимальный буфер для 'gets'. Если пользователь вводит более 10 символов, то 'gets' будет писать за конец' line'. Если вы используете 'fgets', тогда вы можете сказать, насколько велик ваш буфер, что является единственным способом защиты от этой проблемы (использование большего буфера делает ошибку менее вероятной). –

+0

Когда я использую fgets(), и ввод длиннее 10 символов, он печатает сообщение об ошибке, а затем принимает символы после первых 10 и выводит их. Это не то, чего я хочу. Есть ли способ заставить fgets() работать для моей программы? – BLively

ответ

3

Если пользовательский ввод длиннее 10 символов, вы в конечном итоге используете память за пределами допустимых пределов. Именно поэтому вы ДОЛЖНЫ избегать использования gets. См. Why is the gets function so dangerous that it should not be used? для получения дополнительной информации по этому вопросу.

Изменение gets линии:

fgets(line, sizeof(line), stdin); 

Тогда вам не придется беспокоиться о том вводе пользователя более 10 символов. Они будут просто проигнорированы.

Если вы хотите иметь дело с этим прецедентом как пользовательскую ошибку, измените размер line, но по-прежнему используйте fgets.

Update, благодаря @chux

Если пользователь вводит меньше, чем 11 символов в вашем случае, линия

fgets(line, sizeof(line), stdin); 

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

// Trim the newline character from user input. 
size_t len = strlen(line); 
if (len > 0 && line[len-1] == '\n') 
{ 
    line[len-1] = '\0'; 
} 
+0

Если вы используете это, и ввод длиннее 10 символов (например: abcdefghijkl), он распечатывает сообщение об ошибке, а затем принимает оставшиеся символы после первых 10 (ex: kl) и печатает их как допустимый ввод. Есть ли способ стереть данные в строке, чтобы он не искал оставшихся символов? – BLively

+1

Конечно, вы можете написать 'int c; while ((c = fgetc (stdin))! = EOF && c! = '\ n'); 'игнорировать остальную часть строки. –

+0

Нет, дополнительные символы не будут игнорироваться, они останутся вокруг, чтобы их подхватили при следующем чтении. – vonbrand

0

Если вы используете gets, line должен быть достаточно большим, чтобы вместить все возможные символы пользователь может ввести до удара возвращения. Сколько это? Предел приближается к бесконечности. Вместо этого используйте fgets.

2

Чтобы обнаружить, если более n вводятся символы, код должен

  1. Почитайте хотя бы n+1 символы без контроля.

  2. Обращайтесь с чрезмерными символами.

Код OP не должен использоваться gets(). Это устаревшая функция и не препятствует переполнению буфера.

void GetPrintPW(void) { 
    // +1 for the null character. 
    char pw[PASSWORD_MAX_LENGTH + 1]; 

    size_t i = 0; 
    bool too_long = false; 
    int bad_char = EOF; 
    int ch; 

    // Note: All characters in the line are consumed. Only the first `n` are saved. 
    while ((ch = fgetc(stdin)) != '\n' && ch != EOF) { 

    // This would be a good place to add code to check if the character is "good".  
    if (!isprint(ch)) bad_char = ch; 

    if (i < PASSWORD_MAX_LENGTH) pw[i++] = ch; 
    else too_long = true; 
    } 
    pw[i] = '\0'; 

    if (bad_char != EOF) { 
    printf("Error! Bad character, code %d\n", bad_char); 
    } else if (too_long) { 
    // Avoid `printf(only_some_string)` 
    puts("%Error! Password must be shorter than 10 characters!"); 
    } else { 
    // this is BAD! as a % in pw will cause UB with `printf()` 
    // printf(pw); 
    printf("'%s'\n", pw); 
    } 

    // Always a good idea to scrub data after using a password to prevent memory snooping. 
    memset(pw, 0, sizeof pw); 
} 

PW отмечает: Не используйте getline() для чтения паролей, как код теряет контроль над буферами, где хранились пароль. Используйте простой массив символов и скраб после этого. Использование malloc(), realloc() и т. Д. Может также иметь схожие проблемы.

Хорошие ОС будут иметь специальную функцию для чтения паролей, как на каждом уровне функции, любые данные буфера должны быть очищены.