简体   繁体   中英

fscanf printing unknown values

I am trying to use fscanf to take a text file and simply print it in the same format (eventually it will be used to populate an array of structures).

When I use fscanf it prints some values which are not part of the text and I'm not sure where they are coming from. I have put a small part of the input text file and the output below the code section.

The values I want to print across the page horizontally are all in the first column of the output, which makes me think that its something to do with how I have defined my fprint statement? Each of the correct values in the first column are followed by values which I don't know where have come from.

Any help would be greatly appreciated.

#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;
}

Input file:

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

Output:

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

Your scanf format string includes commas, but your input data does not.

Note that fscanf returns either EOF, or the number of values successfully scanned. You can and should use that return value to check for errors, and doing so would have pointed you to the problem in your code.

The commas in your fscanf format string tell fscanf to expect commas in the file and to stop if it does not find them.

There are no commas in your file, so fscanf stops after reading a “string” for the %s conversion.

Remove the commas from the format string.

Test that the return value of fscanf equals the number of items you expect to be assigned, not just that it is not equal to EOF .

Avoidable coding weakness lead to OP's difficulty

Had code checked the return value against the desired result of 5 rather than one of the many incorrect ones like EOF, 0, 1, 2, 3, 4 , the issue would have been quickly narrowed to a scanf failure.

// 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) {

Other issues

White-space

No value, other than maybe style, to put a " " before "%ld" as "%ld" already consumes optional leading white-space.

Yet there is value to put a space before the "," to allow for optional leading white-space input before the ',' .

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

Buffer overflow

Never use "%s" in a (f)scanf() function. Use a width limit, else risk buffer overflow.

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

fgetc() returns an int

fgetc(f) returns 257 different values. Use an int to correctly distinguish.

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

Line count may fail

Count of lines only counted the number of '\n' . Had the file only contained "abc 1 2 3 4" , with no '\n' , the line count would report as 0.

Instead count the number of line beginnings.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM