读取String中的fscanf问题

时间:2009-12-12 14:42:48

标签: c scanf

我正在读一个.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);

这允许我读入没有空格的字符串。但是当我得到一个带有空格的“名字”时,它就不起作用了。

5 个答案:

答案 0 :(得分:12)

这有一个问题:

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在其格式说明符(空格,换行符或制表符)中找到空格时,它会消耗尽可能多的空格(即您可以认为它消耗了与正则表达式匹配的最长字符串{{1} })。

最后,您还应指定最大长度以避免缓冲区溢出。您可以通过将缓冲区长度放在[ \t\n]*%之间来实现。例如,如果[是256个字符的缓冲区,则应该执行以下操作:

ap->name

这适用于静态分配的数组;遗憾的是,如果数组在运行时具有动态大小,那么将缓冲区大小传递给result = fscanf(fp, "%255[^\n]%*c", ap->name); 并不容易。您必须使用fscanf创建格式字符串,例如:

sprintf

答案 1 :(得分:2)

Jumm写道:

  

如果我在fscanf的位置使用fgets,我会在变量中得到“\ n”。

这是一个更容易解决的问题,所以请继续使用:

fgets( ap->name, MAX, fp ) ;
nlptr = strrchr ( ap->name, '\n' ) ;
if( nlptr != 0 )
{
    *nlptr = '\0' ;
}

答案 2 :(得分:0)

我不确定你的意思[^ \ n]是否可以起作用。 []是一个修饰符,表示“接受一个字符,除了该块内的任何字符”。 ^反转条件。使用fscanf的%s仅在读取分隔符时才会读取。对于包含空格和换行符的字符串,请改为使用fgets和sscanf的组合,并指定长度限制。

答案 3 :(得分:0)

没有我收集的这样的东西你试图在fscanf函数中暗示一个不存在的正则表达式,不是我所知道的,也不是我在任何地方看过它 - 启发我这一点。

读取字符串的格式说明符是%s,可能需要这样做,%s\n将获取换行符。

但是对于皮特而言,不要使用Clifford上面的答案所规定的标准旧gets家族函数,因为这是缓冲区溢出发生的地方,并用于1990年代臭名昭着的蠕虫病毒 - 莫里斯蠕虫,更具体地说是fingerd守护进程,曾经叫gets导致混乱。幸运的是,现在已经修补了。此外,许多程序员已经深入研究了不使用该功能的心态。

即使Microsoft采用了gets系列函数的安全版本,也指定了一个参数来指示缓冲区的长度。

修改 我的坏 - 我没有意识到Clifford确实指定了输入的最大长度......哎呀!抱歉!克利福德的答案是对的!所以+1来克利福德的答案。

感谢Neil指出我的错误......

希望这有帮助, 最好的祝福, 汤姆。

答案 4 :(得分:-1)

我发现了问题。

正如Paul Tomblin所说,我在上面的领域有一个额外的新线字符。所以使用tommieb75所说的我用过:

result = fscanf(fp, "%s\n", ap->code);
result = fscanf(fp, "%[^\n]s", ap->name);

这就解决了!

感谢您的帮助。