Как проверить '\ n', используя scanf - PullRequest
2 голосов
/ 21 апреля 2019

Извинения C noob здесь,

Я пытаюсь проверить пользовательский ввод со стандартного ввода, но не могу найти способ обработать один \n ввод.Чтобы полностью упростить проблему, я написал ниже.Когда вводится \n, scanf заканчивается, если это первый введенный символ, например, пользователь нажимает ввод сразу, printf будет выводиться оператором *1007*.

int main(){
    char x[6];
    scanf("%[^\n]s", x);
    printf("%i\n", strlen(x));
    return 0;
}

Моя проблемаЯ не могу найти способ сказать, если пользователь ввел \n или 6 допустимых символов.Я также хотел бы установить проверку ввода MAX, и я не уверен, является ли scanf функцией записи для ввода данных пользователем, в этом случае или fgets может быть более подходящим.

Ответы [ 4 ]

1 голос
/ 21 апреля 2019

Вы можете использовать getchar(), чтобы проверить каждый отдельный вводимый символ и прекратить принимать ввод, когда размер ввода равен 6 или пользователь вводит \n.

Редактировать: Я обновил свой код в соответствии с предложением @ chux. Вы должны увеличить размер массива до 7, чтобы последний символ мог быть нулевым терминатором, когда ввод превышает 6 символов. Я также использовал переменную int c для хранения возвращаемых значений из getchar вместо сохранения непосредственно в x [i], чтобы он мог идентифицировать EOF.

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

int main(){
    char x[7];
    int c;
    size_t i = 0;
    while (i < 6 && (c=getchar()) != EOF) {
       x[i] = c;
       if (x[i] == '\n') {
           break;
       }
       ++i; 
    }
    x[i] = '\0'; // null-terminate string
    printf("%s\n", x);
    printf("%lu\n", strlen(x));
    return 0;
}
0 голосов
/ 21 апреля 2019

Помимо основного вопроса, в коде есть несколько проблем:

int main(){
    char x[6];
    // 1. an attack vector: lines with more than 6 characters will exceed buffer size
    // 2. The s will never be matched, 
    //      since %[^\n] consumes everything until EOF or \n
    // the following char can't be 's'      
    scanf("%[^\n]s", x);
    // if scanf fails, then x can be uninitialized:
    printf("%i\n", strlen(x));
    return 0;
}

Устранение проблем по одной:

scanf("%[^\n]", x); // still not good

Это будет читать до новой строки и останавливаться, но все равно может переполнить буфер:

scanf ("%5[^\n]", x); // better

Это позволит избежать переполнения буфера, ограничивая чтение до 5 символов. К сожалению, если ввод длинный, нет гарантии, что в конце будет записан нулевой терминатор. Также, если scanf завершится неудачно (как в вашем случае), то x будет неинициализирован:

char x[6] = ""; // fill NUL chars
scanf ("%5[^\n]", x); // better

Будет плохо работать, если, например, после чтения 3 символов возникнет проблема с вводом-выводом. Чтобы бороться с такого рода проблемами, проверьте код возврата:

char x[6] = ""; // fill NUL chars
int n_read = scanf ("%5[^\n]", x); // ok
if (n_read < 0) error...
else if (n_read == 0) newline or EOF...
else /*1*/  x is ready...

Обратите внимание, что вместо инициализации x = "", вероятно, лучше установить x[5] = '\0' после scanf. Вместо этого я выбрал вариант инициализации, поскольку легче было постепенно представить ответ таким образом.

0 голосов
/ 21 апреля 2019
#include <stdio.h>

int islegitimate(int c)
{
    if(c < ' ' || c > 127)
        return 0;
    return 1;
}

int isfirstNlegitimate(const char *str, size_t N)
{
    for(size_t index = 0; index < N; index++)
    {
        if(!islegitimate(str[index])) return 0;
    }
    return 1;
}

int main(void) {

    char x[7] ;
    fgets(x, 7, stdin);

    printf("The first 6 chars of the entered string are %slegitimate", isfirstNlegitimate(x,6) ? "" : "not ")
    return 0;
}

Вы также можете удалить символы конца строки (\ n в linux \ r \ n в Windows)

char *removetrailinglineends(char *str)
{
    size_t len = strlen(str);
    char *end = str + !len ? str : str + len - 1;

    while(end > str)
    {
        if(*end == '\n' || *end == '\r') *end = 0;
        end--;
    }
}
0 голосов
/ 21 апреля 2019

Когда вводится \ n, сканирование заканчивается, если это первый введенный символ, например, пользователь сразу нажимает клавишу ввода, оператором printf выводится 6.

Неопределенное поведение. Ничто не было прочитано в неинициализированный x[], поэтому strlen(x) - это UB.


scanf("%[^\n]s", x); отсутствует защита по ширине. У него нет проверки возвращаемого значения. Обнаружение только '\n' не является тривиальным.

Использование fgets().

int main(){
  // char x[6];
  char x[7];  // add at least 1 (useful for the \n code may read)
  // scanf("%[^\n]s", x);
  if (fgets(x, sizeof x, stdin)) {
    x[strcspn(x, "\n")] = '\0'; // lop off potential trailing \n
    // printf("%i\n", strlen(x));
    printf("%zu\n", strlen(x));  // use matching specifier
    return 0;
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...