这样做的一个问题:
result = fscanf(fp, "%[^\n]s", ap->name);
是s您的格式说明符末尾有一个额外的内容。整个格式说明符应该只是%[^\n],它表示“读取由非换行符组成的字符串”。extras不是格式说明符的一部分,因此它被解释为文字:“从输入中读取下一个字符;如果是“s”,则继续,否则失败。”
不过,额外的东西s实际上并没有伤害到你。您确切地知道输入的下一个字符是什么:换行符。它不匹配,输入处理在那里停止,但这并不重要,因为它是格式说明符的结尾。但是,如果在同一格式字符串中此格式说明符之后还有其他格式说明符,这将导致问题。
真正的问题是您没有使用换行符:您只是在读取换行符之前的所有字符,而不是换行符本身。要解决这个问题,你应该这样做:
result = fscanf(fp, "%[^\n]%*c", ap->name);
说明%*c符表示要读入一个字符 ( c),但不要将它分配给任何变量 ( *)。如果省略*,则必须传递fscanf()另一个包含指向字符 (a char*) 的指针的参数,然后它将存储读取的结果字符。
您也可以使用%[^\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);