如何在我的 C 程序中多次使用 "gets" 函数?

How can I use the "gets" function many times in my C program?

我的代码:

#include <stdio.h>
#include <math.h>
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        char a[10],b[10];
        puts("enter");
        gets(a);
        puts("enter");
        gets(b);
        puts("enter");
        puts(a);
        puts(b);
    }
    return 0;
}

输出:

1

enter 

enter

surya  (string entered by user)

enter

surya   (last puts function worked)

How can I use “gets” function many times in C program?

你应该永远不要在你的程序中使用gets()。它已被弃用,因为它很可能导致缓冲区溢出,因为它不可能停止使用特定数量的字符 - f.e。最重要的是 - 缓冲区能够容纳的字符数量,ab 每 10 个字符。

这里也有说明:

Why is the gets function so dangerous that it should not be used?

特别是在乔纳森·莱弗勒的 this 回答中。

改用fgets()


此外,while 循环中 ab 的定义没有任何意义,尽管这只是一个玩具程序,仅供学习之用。

另外请注意,scanf() 留下了换行符,由 stdin 中的 scanf() 调用按到 return 生成。你必须抓住这个,否则之后的第一个 fgets() 会消耗这个字符。


这是更正后的程序:

#include <stdio.h>

int main()
{
    int t;
    char a[10],b[10];

    if(scanf("%d",&t) != 1)
    {
        printf("Error at scanning!");
        return 1;
    }

    getchar();          // For catching the left newline from scanf().

    while(t--)
    {        
        puts("Enter string A: ");
        fgets(a,sizeof a, stdin);
        puts("Enter string B: ");
        fgets(b,sizeof b, stdin);

        printf("\n");

        puts(a);
        puts(b);

        printf("\n\n");
    }

    return 0;
}

执行:

$PATH/a.out
2
Enter string A:
hello
Enter string B:
world

hello

world


Enter string A:
apple
Enter string B:
banana

apple

banana

对您来说最重要的信息是:

永远不要使用 gets - 它不能防止缓冲区溢出。您的缓冲区可以容纳 9 个字符和终止字符,但 gets 将允许用户输入更多字符,从而覆盖程序内存的其他部分。攻击者可以利用它。所以在任何程序中都没有gets

改用fgets

就是说 - 你有什么问题吗?

scanf 在输入流中留下换行符(又名 '\n')。所以第一个 gets 只是读取一个空字符串。然后第二个 gets 读取 "surya".

这样测试:

#include <stdio.h>
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        char a[10],b[10];
        puts("enter");
        gets(a);        // !!! Use fgets instead
        puts("enter");
        gets(b);        // !!! Use fgets instead
        puts("enter");
        printf("|%s| %zu", a, strlen(a));
        printf("|%s| %zu", b, strlen(b));
    }
    return 0;
}

输入:

1
surya
whatever

输出:

enter
enter
enter
|| 0|surya| 5

所以在这里你看到 a 只是一个空字符串(长度为零)并且 b 包含单词 "surya"(长度为 5)。

如果您使用 fgets,您可以保护自己免受用户启动的缓冲区溢出 - 这很重要。

但是 fgets 不会 删除 scanf 遗留下来的 '\n'。你仍然需要自己摆脱​​它。

为此,我建议也删除 scanf。使用 fgets,然后使用 sscanf。喜欢:

if (fgets(a,sizeof a, stdin) == NULL)
{
    // Error
    exit(1);
}
if (sscanf(a, "%d", &t) != 1)
{
    // Error
    exit(1);
}

所以上面的代码会在输入t时自动从输入流中移除'\n',随后的fgets将从下一个单词开始。

综合起来:

#include <stdio.h>
int main()
{
    int t;
    char a[10],b[10];
    if (fgets(a,sizeof a, stdin) == NULL)
    {
        // Error
        exit(1);
    }
    if (sscanf(a, "%d", &t) != 1)
    {
        // Error
        exit(1);
    }

    while(t--)
    {
        puts("enter");
        if (fgets(a,sizeof a, stdin) == NULL)
        {
            // Error
            exit(1);
        }
        puts("enter");
        if (fgets(b,sizeof b, stdin) == NULL)
        {
            // Error
            exit(1);
        }
        puts("enter");
        printf("%s", a);
        printf("%s", b);
    }
    return 0;
}

输入:

1
surya 
whatever

输出:

enter
enter
enter
surya 
whatever

最后的注释:

fgets 将 - 与 gets 不同 - 还将 '\n' 保存到目标缓冲区中。根据您要执行的操作,您可能必须从缓冲区中删除 '\n'