2013-06-14 3 views
0

Что было бы лучшим способом подражать функциональности gets с помощью scanf?Как будет работать функция scanf?

Вот моя текущая попытка

int main() 
{ 
    char cvalue[20]; //char array to store input string 
    int iloop=0;  //integer variable for loop 

    for(iloop=0;iloop<20;iloop++)  // for loop to get the string char by char 
    { 
     scanf("%c",&cvalue[iloop]); //getting input 
     if(cvalue[iloop]=='\n') //if input is newline skip further looping 
     break; 
    }     // end of loop 

    cvalue[iloop]='\0';   //set end of the character for given input 
    printf("%s",cvalue);  //printing the given string 
    return 0; 
} 
+0

Пожалуйста, найдите время, чтобы узнать, как [форматировать свои вопросы] (http://stackoverflow.com/editing-help). Я также сформулировал ваш вопрос, чтобы лучше соответствовать формату SO. Сначала задайте вопрос четко, а затем покажите свою текущую попытку. –

ответ

2

Вы можете использовать scanf этот способ работать как gets

scanf("%[^\n]",&a); 
+0

Кажется, что он не потребляет '\ n' во входном файле, например' gets() '. 'gets()' reads '\ n', но не хранит его в '& a'. – chux

0

Ваша попытка не очень подражают 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 от входного потока, если он действительно встретился.

+0

Новое использование 'printf()' для создания максимальной ширины поля для 'scanf (fmt, s)'. – chux

0

Необходимо соблюдать обычные опасности gets().

Задача использования scanf() является
1) Страхуя что \n потребляется. scanf("%[^\n]",... не делает.
2) Страхование str получает \0, если считывается только \n.
3) Работа с ошибками EOF и I/O и возвратом 0.
4) Зафиксируйте ведущие пробелы в str, так как scanf("%s" пропускает их.

#include <stdio.h> 
// On success, the gets() returns str. 
// If EOF encountered, the eof indicator is set (feof). 
// If this happens before any characters could be read, 
// pointer returned is a null pointer. 
// If a read error occurs, the error (ferror) is set 
// and a null pointer is also returned. 
char *gets_via_scanf(char * str) { 
    // Reads characters from stdin & saves them into str until \n or the end-of-file. 
    // \n, if found, is not copied into str. 
    int retval = scanf("%[^\n]",str); // %[ does not skip leading whitespace 
    if (retval == EOF) return 0; 
    if (retval == 0) { 
    *str = '\0'; // Happens when users only types in \n 
    } 
    char ch; 
    scanf("%c",&ch); // Consume leftover \n, could be done with getc() 
    return str; 
}