为什么 gets() 读取的字符比我在用 calloc() 初始化它时设置的限制更多?

Why does gets() read in more characters to the pointer than the limit I set it when initializing it with calloc()?

我正在尝试获取动态内存分配,我只想让我的程序获取一个字符串和应该从用户的字符串中打印的最大字符数,然后只输出该字符串到我用 calloc 分配的字符数。当我 运行 程序时,它完全无视我使用 calloc() 为它设置的限制,只是打印出整个字符串。

我尝试使用 malloc 但结果相同。另外,当我第一次尝试打印输入的文本时,我取消了对文本的引用,但它导致程序在您输入要打印的字符串后停止。

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

int main()
{
    int max;
    char *text = NULL;

    printf("\n\n");
    printf("Please enter the limit for the string as a positive integer: \n");
    scanf("%d", &max);

    text = (char *)calloc(max, sizeof(char));

    if (text != NULL)
    {
        printf("Please enter the string you want printed: \n");
        scanf(" "); //read in next character so it pauses
        gets(text);

        printf("Inputted text is : %s\n", text);
    }

    free(text);
    text = NULL;


    return 0;
}

是的,我知道,我收到 gets 不安全的警告,但我是通过教程观看的,并且构建了讲师版本并且 运行 很好。即使我使用 scanf 将字符串读入文本,结果也是一样的。


修改后的代码使用 fgets():

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

int main()
{
    int max;
    char *text = NULL;

    printf("\n\n");
    printf("Please enter the limit for the string as a positive integer: \n");
    scanf("%d", &max);

    text = (char *)calloc(max, sizeof(char));

    if (fgets(text, max, stdin))
    {
        printf("Please enter the string you want printed: \n");
        fgets(text, max, stdin);
        text[strcspn(text, "\n")] = '[=11=]';

        printf("Inputted text is : %s\n", text);
    }

    free(text);
    text = NULL;


    return 0;
}

我更改了我的代码以改用 fgets 并进行了一些更正。它 returns 比用户输入的 "max" 少 1 个字符。另外,使用 fgets 是否意味着我不需要为 calloc 烦恼?

当您分配内存并将其分配给指针时,无法从手中的指针推断出内存的大小。所以 gets 没有机会(因此不会检查)它是否会超过您保留的内存量。顺便说一句:gets 不再是 C 标准的一部分(自 C11 起)。请改用 fgets 并将您的 max 作为参数传递:

if (fgets(text, max, stdin)) {
   // something successfully read in
   text[strcspn(text, "\n")] = '[=10=]';
}

请注意,与 gets 相反,fgets 会保留任何输入的新行并将其保留在 text 的末尾。要摆脱这种情况,您可以使用 text[strcspn(text, "\n")] = '[=18=]',这将使字符串在换行符(如果有)处结束。

我认为您的代码忽略 max 变量的确切原因是当标准输入提供的字符串长于 max 时,gets() 函数正在覆盖文本字符数组中的所有空字节。这就是为什么我们总是说“永远不要使用 gets()”的众多原因之一!

更具体地说,gets() 将继续从标准输入写入您的数组,直到它到达换行符或 EOF 字符,而不考虑它的边界。事实上,如果只是未定义的行为,您会看到打印出整个字符串。