将 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 上完全是多余的。)
对于 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 上完全是多余的。)