在字符串中读取的fscanf问题
我正在读一个.txt文件。我正在使用fscanf获取格式化后的数据。 我遇到的问题是:在字符串中读取的fscanf问题,c,scanf,C,Scanf,我正在读一个.txt文件。我正在使用fscanf获取格式化后的数据。 我遇到的问题是: result = fscanf(fp, "%s", ap->name); 这是好的,直到我有一个空白的名字,例如:圣艾夫斯 所以我用这个在空白处读: result = fscanf(fp, "%[^\n]s", ap->name); 然而,当我试着读第一个名字(没有空格)时,它就是不起作用,并且弄乱了另一个fscanf 但是我使用[^\n]它在我使用的另一个文件中运行良好。不知道发生了什么 如
result = fscanf(fp, "%s", ap->name);
这是好的,直到我有一个空白的名字,例如:圣艾夫斯
所以我用这个在空白处读:
result = fscanf(fp, "%[^\n]s", ap->name);
然而,当我试着读第一个名字(没有空格)时,它就是不起作用,并且弄乱了另一个fscanf
但是我使用[^\n]它在我使用的另一个文件中运行良好。不知道发生了什么
如果我使用fgets代替上面的fscanf,则变量中会出现“\n”
编辑//
好的,如果我使用:
result = fscanf(fp, "%s", ap->name);
result = fscanf(fp, "%[^\n]s", ap->name);
这允许我在没有空白的字符串中读取。但是当我得到一个带有空格的“名称”时,它就不起作用了。我不确定你的意思是[^\n]应该如何起作用。[]是一个修饰符,表示“除此块中的任何字符外,接受一个字符”。
^
反转条件。%带fscanf的s仅在遇到分隔符之前读取。对于包含空格和换行符的字符串,请使用fgets和sscanf的组合,并指定长度限制。Jumm写道:
如果我使用fgets代替上面的fscanf,则变量中会出现“\n”
这是一个更容易解决的问题,因此请继续:
fgets( ap->name, MAX, fp ) ;
nlptr = strrchr ( ap->name, '\n' ) ;
if( nlptr != 0 )
{
*nlptr = '\0' ;
}
据我所知,在
fscanf
函数中,没有一个正则表达式是不存在的,我也没有在任何地方看到过它——请告诉我这一点
用于读取字符串的格式说明符是%s
,可能是您需要这样做,%s\n
将拾取换行符
但看在皮特的份上,不要使用Clifford在上面的回答中指定的标准旧的get
家族函数,因为这是缓冲区溢出发生的地方,并且在20世纪90年代的一个臭名昭著的蠕虫中被使用过——莫里斯蠕虫,更具体地说是在fingerd
守护进程中,该守护进程用于调用导致混乱的get
。幸运的是,现在,这一问题已经得到解决。而且,许多程序员已经养成了不使用函数的心态
甚至微软也采用了一个安全版本的gets
函数族,它指定了一个参数来指示缓冲区的长度
编辑
我的错-我没有意识到Clifford确实指定了输入的最大长度…哇!很抱歉克利福德的回答是正确的!克利福德的答案是+1
谢谢尼尔指出我的错误
希望这有帮助,
顺致敬意,
汤姆。我发现了问题
正如Paul Tomblin所说,我在上面的字段中有一个额外的新行字符。所以用tommieb75说的话:
result = fscanf(fp, "%s\n", ap->code);
result = fscanf(fp, "%[^\n]s", ap->name);
这把它修好了
谢谢您的帮助。这有一个问题:
result = fscanf(fp, "%[^\n]s", ap->name);
就是在格式说明符的末尾有一个额外的s
。整个格式说明符应该是%[^\n]
,表示“读入由非换行字符组成的字符串”。额外的s
不是格式说明符的一部分,因此它被解释为文字:“从输入中读取下一个字符;如果是“s”,则继续,否则失败。”
不过,额外的s
实际上并不会伤害你。您确切地知道输入的下一个字符是什么:换行符。它不匹配,输入处理在那里停止,但这并不重要,因为它是格式说明符的结尾。但是,如果在此之后有其他格式说明符位于同一格式字符串中,则这将导致问题
真正的问题是你没有阅读新行:你只阅读到新行之前的所有字符,而不是新行本身。要解决此问题,您应该执行以下操作:
result = fscanf(fp, "%[^\n]%*c", ap->name);
result = fscanf(fp, "%255[^\n]%*c", ap->name);
%*c
说明符表示读入字符(c
),但不将其分配给任何变量(*
)。如果省略了*
,则必须传递另一个参数fscanf()
,该参数包含指向某个字符的指针(achar*
),然后它将存储读取的结果字符
您也可以使用%[^\n]\n
,但这也会读取换行后的任何空格,这可能不是您想要的。当fscanf
在其格式说明符(空格、换行符或制表符)中查找空白时,它将尽可能多地使用空白(即,您可以认为它使用与正则表达式匹配的最长字符串[\t\n]*
)
最后,还应指定最大长度以避免缓冲区溢出。您可以通过将缓冲区长度放置在%
和[
之间来完成此操作。例如,如果ap->name
是256个字符的缓冲区,则应执行以下操作:
result = fscanf(fp, "%[^\n]%*c", ap->name);
result = fscanf(fp, "%255[^\n]%*c", ap->name);
这对于静态分配的数组非常有效;不幸的是,如果数组在运行时动态调整大小,则无法将缓冲区大小传递给fscanf
。您必须使用sprintf
创建格式字符串,例如:
char format[256];
snprintf(format, sizeof(format), "%%%d[^\n]%%*c", buffer_size - 1);
result = fscanf(fp, format, ap->name);
您的文件中是否可能有一个额外的换行符?fgets()没有问题,因为它的第二个参数设置了一个大小限制-您考虑的是gets().我删除了我的评论以回应Neil的评论,因为我是不正确的,并为在这里跳枪道歉…是的,确实你是对的Neil…需要一杯咖啡因饮料…:)删除你的评论,你只是让Neil的评论看起来像是对我帖子的批评,我认为这不是他的意图。错-请看我对Clifford回答的评论。这适用于单个字符串,但不适用于包含空格的字符串。感谢您提供的额外信息=]如果您这样做,请确保ap->code和ap->name有足够的存储空间。此外,
s
在这里没有意义<代码>%[^\n]已请求除新行以外的所有字符。