gpt4 book ai didi

c - 在 C 中动态指定 scanf 的最大字符串长度(如 printf 中的 "%*s")

转载 作者:行者123 更新时间:2023-11-30 16:26:25 25 4
gpt4 key购买 nike

我可以使用此技术指定 scanf 读取到 缓冲区 的最大字符数:

char buffer[64];

/* Read one line of text to buffer. */
scanf("%63[^\n]", buffer);

但是如果我们在编写代码时不知道缓冲区长度怎么办?如果是函数的参数怎么办?

void function(FILE *file, size_t n, char buffer[n])
{
/* ... */
fscanf(file, "%[^\n]", buffer); /* WHAT NOW? */
}

此代码容易发生缓冲区溢出,因为 fscanf 不知道缓冲区有多大。

我记得以前看到过这个,并开始认为这是问题的解决方案:

fscanf(file, "%*[^\n]", n, buffer);

我的第一个想法是 "%*[*^\n]" 中的 * 意味着最大字符串大小传递给一个参数(在本例中 n)。这就是printf*的含义。

当我检查 scanf 的文档时,我发现这意味着 scanf 应该丢弃 [^\n] 的结果。

这让我有些失望,因为我认为能够为 scanf 动态传递缓冲区大小将是一个非常有用的功能。

有什么方法可以动态地将缓冲区大小传递给 scanf 吗?

最佳答案

基本答案

scanf() 中没有与 printf() 格式说明符 * 类似的内容。

The Practice of Programming 、Kernighan 和 Pike 建议使用 snprintf() 创建格式字符串:

size_t sz = 64;
char format[32];
snprintf(format, sizeof(format), "%%%zus", sz);
if (scanf(format, buffer) != 1) { …oops… }

额外信息

将示例升级为完整功能:

int read_name(FILE *fp, char *buffer, size_t bufsiz)
{
char format[16];
snprintf(format, sizeof(format), "%%%zus", bufsiz - 1);
return fscanf(fp, format, buffer);
}

这强调了格式规范中的大小比缓冲区的大小小一(它是在不计算终止空的情况下可以存储的非空字符的数量)。请注意,这与 fgets() 不同,其中大小(顺便说一下,是 int;不是 size_t)是缓冲区的大小,一个也不能少。改进功能的方法有很多种,但它说明了要点。 (如果您愿意,可以将格式中的 s 替换为 [^\n]。)

此外,如Tim Čas comments 中指出,如果您想要(其余的)一行输入,通常最好使用 fgets() 来读取该行,但请记住它在输出中包含换行符(而 %63[^\n] 留下换行符以供下一个 I/O 操作读取)。对于更一般的扫描(例如 2 或 3 个字符串),此技术可能更好 - 特别是与 fgets()getline() 一起使用,然后与 sscanf() 解析输入。

此外,由 Microsoft(或多或少)实现并在 ISO/IEC 9899-2011(C11 标准)附录 K 中标准化的 TR 24731-1“安全”函数明确要求长度:

if (scanf_s("%[^\n]", buffer, sizeof(buffer)) != 1)
...oops...

这可以避免缓冲区溢出,但如果输入太长,可能会产生错误。大小可以/应该像以前一样在格式字符串中指定:

if (scanf_s("%63[^\n]", buffer, sizeof(buffer)) != 1)
...oops...

if (scanf_s(format, buffer, sizeof(buffer)) != 1)
...oops...

请注意,对于使用生成的格式字符串的代码,必须忽略或抑制有关“非常量格式字符串”的警告(来自某些编译器在某些标志集下)。

关于c - 在 C 中动态指定 scanf 的最大字符串长度(如 printf 中的 "%*s"),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53071084/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com