Использование scanf
для линейно-ориентированного ввода является неправильным выбором. Рекомендуемый способ чтения строк пользовательского ввода - fgets()
или POSIX getline()
.
Зачем использовать fgets ()?
Короче говоря, он более надежный, он обрабатывает внутренние пробелы, позволяя вам ввести "first last"
name или "(409) 555-1212"
в качестве telno (scanf()
с "%s"
не может), и ваша единственная ответственность заключается в проверке возврата, а затем обрезке трейлинга '\n'
на входе. Вы проверяете возврат для обработки сгенерированного вручную EOF
, где пользователь отменяет ввод, нажимая Ctrl + d на Linux или Ctrl + z на windows. (так же, как вы должны сделать для scanf()
). В качестве преимущества вам не нужно вводить '#'
для завершения ввода, потому что fgets()
читает '\n'
, когда нажата Enter , что позволяет пользователь просто нажимает Введите в пустой строке name
для выхода.
Например, вы можете прочитать и проверить, что строка имени и телефонного номера была введена с чем-то простым как:
#define MAXTEL 32 /* if you need a constant, #define one (or more) */
#define MAXNM 64
#define MAXEMP 128
typedef struct {
char name[MAXNM],
telno[MAXTEL];
} employee;
int readin (employee *emp)
{
int n;
for (n = 0; n < MAXEMP; n++) { /* loop continually - protect array bounds */
fputs ("\nEnter name: ", stdout); /* prompt */
/* read/validate, check for Enter alone to exit */
if (!fgets (emp[n].name, MAXNM, stdin) || *emp[n].name == '\n')
break;
emp[n].name[strcspn(emp[n].name, "\n")] = 0; /* trim trailing \n */
fputs ("Enter tel : ", stdout); /* prompt */
if (!fgets (emp[n].telno, MAXTEL, stdin)) /* read/validate */
break;
emp[n].telno[strcspn(emp[n].telno, "\n")] = 0; /* trim trailing \n */
}
return n;
}
Как насчет использования scanf ()?
Это выполнимо, но ваши обязанности резко возрастут, так как вам нужно будет удалить '\n'
, который остается в stdin
после получения ввода, чтобы гарантировать, что следующий ввод в вашем коде после выхода из функции readin()
не завершится с ошибкой. С scanf()
(установите до l oop, как вы указали, требуя '#'
для завершения ввода), потребуется:
int readin (employee *emp)
{
int n;
for (n = 0; n < MAXEMP; n++) { /* loop continually - protect array bounds */
int rtn; /* variable to save the return of scanf */
fputs ("\nEnter name: ", stdout); /* prompt */
rtn = scanf(" %63[^\n]", emp->name); /* read into tmp saving return */
if (rtn == EOF) { /* handle EOF - user presses Ctrl+d (Ctrl+z win) */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 1 && *emp->name == '#') /* good input and '#' -- bail */
break;
for (;;) { /* loop contianually until valid telno entered */
fputs ("Enter tel : ", stdout); /* prompt */
rtn = scanf(" %31[^\n]", emp->telno); /* read saving return */
if (rtn == EOF) { /* handle EOF - ditto */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 1) { /* good input */
/* further validate telno here */
break;
}
} /* empty trailing \n from stdin */
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
emp++; /* advance pointer */
}
return n; /* return success */
}
И вам все еще нужно ввести '#'
для завершения ввод - который не должен быть необходим.
Что бы вы предпочли использовать?
Пример
Использовать любую функцию с :
int main (void) {
employee e[MAXEMP] = {{ .name = "" }};
int n = readin (e);
for (int i = 0; i < n; i++)
printf ("\nemployee:\n name : %s\n telno : %s\n",
e[i].name, e[i].telno);
}
Пример использования / вывода - fgets ()
$ ./bin/empnametelnoarray
Enter name: John Q. Public
Enter tel : 444-1212
Enter name: Sally P. Public
Enter tel : 444-1222
Enter name: Mary Jane
Enter tel : 444-1223
Enter name:
employee:
name : John Q. Public
telno : 444-1212
employee:
name : Sally P. Public
telno : 444-1222
employee:
name : Mary Jane
telno : 444-1223
Пример использования / вывода - scanf ()
$ ./bin/empnametelnoarray
Enter name: John Q. Public
Enter tel : 444-1212
Enter name: Sally P. Public
Enter tel : 444-1222
Enter name: Mary Jane
Enter tel : 444-1223
Enter name: #
employee:
name : John Q. Public
telno : 444-1212
employee:
name : Sally P. Public
telno : 444-1222
employee:
name : Mary Jane
telno : 444-1223
Полный пример показан ниже, просто добавьте -DUSESCANF
в строку компиляции (или /D USESCANF
для VS), чтобы использовать версию scanf()
, по умолчанию используется fgets()
. В целом, нет смысла использовать scanf()
для чтения двух строк ввода пользователя. Вы гораздо лучше справляетесь, используя линейно-ориентированную функцию ввода для чтения строк ввода от пользователя:
#include <stdio.h>
#include <string.h>
#define MAXTEL 32 /* if you need a constant, #define one (or more) */
#define MAXNM 64
#define MAXEMP 128
typedef struct {
char name[MAXNM],
telno[MAXTEL];
} employee;
#ifndef USESCANF
int readin (employee *emp)
{
int n;
for (n = 0; n < MAXEMP; n++) { /* loop continually - protect array bounds */
fputs ("\nEnter name: ", stdout); /* prompt */
/* read/validate, check for Enter alone to exit */
if (!fgets (emp[n].name, MAXNM, stdin) || *emp[n].name == '\n')
break;
emp[n].name[strcspn(emp[n].name, "\n")] = 0; /* trim trailing \n */
fputs ("Enter tel : ", stdout); /* prompt */
if (!fgets (emp[n].telno, MAXTEL, stdin)) /* read/validate */
break;
emp[n].telno[strcspn(emp[n].telno, "\n")] = 0; /* trim trailing \n */
}
return n;
}
#else
int readin (employee *emp)
{
int n;
for (n = 0; n < MAXEMP; n++) { /* loop continually - protect array bounds */
int rtn; /* variable to save the return of scanf */
fputs ("\nEnter name: ", stdout); /* prompt */
rtn = scanf(" %63[^\n]", emp->name); /* read into tmp saving return */
if (rtn == EOF) { /* handle EOF - user presses Ctrl+d (Ctrl+z win) */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 1 && *emp->name == '#') /* good input and '#' -- bail */
break;
for (;;) { /* loop contianually until valid telno entered */
fputs ("Enter tel : ", stdout); /* prompt */
rtn = scanf(" %31[^\n]", emp->telno); /* read saving return */
if (rtn == EOF) { /* handle EOF - ditto */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 1) { /* good input */
/* further validate telno here */
break;
}
} /* empty trailing \n from stdin */
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
emp++; /* advance pointer */
}
return n; /* return success */
}
#endif
int main (void) {
employee e[MAXEMP] = {{ .name = "" }};
int n = readin (e);
for (int i = 0; i < n; i++)
printf ("\nemployee:\n name : %s\n telno : %s\n",
e[i].name, e[i].telno);
}
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.