2009-12-12 56 views
4

我正在阅读.txt文件。我使用fscanf在格式化后获取数据。 我有问题的线路是这样的:阅读字符串fscanf问题

result = fscanf(fp, "%s", ap->name); 

这是罚款,直到我有一个空格如姓名:圣艾夫斯 所以我用这个在白色空间为:

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); 

这让我在没有空格的字符串读取。但是当我得到一个带有空格的“名称”时,它不起作用。

+0

是否有可能在文件中有额外的换行符? – 2009-12-12 14:57:34

回答

0

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

2

Jumm写道:

如果我使用的的fscanf的地方与fgets上面我在变量得到 “\ n”。

这是解决一个更容易的问题,所以用它去:

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

fgets()没有问题,因为它的第二个参数设置了大小限制 - 你正在考虑gets()。 – 2009-12-12 15:12:13

+0

我在回复尼尔的评论时删除了我的评论,因为我是不正确的,并且在这里跳枪的道歉...是的,的确,你是正确的尼尔......需要咖啡因踢...... :) – t0mm13b 2009-12-12 15:14:46

+1

删除你的评论,你只是让尼尔的评论看起来像是对我的博文的批评,我认为这不是他的意图。 – Clifford 2009-12-12 16:33:42

0

有没有这样的事情,因为我收集你想暗示不存在fscanf功能的正则表达式,不是我的知识,也没有我看到它 - 在这方面给我启发。

用于读取字符串的格式说明符是%s,可能是因为您需要这样做,%s\n会选择换行符。

但是对于皮特的缘故不使用标准的旧gets家庭功能 如克利福德的回答上面 为指定的地方缓冲区溢出发生在20世纪90年代的一个臭名昭著的蠕虫使用 - 莫里斯蠕虫,更特别是在fingerd守护进程,用于调用gets,导致混乱。现在幸运的是,现在已经修补了。此外,很多程序员都钻入了不使用函数的思路。

即使微软已经通过gets家庭的功能,即指定参数,以指示缓冲区的长度,而不是一个安全的版本。

编辑 我的坏 - 我并没有意识到,克利福德的确已指定用于输入的最大长度...哎呦!抱歉!克利福德的回答是正确的!所以+1给克利福德的答案。

感谢尼尔指出我的错误...

希望这有助于 最好的问候, 汤姆。

+0

错误 - 请参阅我对克利福德的回答的评论。 – 2009-12-12 15:13:00

+0

这适用于单个字符串,但有空白的字符串不适用。感谢额外的信息,但= = – jumm 2009-12-12 15:16:16

0

我发现这个问题。

正如保罗汤布林说,我曾在上述领域的一个额外的换行字符。所以使用什么tommieb75说我用过:

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

而这个固定它!

感谢您的帮助。

+0

如果你这样做,请确保ap-> code和ap-> name有足够的存储空间。 – 2009-12-12 19:45:44

11

一个问题是:

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);