这里面存在一个问题:
result = fscanf(fp, "%[^\n]s", ap->name);
你的格式说明符末尾多了一个额外的字符"s"。正确的格式说明符应该只是
%[^\n]
,意思是“读取一个由非换行符组成的字符串”。多余的字符"s"不是格式说明符的一部分,所以它被解释为字面量:“读取输入中的下一个字符;如果它是“s”,则继续,否则失败。”
然而,这个额外的字符"s"并不会对你造成实际伤害。你确切地知道输入的下一个字符是什么:一个换行符。它不匹配,并且输入处理停止在那里,但这并不重要,因为它是你的格式说明符的结尾。但是,如果在同一个格式字符串中,在此之后还有其他格式说明符,则会出现问题。
真正的问题是你没有消耗掉换行符:你只读取了所有字符,直到换行符,但没有读取换行符本身。要解决这个问题,你应该这样做:
result = fscanf(fp, "%[^\n]%*c", ap->name);
%*c
格式说明符表示读取一个字符(
c
),但是不将其赋值给任何变量(
*
)。如果省略了
*
,则必须向
fscanf()
传递另一个参数,该参数包含指向字符的指针(
char*
),
fscanf()
会将读取到的字符存储在其中。
您也可以使用
%[^\n]\n
,但这也会读取紧随换行符后的任何空格,这可能不是您想要的。当
fscanf
在其格式说明符中发现空格、换行符或制表符时,它会尽可能地消耗所有空格(即可以将其视为消耗与正则表达式
[ \t\n]*
匹配的最长字符串)。
最后,为避免缓冲区溢出,您还应指定最大长度。您可以通过将缓冲区长度放置在
%
和
[
之间来实现。例如,如果
ap->name
是一个256个字符的缓冲区,则应执行以下操作:
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);