【问题标题】:How to write and read (including spaces) from text file如何从文本文件中读写(包括空格)
【发布时间】:2013-12-27 15:30:10
【问题描述】:

我正在使用fscanffprintf

我尝试用\t 分隔每一行的字符串,并像这样读取它:

fscanf(fp,"%d\t%s\t%s",&t->num,&t->string1,&t->string2);

文件内容:

1[TAB]string1[TAB]some string[NEWLINE]

它无法正确读取。如果我printf("%d %s %s",t->num,t->string1,t->string2) 我得到:

1 string1 some

我也收到了这个编译警告:

warning: format specifies type 'char *' but the argument has type 'char (*)[15]' [-Wformat]

如何在不使用二进制 r/w 的情况下解决此问题?

【问题讨论】:

  • “读取不正确”。 做什么“它”做什么?您是否正确分配了t 指向的任何内容(假设它键入的结构的成员也是正确的)?
  • 一会儿我会修改我的问题。

标签: c file-io scanf printf


【解决方案1】:

我猜"some string" 中的空格是问题所在。 fscanf() 使用%s 读取字符串在第一个空白字符处停止。要包含空格,请使用以下内容:

fscanf(fp, "%d\t%[^\n\t]\t%[^\n\t]", &t->num, &t->string1, &t->string2);

另请参阅a reference page for fscanf() 和/或another StackOverflow thread on reading tab-delimited items in C

[编辑以响应您的编辑:您传递给fscanf() 的参数似乎也有问题。您需要发布t->string1 的声明以确保,但看起来string1 是一个字符数组,因此您应该从fscanf() 调用中删除&...]

【讨论】:

  • 缓冲区溢出。你不能像这样读入任意长度的字符串。 fscanf应该如何知道t->string1t->string2指向的对象的大小(错误信息看起来&是错误的)?
  • 你对防止溢出有什么建议?
  • @MikeL 如果您不能保证输入字符串的最大大小并相应地分配缓冲区,您可以use width specifiers 强制执行最大字段长度。我应该将其包含在答案中,但这不是问题的主题,所以我掩盖了它。
【解决方案2】:

%s 转换规范在第一个空格处停止读取,并且制表符和空格都算作空格。

如果要读取非制表符的字符串,可以使用“扫描集”转换说明符:

if (fscanf(fp, "%d\t%[^\t\n]\t%[^\t\n]", &t->num, t->string1, t->string2) != 3)
    ...oops - format error in input data...

(我认为从字符串参数中省略 & 是正确的。)问题已被编辑;我赢了。删除& 是避免编译器警告的必要条件!

这仍然没有达到您的预期。如果第二个字段的开头有空格,它们将被格式字符串中的\t 吃掉。格式字符串中的任何空格都会占用输入中的任何空格(包括换行符)。 %[^\t] 转换规范只有在输入中出现非空白字符时才会开始。我还假设您希望您的输入受到换行符的限制。如果您愿意,可以省略 \n 字符。

请注意,我检查了 fscanf() 解释了 3 个字段。错误检查您的输入很重要。

如果您真的想要控制,您可能应该使用fgets() 读取整行,然后使用sscanf() 解析数据。


关于fgets()sscanf();您能否详细说明它将如何提供更多控制权?

假设输入数据被写入

1234



a string with spaces



another string

像这样分散在多行上。使用原始fscanf(),即使它分布在 9 行输入中,这也是可接受的输入。使用fgets(),您可以读取一行,然后使用sscanf() 对其进行分析,您会知道第一行的格式不正确。然后,您可以决定如何处理它。

另外,由于mafso 在他的comment 中调用了我,我们应该通过限制扫描集匹配的字符串的大小来确保没有缓冲区溢出。

if (fscanf(fp, "%d\t%14[^\t\n]\t%14[^\t\n]", &t->num, t->string1, t->string2) != 3)
    ...oops - format error in input data...

我正在使用关于 char (*)[15] 的错误消息来推断 14 是要使用的正确数字。请注意,与printf() 不同,您不能通过* 表示法指定大小(在scanf()-family,* 抑制分配),因此您必须创建具有正确大小的格式。此外,您指定的大小是终止空字节之前的字符数,因此如果数组的大小为 15,则您在格式字符串中指定的大小为 14,如图所示。

【讨论】:

  • fscanf 调用导致缓冲区溢出。
  • 是的,不...我不是,但我不确定它们不会溢出。如果没有字符串类型的定义,就很难知道要使用什么值——尽管一旦更新了问题,您可能会猜到%14[\t\n] 可能是合适的。
  • 删除并修复了问题,Jonathan 关于 fgets() 和 sscanf() 你能详细说明它将如何提供更多控制权吗?
猜你喜欢
  • 1970-01-01
  • 2023-01-01
  • 2021-10-16
  • 1970-01-01
  • 2018-05-18
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
相关资源
最近更新 更多