0

What would be the best way to imitate the functionality of gets with scanf?

Here is my current attempt

 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;
}
4

3 回答 3

2

你可以使用scanf这种方式来工作gets

scanf("%[^\n]",&a);
于 2013-06-14T14:54:58.180 回答
0

您需要观察通常的危险gets()

使用的挑战scanf()
1) 确保\n消费。 scanf("%[^\n]",...不这样做。
2)如果只读取a ,则确保str得到 a 。 3)处理EOF和I/O错误并返回。 4) 确保前导空白被读入作为跳过它们。\0\n
0
strscanf("%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;
}
于 2013-06-18T01:52:38.720 回答
0

您的尝试并没有真正模仿gets(),因为gets()只是不断将字节放入提供的缓冲区,直到到达行尾。你应该意识到那gets()是危险的,应该避免。它不提供任何缓冲区溢出保护。所以,模仿它也是有问题的。

鉴于此,我看到您的尝试存在一些缺陷。首先,它循环到输入缓冲区的完整大小。如果输入行是 20 字节或更长,这不会给您留下任何空间来存储 NUL 终止符。这意味着您可以尝试将\0at存储在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在实际遇到输入流时才从输入流中删除它。

于 2013-06-14T15:06:27.097 回答