scanf的缺点 [英] Disadvantages of scanf

查看:43
本文介绍了scanf的缺点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道scanf()的缺点.

在许多站点中,我读到使用 scanf 可能会导致缓冲区溢出.这是什么原因?scanf 还有其他缺点吗?

In many sites, I have read that using scanf might cause buffer overflows. What is the reason for this? Are there any other drawbacks with scanf?

推荐答案

scanf 的问题(至少)是:

The problems with scanf are (at a minimum):

  • 使用%s从用户处获取字符串,这导致字符串可能比您的缓冲区长,从而导致溢出.
  • 扫描失败的可能性,将您的文件指针留在不确定的位置.
  • using %s to get a string from the user, which leads to the possibility that the string may be longer than your buffer, causing overflow.
  • the possibility of a failed scan leaving your file pointer in an indeterminate location.

我非常喜欢使用 fgets 来读取整行,这样你就可以限制读取的数据量.如果您有一个 1K 的缓冲区,并且您使用 fgets 将一行读入其中,您可以通过没有终止换行符的事实来判断该行是否太长(文件的最后一行没有尽管有换行符).

I very much prefer using fgets to read whole lines in so that you can limit the amount of data read. If you've got a 1K buffer, and you read a line into it with fgets you can tell if the line was too long by the fact there's no terminating newline character (last line of a file without a newline notwithstanding).

然后你可以向用户抱怨,或者为行的其余部分分配更多的空间(如果有必要,继续,直到你有足够的空间).无论哪种情况,都不存在缓冲区溢出的风险.

Then you can complain to the user, or allocate more space for the rest of the line (continuously if necessary until you have enough space). In either case, there's no risk of buffer overflow.

一旦您阅读了该行,您就知道您位于下一行,因此那里没有问题.然后,您可以sscanf 将您的字符串变成您心仪的内容,而无需保存和恢复文件指针以供重新读取.

Once you've read the line in, you know that you're positioned at the next line so there's no problem there. You can then sscanf your string to your heart's content without having to save and restore the file pointer for re-reading.

这是我经常使用的一段代码,以确保在向用户询问信息时不会出现缓冲区溢出.

Here's a snippet of code which I frequently use to ensure no buffer overflow when asking the user for information.

如有必要,可以轻松调整以使用标准输入以外的文件,您也可以让它分配自己的缓冲区(并不断增加它直到足够大),然后再将其返回给调用者(尽管调用者会然后负责释放它,当然).

It could be easily adjusted to use a file other than standard input if necessary and you could also have it allocate its own buffer (and keep increasing it until it's big enough) before giving that back to the caller (although the caller would then be responsible for freeing it, of course).

#include <stdio.h>
#include <string.h>

#define OK         0
#define NO_INPUT   1
#define TOO_LONG   2
#define SMALL_BUFF 3
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Size zero or one cannot store enough, so don't even
    // try - we need space for at least newline and terminator.

    if (sz < 2)
        return SMALL_BUFF;

    // Output prompt.

    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }

    // Get line with buffer overrun protection.

    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // Catch possibility of `` in the input stream.

    size_t len = strlen(buff);
    if (len < 1)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.

    if (buff[len - 1] != '
') {
        extra = 0;
        while (((ch = getchar()) != '
') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[len - 1] = '';
    return OK;
}

还有,它的测试驱动程序:

And, a test driver for it:

// Test program for getLine().

int main (void) {
    int rc;
    char buff[10];

    rc = getLine ("Enter string> ", buff, sizeof(buff));
    if (rc == NO_INPUT) {
        // Extra NL since my system doesn't output that on EOF.
        printf ("
No input
");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long [%s]
", buff);
        return 1;
    }

    printf ("OK [%s]
", buff);

    return 0;
}

最后,测试运行以显示它的实际效果:

Finally, a test run to show it in action:

$ printf "" | ./tstprg     # Singular NUL in input stream.
Enter string>
No input

$ ./tstprg < /dev/null       # EOF in input stream.
Enter string>
No input

$ ./tstprg                   # A one-character string.
Enter string> a
OK [a]

$ ./tstprg                   # Longer string but still able to fit.
Enter string> hello
OK [hello]

$ ./tstprg                   # Too long for buffer.
Enter string> hello there
Input too long [hello the]

$ ./tstprg                   # Test limit of buffer.
Enter string> 123456789
OK [123456789]

$ ./tstprg                   # Test just over limit.
Enter string> 1234567890
Input too long [123456789]

这篇关于scanf的缺点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆