Home > OS >  Correct way to limit document read in C without !feof, document error cannot read the .txt
Correct way to limit document read in C without !feof, document error cannot read the .txt

Time:06-08

I've been doing this C program which requires reading .txt files and so on. I've been warned so many times by the community about avoiding !feof as loop parameter to define stop reading the files. I was just wonder how to actually do it correctly, but hey anything works is fine to me that day. Now I just found some unknown problem and looks like !feof finally make its problem on me. I wonder if the fault is really on !feof?

typedef struct City {
  char cityName[20];
  char cityID[10];
};

void readFiles() {
  //preparing .txt file to read
  char *txtMap = "map.txt";
  char *txtPrice = "deliver_price.txt";
  FILE *fmap = fopen(txtMap, "r");
  FILE *fprice = fopen(txtPrice, "r");
  City cityArr[20];                     //I've defined the typedef struct before
  int j, a = 0;

  if (fmap == NULL || fprice == NULL || fmap && fprice == NULL) {
    if (fmap == NULL) {
      printf("\n\n\n\t\t\t\t\tError: Couldn't open file %s\n\n\n\n\n\n\n",
          fmap);
      printf("\n\n\n\t\t\t\t\tPress enter to continue\n\t\t\t\t\t");

      return 1;
    } else if (fprice == NULL) {
      printf("\n\n\n\t\t\t\t\tError: Couldn't open file %s\n\n\n\n\n\n\n",
          fprice);
      printf("\n\n\n\t\t\t\t\tPress enter to continue\n\t\t\t\t\t");

      return 1;
    }

  }

  while (!feof(fmap)) {
    City newCity;

    fscanf(fmap, "%[^#]||%[^#]\n", &newCity.cityName, &newCity.CityID);
    cityArr[a] = newCity;
    a  ;
  }
  printf("reading file succesfull");
  fclose(fmap);

  for (j = 0; j < a; j  ) {
    printf("\n%s || %s\n", cityArr[j].cityName, cityArr[j].cityID);
  }
  getch();
}

The text files need to be read:

New York||0
Washington D.C||1
Atlanta||2
Colombus||3

This program cannot read the files properly and making the program crash returning memory number. Anyone knows what's wrong with this program?

Sometimes when I tried fixing it, it says 'this part is a pointer, maybe you meant to use ->' error stuff. I don't know why this happen because in previous code, where I copied the file processing code part from, it doesn't happen like this.

CodePudding user response:

Code has various troubles including:

Code not compiled with all warnings enabled

Save time. Enable all warnings.

Wrong use of feof()

See Why is “while ( !feof (file) )” always wrong?.

No width limit

"%[^#]" risks reading to much into &newCity.cityName.

Wrong type

"%[^#]" matches a char *. &newCity.cityName is not a char *.

Incorrect format

"%[^#]||%[^#]\n" will only match text that begins with a non-'#' and then up to, but not including a '#') followed by a '|' - which is impossible.

Consuming more than 1 line

"\n" reads any number of lines or white space.

Code is not checking the return value of input functions

Unlimited lines

Code can attempt to read more than 20 lines, yet City cityArr[20]; is limited.


Some corrections:

  while (a < 20) {
    City newCity;

    int count = fscanf(fmap, "[^|]||%9[^\n]%*1[\n]",
        newCity.cityName, newCity.CityID);
    if (count != 2) break;

    cityArr[a] = newCity;
    a  ;
  }

Better

  // Size line buffer to about 2x expected maximum
  #define LINE_SIZE (sizeof(struct City)*2   4)
  char buf[LINE_SIZE];

  while (a < 20 && fgets(buf, sizeof buf, fmap)) {
    City newCity;
    int n = 0; 
    sscanf(buf, "[^|]||%9[^\n] %n", newCity.cityName, newCity.CityID, &n);
    if (n == 0 || buf[n] != '\0') {
      fprintf(stderr, "Bad input line <%s>\n", buf);
      return -1;
    }
    cityArr[a] = newCity;
    a  ;
  }

Wrong test

fmap && fprice == NULL is not what OP wants. Review operator precedence.

// if(fmap == NULL || fprice == NULL || fmap && fprice == NULL){
if (fmap == NULL || fprice == NULL) {

Useful to post exact errors

Not "it says 'this part is a pointer, maybe you meant to use ->' error stuff."

Return from void readFiles()?

Code attempts return 1;. Use int readFiles().

FILEs not closed

Add fclose( name ) when done with file.

  • Related