将 scanf 与 %[^\n] 一起用于没有已知限制的字符串

Using scanf with %[^\n] for a string with no known limit

对于 uni 作业,我必须捕获一个字符串(稍后将成为一个命令)。老师推荐使用 fgets 但由于我不知道限制,我决定使用那个 scanf。

问题是打印不正确。

这是我的测试代码:

int main()
{
    char *name1;
    printf("go:");
    scanf(" %[^\n]", name1);
    printf("%s xx %s", name1);
}

如果您对 fgets 有任何建议,那也很好!

标准 C 库中没有函数可以安全地读取无界字符串。这是我手写的(不能保证它具有所有安全功能,我尝试添加我想到的内容):

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

char* get_string(FILE* stream)
{
    #define INITIAL_BUF_SIZE 100
    size_t size = INITIAL_BUF_SIZE, i = 0;
    int c;
    char* s = malloc(size * sizeof *s);
    if (s == NULL)
        return NULL;
    while ((c = getc(stream)) != '\n' && c != EOF)
    {
        s[i++] = c;
        if (i == size)
        {
            size *= 2;
            char* p = realloc(s, size * sizeof *p);
            if (p == NULL)
            {
                free(s);
                return NULL;
            }
            s = p;
        }
    }
    s[i++] = '[=10=]';
    if (i == size)
        return s;
    char* p = realloc(s, i * sizeof *p);
    if (p == NULL)
    {
        free(s);
        return NULL;
    }
    return p;
    #undef INITIAL_BUF_SIZE
}

int main(void)
{
    char* name1 = get_string(stdin);
    printf("The string is: %s\n", name1);
    free(name1);
}

请注意,返回的字符串必须由调用者使用 free() 释放以避免内存泄漏。

如果您正在为 PC(而不是某些嵌入式设备)编程,只需分配一个 非常大的缓冲区(比如 1 MB、10 或 100),其中您确定它适用于所有可能的用例。现在内存非常便宜,为了节省内存而花费资源和使程序复杂化是不值得的。 (例如:您需要多长时间才能 100% 确定 David 的解决方案完全没有错误?如果在生产中使用它,我可能 想为它编写一个测试代码。)

尽管动态或静态分配内存;自动变量的堆栈 space 可能仍然受到限制。然后使用 fgets。尽管如此,请确保优雅地处理太长的行。不需要像 David 的回答那样将它们从块中连接起来:这些长行要么是测试用例,要么是数据错误。您可以简单地退出并显示一条错误消息。 (如果你想满足 David Ranieri 的良好秩序和原则感,你也可以显式释放任何分配的内存,即使这在 PC 上完全是多余的。)