альтернативу можно использовать вместо get ()
char str[MAX_SIZE]; gets()
возникают проблемы при чтении строки из N
символов.(N
также учитывает '\n'
).
Когда N > MAX_SIZE
, результатом будет неопределенное поведение (UB).Слишком много информации и некуда идти.Часто этот UB записывает в места, используемые другими объектами.Плохо - очень плохо.
C11 исключено gets()
и с тех пор не является стандартной функцией.
Обычное решение fgets()
хорошо предложено @ Stephan Lechner .fgets()
имеет некоторые недостатки, перечисленные ниже.
str[MAX_SIZE]
теперь должно быть str[MAX_SIZE + 1]
, поскольку fgets()
также сохраняет '\n'
, в отличие от gets()
.Иногда добавление + 1 нецелесообразно.
fgets()
сохраняет потенциал '\n'
.См. Удаление завершающего символа новой строки из fgets ()
Если ввод слишком большой, fgets()
просто не читает его, в отличие от gets()
.Это хорошо ведет себя (не UB), но мы все еще сталкиваемся с этой проблемой: как обнаружить чрезмерный ввод и что с этим делать?
Если код может с этим справиться, используйте fgets()
.В противном случае читайте дальше.
mygets()
альтернатива
Эта функция не нуждается в +1 к размеру буфера s
.
Чрезмерно длинный ввод возвращает NULL
.Вся строка прочитана.Буфер s
заполнен начальными символами.
char *mygets(char *s, size_t n) {
char *dest = s;
// Pathological case of n==0
char dummy[1];
if (n == 0) {
n = sizeof dummy;
dest = dummy;
}
size_t i = 0;
int ch;
n--;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < n) {
dest[i++] = (char) ch;
} else {
s = NULL; // Not enough room
}
}
if (ch == EOF) {
if (feof(stdin)) { // end-of-file
if (i == 0) {
s = NULL;
}
} else { // input error
i = 0;
s = NULL;
}
}
dest[i] = '\0';
return s;
}
Тонкие бонусы:
s
буфер хорошо определен при редкой ошибке ввода.С gets/fgets
содержимое буфера тогда не определено.
Патологический размер 0 хорошо определен.fgets()
немного сомнительно на этом.
Размер буфера - идиоматический size_t
, а не int
как с fgets()
.
Использование
str[MAX_SIZE];
if (mygets(str, sizeof str)) {
printf("Success <%s>\n", str);
} else {
if (feof(str)) printf("End of file detected. <%s>\n", str);
else if (ferror(str)) printf("End of file detected. <%s>\n", str);
else printf("Input too long <%s>.", str);
}