【问题标题】:Using fscanf with a while loop to store a char and int使用 fscanf 和 while 循环来存储 char 和 int
【发布时间】:2018-11-12 01:52:27
【问题描述】:

我正在尝试使用 fscanf 读取十六进制数字的文件,该文件要么有一个字符后跟数字,要么只有数字而没有字符。 fscanf 似乎适用于文件的第一行,但仅此而已。

文件

E10
20
22
18
E10
210
12

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char** argv) {
FILE * iFile;
char instr;
unsigned long long int address;

iFile = fopen("addresses.txt", "r");
if(iFile != NULL){

    while (fscanf(iFile, "%c%x", &instr, &address) > 0){

      printf("%c", instr);   //This just works for the first line

    }

}
fclose(iFile);
return 0;
}

【问题讨论】:

  • 当您说它对第一行“有效”时,您就暗示它对后续行“无效”。请定义你的意思。你看到了什么行为?你期望什么行为?
  • @paddy 所以文件的第一行是 E10 所以 instr 应该打印出 E,它确实如此。但是当它到达文件的第 5 行时,又是 E10,那个 E 没有出现。
  • 第 2 行、第 3 行和第 4 行显示什么?我的猜测是它会写入上次读取%x 后留在流中的换行符。如果您使用调试器单步调试程序或添加额外的输出(例如 fscanf 返回的内容,或 address 中的值),您可能会自己弄清楚发生了什么。
  • @paddy 我想通了,只需要在第一个 % 前面添加一个空格
  • 您使用了错误的格式说明符,%x 用于 unsigned int

标签: c while-loop scanf


【解决方案1】:

在这种情况下,您将尝试多次解析同一行,最好将该行读入内存,然后处理内存中的数据,而不是磁盘上的数据。

char line[MAXLINE];
fgets(line, MAXLINE, iFile);

然后你就有了我所说的“sscanf 阶梯”,它是一系列if-else if 子句,每个子句都试图以不同的方式解析line。该条件将检查sscanf 的返回值,因为成功读取的对象数就是返回值。所以我们用这个数字来区分几种不同的格式:

if (sscanf(line, "%c%x", &instr, &address) == 2)
    /* you have an instruction and an address */
else if (sscanf(line, "%x", &address) == 1)
    /* you have an address only */

由于在您的情况下,这是一个循环条件,您必须将其重构为它自己的函数:

int readAtLeastAddress(const char *const line, char *instr, unsigned long long *address)
{
    return sscanf(line, "%c%x", instr, address) == 2 || sscanf(line, "%x", &address) == 1;
}

然后你会这样重写循环

while (readAtLeastAddress(line, &instr, &address)) {
    printf("%c", instr);
}

【讨论】:

  • 部分好建议,但不实用,因为任何包含至少两个字符且第二个字符是数字的输入都将匹配%c%x 模式。逐行阅读当然是正确的开始方式,但在这种情况下解释该行的逻辑应该是使用 isalphaisdigit 之类的东西来测试该行的第一个字符。
  • 你使用了错误的格式说明符,%xunsigned int
猜你喜欢
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 1970-01-01
相关资源
最近更新 更多