Danny54089
Danny54089

Reputation: 1

fscanf consumes first letter in file. How do I fix it?

I am making a program for a class that reads the contents of a .csv file. I am using a while loop inside of a for loop to scan the contents into two separate arrays, and when it prints the contents, everything is right, except it is missing the first letter in the file. We are not allowed to use any functions from the library except what is permitted.

Code in question:

void readFile(FILE *fptr, int size)
{
  int i, a;
  a = size / 2;
  printf("number of lines in readFile is %d:\n", size);
  double y[50];
  char x[50];
  for (i = 0; i < a; i++)
    {
      while (fscanf(fptr,"%c,%lf,", &x[i], &y[i]) ==2);
    }
  printf("%c, %.2lf: ", x[0], y[0]);
  //a loop to make sure it scanned properly by displaying array contents
  for (i = 0; i < a; i++)
    {
      printf("%c, %.2lf:\n", x[i], y[i]);
    }
}

I tried with no luck to !feof(fptr), != EOF, but these are not supposed to be used in the intro class I am taking. I am out of ideas to fix it. This is the output of the program above:

number of lines in readFile is 4:
, 20.00: 
, 20.00:
E, 30.00:
number of lines is 4:

Upvotes: 0

Views: 54

Answers (1)

Craig Estey
Craig Estey

Reputation: 33621

A few issues ...

  1. The fscanf format is wrong. It needs a leading space to skip over newlines.
  2. Unless you intend to operate on the data read in readFile (vs. passing it back to caller), having function scoped x and y arrays will go out of scope when the function returns.
  3. The caller of readFile should pass the maximum array count but let the function determine the actual number of entries.
  4. Whenever I see two or more "parallel" arrays [indexed by the same variable], I would use a struct. Particularly for .csv data.
  5. .csv files are of the form: a,b\nc,d\n and not a,b,\nc,d,\n so the trailing , in the fscanf is incorrect.
  6. Using nested loops for the data input doesn't work.
  7. No need for feof. Just loop until the fscanf return is not 2.

Here is the corrected code. It is annotated:

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

// data for single .csv line
struct data {
    char x;
    double y;
};

// readFile -- read in .csv file
// RETURNS: count of records/lines read
size_t
readFile(FILE *fptr, struct data *arr, size_t size)
// fptr -- open file stream
// arr -- pointer to data array
// size -- maximum number of elements in arr
{
    int count = 0;

    while (1) {
        // check for overflow of array
        if (count >= size) {
            fprintf(stderr,"readFile: too much data for array\n");
            exit(1);
        }

        // point to current struct/record
        struct data *cur = &arr[count];

        // read in the .csv line -- stop on error or EOF
        if (fscanf(fptr, " %c,%lf", &cur->x, &cur->y) != 2)
            break;

        // advance the count of the number of valid elements
        ++count;
    }

    return count;
}

int
main(int argc,char **argv)
{
    struct data arr[50];

    // skip over program name
    --argc;
    ++argv;

    if (argc != 1) {
        printf("wrong number of arguments\n");
        exit(1);
    }

    // open the input file
    FILE *fptr = fopen(argv[0],"r");
    if (fptr == NULL) {
        perror(argv[0]);
        exit(1);
    }

    // read in the data lines
    size_t count = readFile(fptr,arr,sizeof(arr) / sizeof(arr[0]));
    fclose(fptr);

    // print the array
    for (size_t idx = 0;  idx < count;  ++idx) {
        struct data *cur = &arr[idx];
        printf("%c, %.2f:\n",cur->x,cur->y);
    }

    return 0;
}

Here is the sample input I used to test the program:

J,23
D,37.62
F,17.83

Here is the program output:

J, 23.00:
D, 37.62:
F, 17.83:

Upvotes: 1

Related Questions