读取String中的fscanf问题
我正在读一个.txt文件。 我正在使用fscanf来获取格式化的数据。 我遇到问题的这条线是这样的:
result = fscanf(fp, "%s", ap->name);
这是好的,直到我有一个空格的名称,例如:St Ives所以我用它来读取空白区域:
result = fscanf(fp, "%[^\n]s", ap->name);
但是,当我尝试读取名字(没有空白区域)时,它只是不起作用并且弄乱了其他的fscanf。
但我使用[^ \ n]它在我正在使用的不同文件中工作正常。 不知道发生了什么。
如果我在fscanf的位置使用fgets,我会在变量中得到“\ n”。
编辑//
好的,如果我使用:
result = fscanf(fp, "%s", ap->name); 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);
%*c
说明符表示读入字符( c
),但不将其分配给任何变量( *
)。 如果省略了*
,则必须传递fscanf()
另一个包含指向字符( 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);
Jumm写道:
如果我在fscanf的位置使用fgets,我会在变量中得到“\ n”。
这是一个更容易解决的问题,所以顺其自然:
fgets( ap->name, MAX, fp ) ; nlptr = strrchr ( ap->name, '\n' ) ; if( nlptr != 0 ) { *nlptr = '\0' ; }
我不确定你的意思是[^ \ n]假设工作。 []是一个修饰符,表示“接受一个字符, 除了该块内的任何字符”。 ^
反转条件。 带有fscanf的%s只读取,直到遇到分隔符。 对于包含空格和换行符的字符串,请改为使用fgets和sscanf的组合,并指定长度限制。
没有这样的东西,我收集到你试图在fscanf
函数中暗示一个不存在的正则表达式,不是我所知道的,也不是我在任何地方看过它 – 启发我这一点。
读取字符串的格式说明符是%s
,可能需要这样做, %s\n
将获取换行符。
但是对于皮特而言,不要使用Clifford上面的答案所规定的标准旧的gets
家庭function,因为这是缓冲区溢出发生的地方,并且被用于1990年代的臭名昭着的蠕虫 – 莫里斯蠕虫,更具体地说是fingerd
守护进程中使用的打电话gets
那造成混乱。 幸运的是,现在已经修补了。 此外,许多程序员已经深入研究了不使用该function的心态。
甚至微软也采用了一系列函数的安全版本,它指定了一个参数来代表缓冲区的长度。
编辑我的坏 – 我没有意识到Clifford确实指定了输入的最大长度……哎呀! 抱歉! 克利福德的答案是对的! 所以+1来克利福德的回答。
谢谢尼尔指出我的错误……
希望这会有所帮助,最好的问候,汤姆。
我发现了问题。
正如Paul Tomblin所说,我在上面的领域有一个额外的新线条。 所以使用tommieb75说我用过的:
result = fscanf(fp, "%s\n", ap->code); result = fscanf(fp, "%[^\n]s", ap->name);
这固定了!
谢谢你的帮助。