Ваша попытка на самом деле не имитирует gets()
, поскольку gets()
просто продолжает помещать байты в предоставленный буфер до тех пор, пока не будет достигнут конец строки. Вы должны понимать, что gets()
опасен и его следует избегать. Он не предлагает никакой защиты от переполнения буфера. Так что имитировать его тоже сомнительно.
Учитывая это, ваша попытка имеет пару недостатков, которые я вижу. Во-первых, он возвращается к полному размеру входного буфера. Это не оставляет вам места для хранения терминатора NUL, если длина входной строки составляет 20 байт или больше. Это означает, что вы можете попытаться сохранить \0
в cvalue[20]
, что находится за границей массива. Вы можете исправить это, сократив цикл for
на единицу:
for(iloop=0;iloop<19;iloop++) // for loop to get the string char by char
Второй недостаток заключается в том, что вы не проверяете успешность вызова scanf()
. Если вы обнаружите сбой, вы также должны выйти из цикла:
if (scanf("%c",&cvalue[iloop]) != 1) { //getting input
break;
}
Ниже была моя попытка создать более безопасную версию gets()
, реализованную с помощью scanf()
.
char *getsn (char *s, size_t sz) {
char c;
char fmt[sizeof(sz) * CHAR_BIT + sizeof("[^\n]")];
if (sz == 0) return 0;
if (sz == 1) {
s[0] = '\0';
return s;
}
s[sz-2] = '\0';
snprintf(fmt, sizeof(fmt), "%%%lu%s", (unsigned long)sz-1, "[^\n]");
switch (scanf(fmt, s)) {
case 0: s[0] = '\0';
scanf("%c", &c);
return s;
case 1: scanf("%c", &c);
if (s[sz-2] != '\0' && c != '\n') {
ungetc(c, stdin);
}
return s;
default: break;
}
return 0;
}
Более безопасная версия использует snprintf()
для создания строки формата, ограничивающей количество символов, которое должно храниться в scanf()
. Таким образом, если предоставленный параметр sz
равен 100, результирующая строка формата будет "%99[^\n]"
. Затем он удаляет \n
из входного потока только в том случае, если он действительно встречается.
person
jxh
schedule
14.06.2013