当与 fscanf 配对时,这个格式字符串究竟做了啥?

Posted

技术标签:

【中文标题】当与 fscanf 配对时,这个格式字符串究竟做了啥?【英文标题】:What exactly does this format string do when paired with fscanf?当与 fscanf 配对时,这个格式字符串究竟做了什么? 【发布时间】:2022-01-07 18:58:59 【问题描述】:

我正在查看一些代码并遇到了这一行:

fscanf(file, "%*[: ]%16s", dest);

%*[: ]%16s 格式字符串说明符有什么作用?

【问题讨论】:

我觉得对您的问题的最佳答案是,对于 fscanf 格式说明符,表面上必须是任何 documentation page。因此,除非您在某些文档中遇到您特别需要澄清或不理解的内容,否则我将投反对票(基于缺乏研究),在这种情况下,请在您的问题中澄清您对现有的了解或不了解的内容格式说明符的文档。 @Wyck 据我所知,有时即使是高级程序员也没有读过 C 或 C++ 标准。 如果在许多问题上甚至没有像在网上询问 scanf 格式字符串这样的简单研究功能,而且没有任何自己努力的迹象,它会正确地导致投票失败。您可能需要再次使用tour。坏名声反映在滥用 SO 的人身上。 【参考方案1】:

这个格式字符串

"%*[: ]%16s"

表示必须在输入流中跳过所有符号':'' '(格式字符串中方括号中的符号),然后在字符数组中读取最多16个字符。

在格式字符串中,符号*是赋值抑制字符。

这是一个演示程序。为了可见性,我使用sscanf 而不是fscanf

#include <stdio.h>

int main( void ) 

    const char *stream = "::: : : : :::Hello";
    char s[17];
    
    sscanf( stream, "%*[: ]%16s", s );
    
    printf( "\"%s\"\n", s );

    return 0;

程序输出是

"Hello"

【讨论】:

【参考方案2】:

它读取任何空格或:(冒号)字符,然后丢弃它们,然后将最多 16 个非空白字符读入dest(17 个包括空终止符 \0)。

% 之后的 * 是“赋值抑制字符”。 %s 之间的数字是“最大字段宽度”。 方括号表示匹配其中的字符或除这些字符之外的所有字符(带有插入符号)。破折号和插入符号经过特殊处理。

来自 scanf 的 Linux 手册页:

格式中的每个转换规范都以字符“%”或字符序列“%n$”开头 (区别见下文)后跟:

· 可选的 '*' 赋值抑制字符: scanf() 按照转换的指示读取输入 规范,但丢弃输入。不需要相应的指针参数,并且此规范不包括在 scanf() 返回的成功分配计数中。 [剪辑]

· 一个可选的十进制整数,它指定最大字段宽度。 字符读取停止 达到此最大值或找到不匹配字符时,以先发生者为准。 大多数转换会丢弃初始空白字符(例外情况如下所述),并且这些 丢弃的字符不计入最大字段宽度。字符串输入转换存储一个终止空字节('\0')来标记输入的结束;最大字段宽度不包括此终止符。

以下转换说明符可用:

[剪辑]

s 匹配一系列非空白字符; next 指针必须是指向字符数组的初始元素的指针,该元素的长度足以容纳输入序列和自动添加的终止空字节 ('\0')。输入字符串在空白处或最大字段宽度处停止,以先发生者为准。

[剪辑]

[ 匹配指定的可接受字符集中的非空字符序列; next 指针必须是指向 char 的指针,并且必须有足够的空间容纳字符串中的所有字符,外加一个终止空字节。前导空白的通常跳过被抑制。字符串由特定集合中(或不在)中的字符组成;该集合由左括号 [ 字符和右括号 ] 字符之间的字符定义。如果左括号后的第一个字符是抑扬符 (^),则该集合排除这些字符。要在集合中包含右括号,请将其作为左括号或抑扬符之后的第一个字符;任何其他位置将结束该组。连字符 - 也很特殊;当放置在其他两个字符之间时,它会将所有中间字符添加到集合中。要包含连字符,请将其设为最后一个右括号之前的最后一个字符。例如,[^]0-9-] 表示集合“除了右括号、0 到 9 和连字符之外的所有内容”。字符串以出现不在(或者,带有抑扬符,in)集中的字符或字段宽度用完时结束。

– scanf(3) 的 Linux 手册页

【讨论】:

【参考方案3】:

"%*[: ]%16s" 格式字符串说明符有什么作用?

    "%*[: ]":读取并丢弃(由于"*"scan_set至少一个输入字符:':'' '。如果没有找到':'' ',则停止扫描。

    "%16s" 有 3 个步骤:1) 读取并丢弃任何(0 个或更多)前导空格。例如' ''\n''\t' 等 2) 读取并保存到 dest至少一个但不超过 16 个非空白 - 否则停止扫描。 3) 将 null 字符 附加到dest。因此dest 至少应为 17:char dest[16+1];


高级

fscanf()sscanf() 的一个奇怪区别在于,当 sscanf() 读取 空字符 时,扫描会停止。使用fscanf(),继续扫描。

fscanf(file "%s", dest)'\t','1','2','3','\0','x','y','z',@987654@的8个字符文件数据将得到'1''2''3''\0''x''y''z''\0'。文本文件中出现空字符是不常见的。

【讨论】:

以上是关于当与 fscanf 配对时,这个格式字符串究竟做了啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 fscanf 之前初始化空指针

C语言fscanf/fprintf函数(格式化读写文件)的用法(%[]和%n说明符)

fscanf()函数详解&&fprintf()

scanf sscanf fscanf

c语言:fscanf(fp,"%*[^\n]")为啥可以跳过全部字符直到下一个换行符

fscanf(fp,"%*s%*s"); 啥意思?