1

So I'm having issues right now with my program. I'm trying to get it to open a file count the lines rewind and then go through the file to store the variables. String String String int is the format of the file but I'm having issues after I count the lines. I can print the numbers to the screen but then I get a seg fault right after the print. I don't know why

int countLines(FILE * fin){
int count=0;
char street[100];
char city[100];
char state[3];
int zip;

do{
    fgets(street, 100, fin);
    fgets(city, 100, fin);
    fgets(state, 3, fin);
    fscanf(fin, "%d\n", &zip);
    count++;
}while(!feof(fin));

rewind(fin);

return count;

}

lines=countLines(fin); is how I call the function. What am I doing wrong?

kevorski
  • 816
  • 1
  • 11
  • 29
  • fgets reads entire line until the end of file or newline. Are your "String String String int" values line by line or all in one line? – taneryilmaz Nov 23 '13 at 04:55
  • it's one line for each entry. String\n String\n String\n int\n – kevorski Nov 23 '13 at 04:59
  • Not checking *any* of those `fgets()` calls, nor `fscanf()`, for result codes should be put at the top of your list of "what-i'm-doing-wrong", followed shortly thereafter by using `feof()` as a break condition in a while-loop, [which is nearly always wrong.](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong) – WhozCraig Nov 23 '13 at 06:43

2 Answers2

2

Do not mix fgets() with fscanf() until you are very comfortable with these functions. They do not play well together. That \n in the format is a white space and will match any number of consecutive white space including multiple \n, spaces, tabs, etc.

// fscanf(fin, "%d\n", &zip);

Recommend avoiding feof() and using the return value from fgets().

feof() does not become true until a file read is attempted and fails to provide a char. This is different than "true when none left". Example: you read the last char of a file. feof() is still false. Code attempts to read more (and fails). Now feof() is true. (and remains true).

Do count the lines in a simple fashion and use symmetry. Further consider more error checking. Read the zip code line as a string and then parse it as an integer.

int countLines(FILE * fin){
  int count=0;
  char street[100];
  char city[100];
  char state[100];
  char zips[100];
  unsigned zip;

  while (fgets(street, sizeof street, fin) != NULL) {
    count++;
  }
  rewind(fin);

  if (count%4 != 0) Handle_LineCountNotMultipleof4();

  // You could return here, but let's read the file again and get the data.
  // This is likely part of OP's next step.
  for (int i=0; i<count; i += 4) {
    if ((NULL == fgets(street, sizeof street, fin)) ||
      (NULL == fgets(city,   sizeof city, fin)) ||
      (NULL == fgets(state,  sizeof state, fin)) ||
      (NULL == fgets(zips,   sizeof zips, fin)) ||
      (1 != sscanf(zips, "%u", &zip))) handle_error();
    // Remember street, city, state, still have an ending \n
    do_something(street, city, state, zip);
  }
  return count;
}

Alternatively, to count the lines use the following. A singular difficulty occurs in reading if you have long lines, so let's check that as we go. Take this out line length stuff if you prefer a simple answer. You could use the Maxline+1 as you buffer size instead of a fixed 100.

  size_t Maxline = 0;
  size_t Curline = 0;
  int ch;
  while ((ch = fgetc(fin)) != EOF) {
    Curline++;
    if (ch == '\n') {
      count++;
      if (Curline > Maxline) MaxLine = Curline;
      Curline = 0;  
    }
  }
  if ((Maxline + 1) > 100) TroubleAhead() ; // Trouble with future (fgets(buf, 100, fin), use bigger buffers
  rewind(fin);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • when I try to get the values stored into the variables (street, city, state, zip) I get a segmentation fault after the function call of countLines. What causes that? It's after I print the number to the screen. Is it because of the trailing \n? How do you remove the trailing \n from an int? – kevorski Nov 23 '13 at 17:23
  • @kevorski For debug, let `do_something()` be `printf("s:<%s> c:<%s> S:<%s> z:<%u>\n", street, city, state, zip)`. Double check your and my usage of `zips` (a char array) and `zip` (an integer). – chux - Reinstate Monica Nov 23 '13 at 19:17
  • I got it working. Just having issues elsewhere now haha – kevorski Nov 23 '13 at 19:20
  • @kevorski Oh happy day! – chux - Reinstate Monica Nov 23 '13 at 19:21
0

fgets tries to read a whole line,not just a word, which seems to be what you are hoping for. So, the buffers you are passing it arent big enough, and they won't get what you were hopign for and you are incrementign the count once for every 3 lines and fscan usually wont read a line leaving the remains of that line to interfere with your next read.

If you want to read words, try scanf, with %s. If you want to read a fixed number of chars, try fread.

RichardPlunkett
  • 2,998
  • 14
  • 14
  • I know I'm doing an increment once every 4 lines. I'm using a struct to which is street city state zip. can you give example of scanf? Right now I just get a blank screen once I input the file name @RichardPlunkett – kevorski Nov 23 '13 at 05:05