Проверка с помощью strlen в c

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

    do
    {
        inputflag=0;
        printf("Passenger ID no: ");
        gets(newRes.idCard);
        if((strlen(newRes.idCard))>7)
        {
            printf("invalid input \n");
            inputflag=1;
        }
        fflush(stdin);
    } while(inputflag==0);

person user3052741    schedule 23.12.2013    source источник
comment
Не используйте fflush(stdin). Это незаконно и вызывает неопределенное поведение!   -  person Fiddling Bits    schedule 23.12.2013
comment
К тому времени, когда вы проверите размер ввода, ущерб уже будет нанесен... Попробуйте вместо этого использовать fgets.   -  person    schedule 23.12.2013
comment
еще хуже без fflush(stdin)   -  person user3052741    schedule 23.12.2013
comment
Вам будет полезно найти прототип gets() в заголовках реализации и закомментировать его. Это настолько мерзко и зло, что язык устарел и больше не будет поддерживаться в будущих версиях. Вместо этого используйте fgets().   -  person WhozCraig    schedule 23.12.2013
comment
Ваш fflush должен быть на стандартном выводе после печати.   -  person cup    schedule 23.12.2013


Ответы (3)


Ваш gets вызов небезопасен. Он может принять больше символов, чем вы выделили. Бум.

Предполагая, что вы выделили не менее 8 байтов для .idCard (т.е. 7 символов плюс терминатор), рассмотрите возможность использования этого:

  fgets(newRes.idCard, 7+1, stdin);

Это гарантирует, что вы не примете слишком много символов. Он будет обрезан по мере необходимости. Проверьте возвращаемое значение fgets на успешность.

(man fgets)

Скомпилируйте этот пример кода и изучите. Надеюсь, вы найдете здесь то, что ищете.

#include <stdio.h>
#include <string.h>

#define MAX_ID_LEN (7)

int main() {
    char idCard[MAX_ID_LEN+1];
    printf("ID: ");
    if (fgets(idCard, MAX_ID_LEN+1, stdin)) {
        char *cLast = idCard + strlen(idCard)-1;
        if (*cLast == '\n')
            *cLast = 0;  // strip newline *if* present
        printf("Success!  idCard='%s'\n", idCard);
    } else {
        printf("Failure.\n");
    }
    return 0;
}

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

В качестве альтернативы, это, вероятно, меньше отвлекает вас: (просто используйте fscanf)

#include <stdio.h>

int main() {
    char idCard[7+1];
    printf("ID: ");
    fscanf(stdin, "%7s", idCard);
    printf("idCard='%s'\n", idCard);
    return 0;
}
person Darren Stone    schedule 23.12.2013
comment
@ user3052741, поделитесь кодом или фрагментом, который вы пробовали. fgets перестанет читать после новой строки. - person Darren Stone; 23.12.2013
comment
' сделать {inputflag=0; printf (номер удостоверения личности пассажира: ); fgets(newRes.idCard, 7+1, стандартный ввод); if((strlen(newRes.idCard))›7) { printf(invalid input\n); входной флаг=1; } fflush(стандартный ввод); } пока (входной флаг == 0);' - person user3052741; 23.12.2013
comment
Это потому, что fflush не работает должным образом. Посмотрите на мой ответ, как сбросить stdin. - person Devolus; 23.12.2013
comment
Я думаю, что также необходимо принудительно завершать нулем результирующую строку - если количество прочитанных символов равно › 7, значение idCard не будет завершаться нулем. - person ; 23.12.2013
comment
@ user3052741, я только что отредактировал свой ответ выше, включив в него небольшую тестовую программу. Я предлагаю вам скомпилировать и запустить его, чтобы убедиться, что он работает. Будет. Обратите внимание, что нет необходимости в какой-либо проверке допустимой длины strlen, если вы используете fgets, поскольку максимальная длина уже обеспечена. - person Darren Stone; 23.12.2013
comment
fgets позаботится о том, чтобы был 0 байт. - person Devolus; 23.12.2013
comment
спасибо, спасибо @DarrenStone, это сработало :) и, кроме того, я понял метод. - person user3052741; 23.12.2013
comment
@ user3052741, отлично. Я только что добавил еще один пример, в котором используется fscanf — вы также можете рассмотреть этот метод. - person Darren Stone; 23.12.2013

Чтобы правильно сбросить stdin, вы должны сделать следующее:

int c;
while ((c = getchar()) != '\n' && c != EOF);

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

gets не будет знать длину, и, таким образом, если пользователь введет больше, чем предусмотрено буфером, это может привести к переполнению буфера.

Почему функция fflush(stdin) не работает?

person Devolus    schedule 23.12.2013

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

fgets() — отличная замена устаревшему gets(). Не забудьте убрать потенциальное окончание \n.

Также избегайте магических чисел, таких как «7». Используйте что-то вроде sizeof(newRes.idCard).

В хорошо спроектированном коде fflush(stdin) не требуется, и его следует избегать, поскольку он не переносим.

int inputflag = 0;  // Not clear is OP needs this value after the while loop.
do {
  printf("Passenger ID no: ");
  char buf[sizeof(newRes.idCard) * 2]; ' twice as big as needed.
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    inputflag = 1;
    break;
  }
  size_t Len = strlen(buf);
  if (Len && buf[Len-1] == '\n') buf[--Len] = '\0';
  if(Len >= sizeof(newRes.idCard)) {
    printf("invalid input \n");
    inputflag = 1;
  }
  else {
    strcpy(newRes.idCard, buf);
  }
} while (inputflag == 0);
person chux - Reinstate Monica    schedule 24.12.2013