fscanf 打印未知值

fscanf printing unknown values

我正在尝试使用 fscanf 获取文本文件并以相同的格式简单地打印它(最终它将用于填充结构数组)。

当我使用 fscanf 时,它会打印一些不属于文本的值,我不确定它们来自哪里。我在代码部分下面放了一小部分输入文本文件和输出。

我想在页面上水平打印的值都在输出的第一列中,这让我觉得这与我定义 fprint 语句的方式有关?第一列中的每个正确值后面都有我不知道从哪里来的值。

如有任何帮助,我们将不胜感激。

#include <stdlib.h>

int count_lines(char file[]) {

  FILE* f = fopen(file, "r");          /* declaration of file pointer */
  char x;
  int c = 0;                                      /* declaration of variable */
  f = fopen(file, "r");
  if (f == NULL) {
    printf("Cannot open file for reading");
    return -1;
  }
  while ((x = fgetc(f)) != EOF) {
    if (x == '\n') {
      c = c + 1;
    }
  }
  if (fclose(f) != 0) {
    printf("File could not be closed.\n");
    return -1;
  }
  printf("Number of lines = %d\n", c);
  return c;
}

struct votes {
  char state[100];     /* state name */
  long dempv;          /* democrats popular votes */
  long demev;          /* democrats electoral votes */
  long reppv;          /* republicans popular votes */
  long repev;          /* republicans electoral votes */
};

void initialise_votes(char file[], struct votes* arr, int nlines) {
  FILE* f = fopen(file, "r");
  char temp1[20];
  long temp2;
  long temp3;
  long temp4;
  long temp5;

  if (f == NULL) {
    printf("Cannot open file for reading\n");
  }

  while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) != EOF) {
    printf("%s\t%ld\t%ld\t%ld\t%ld\n", temp1, temp2, temp3, temp4, temp5);
  }

  if (fclose(f) != 0) {
    printf("File could not be closed.\n");
  }
}


int main(void) {
  char s_in[] = "uselection2012.txt"; /* input data file */
  int nlines;
  struct votes* arr;

  nlines = count_lines(s_in);
  arr = (struct votes*)malloc(sizeof(struct votes) * nlines);

  initialise_votes(s_in, arr, nlines);

  return 0;
}

输入文件:

Alabama 795696 0 1255925 9
Alaska 122640 0 164676 3
Arizona 1025232 0 1233654 11
Arkansas 394409 0 647744 6
California 7854285 55 4839958 0

输出:

Alabama 6356696 -37862896       6380    0
795696  6356696 -37862896       6380    0
0       6356696 -37862896       6380    0
1255925 6356696 -37862896       6380    0
9       6356696 -37862896       6380    0
Alaska  6356696 -37862896       6380    0
122640  6356696 -37862896       6380    0
0       6356696 -37862896       6380    0
164676  6356696 -37862896       6380    0
3       6356696 -37862896       6380    0
Arizona 6356696 -37862896       6380    0
1025232 6356696 -37862896       6380    0
0       6356696 -37862896       6380    0
1233654 6356696 -37862896       6380    0
11      6356696 -37862896       6380    0
Arkansas        6356696 -37862896       6380    0
394409  6356696 -37862896       6380    0
0       6356696 -37862896       6380    0
647744  6356696 -37862896       6380    0
6       6356696 -37862896       6380    0
California      6356696 -37862896       6380    0
7854285 6356696 -37862896       6380    0
55      6356696 -37862896       6380    0
4839958 6356696 -37862896       6380    0
0       6356696 -37862896       6380    0

您的 scanf 格式字符串包含逗号,但您的输入数据不包含逗号。

请注意,fscanf returns 要么是 EOF,要么是成功扫描的值的数量。您可以而且应该使用该 return 值来检查错误,这样做会指出您代码中的问题。

fscanf 格式字符串中的逗号告诉 fscanf 期待文件中有逗号,如果找不到则停止。

您的文件中没有逗号,因此 fscanf 在读取用于 %s 转换的“字符串”后停止。

从格式字符串中删除逗号。

测试 fscanf 的 return 值是否等于您期望分配的项目数,而不仅仅是它不等于 EOF.

可避免的编码弱点导致 OP 的难度

如果代码根据预期结果 5 检查 return 值,而不是检查 EOF, 0, 1, 2, 3, 4 等众多不正确结果之一,问题将很快缩小为 scanf 失败。

// while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) != EOF) {
while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {

其他问题

白-space

没有价值,除了可能的风格,在 "%ld" 之前放置 " " 因为 "%ld" 已经消耗了可选的前导白色-space.

然而,在 "," 之前放置一个 space 是有价值的,以允许在 ','.

之前输入可选的前导白色-space
while (fscanf(f, "%s ,%ld ,%ld ,%ld ,%ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {

缓冲区溢出

切勿在 (f)scanf() 函数中使用 "%s"。使用 宽度 限制,否则有缓冲区溢出的风险。

// width   --------vv
while (fscanf(f, "%19s ,%ld ,%ld ,%ld ,%ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {

fgetc() return一个int

fgetc(f) returns 257 个不同的值。使用一个int来正确区分。

// char x;
int x;
...
while ((x = fgetc(f)) != EOF) {

行数可能会失败

Count of lines 只计算了 '\n' 的行数。如果文件只包含 "abc 1 2 3 4",没有 '\n',行数将报告为 0.

而是计算行首的数量。

count = 0;
int prior = '\n';
while ((x = fgetc(f)) != EOF) {
  if (prior == '\n') {
    count++;
  }
  prior = x;
  ...
}