Mabs 2001
Mabs 2001

Reputation: 13

fgets() gets more than it should in file reading - C

Currently I'm doing a practical work to collage in witch I have to read data from a file.

The file data structure is: "id name sex"

example:

nm0025630   Vikas Anand M
nm0418131   Victor Janson   M
nm0411451   Dick Israel M
nm0757820   Leopoldo Salcedo    M

To read the currently I'm using this code:

    fh = NULL;
    fh = fopen(ACTORS, "r");
    if (!fh) {
        exit(1);
    }
    while (!feof(fh)) {
        char sex, name[100], id[10];

        fgets(id, 10, fh);
        fgets(name, 100, fh);
        fgetc(sex);

        if (!feof(fh)) {
            hash_update_node(hash, get_id_num(id), name, sex);
            count++;
        }
    }

The problem is that it reads the name and the sex together. Any help is appreciated.

Upvotes: 1

Views: 113

Answers (2)

bruno
bruno

Reputation: 32586

fgets(name, 100, fh); reads up to 99 character, when the name has less than 98 character the sex is also read if it has onlt one space before.

Because the name is may be composed of several words separated by spaces one way is to read all the line then extract the sex.

Warning the first time you do while (!feof(fh)) { this is without any read before so feof cannot know if the file is empty or not then if you reach EOF or not. I encourage you to detect the EOF looking at read result.

Also because you only save the read data when if (!feof(fh)){ you do not memorize the information from the last line.

Note also fgets saves the newline if there is enough place for it, it is more practical to use fscanf.

So one way can be :

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

#define ACTORS "/tmp/actors"

int main()
{
  FILE * fh = fopen(ACTORS, "r");

  if (!fh) {
    perror("cannot read " ACTORS);
    exit(1);
  }

  char name[100],id[10];

  while (fscanf(fh, "%9s %99[^\n]", id, name) == 2) {
    size_t sz = strlen(name);
    char sex = name[--sz];

    for (;;) {
      if (sz == 0) {
        puts("empty name");
        exit(2);
      }
      if (!isspace((unsigned char) name[--sz]))
        break;
    }

    name[sz+1] = 0;

    /*
    hash_update_node(hash, get_id_num(id) , name, sex);
    count++;
    */
    printf("id='%s', name='%s', sex=%c\n", id, name, sex);
  }

  fclose(fh);
  return 0;
}

Compilation and executions :

pi@raspberrypi:/tmp $ gcc -Wall r.c
pi@raspberrypi:/tmp $ ./a.out
cannot read /tmp/actors: No such file or directory
pi@raspberrypi:/tmp $ cat > actors
nm0025630 Vikas Anand M
nm0418131 Victor Janson M
nm0411451 Dick Israel M
nm0757820 Leopoldo Salcedo M
pi@raspberrypi:/tmp $ ./a.out
id='nm0025630', name='Vikas Anand', sex=M
id='nm0418131', name='Victor Janson', sex=M
id='nm0411451', name='Dick Israel', sex=M
id='nm0757820', name='Leopoldo Salcedo', sex=M
pi@raspberrypi:/tmp $ 

Upvotes: 1

chqrlie
chqrlie

Reputation: 144550

It seems the fields are separated by TAB characters in the file. If this is correct, you can parse the file with fscanf():

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

int local_file(void) {
    char sex, name[100], id[10];
    int count = 0;

    FILE *fh = fopen(ACTORS, "r");
    if (!fh) {
        exit(1);
    }
    while (fscanf("%9[^\t]%*1[\t]%99[^\t]%*1[\t]%c", id, name, &sex) == 3) {
        hash_update_node(hash, get_id_num(id), name, sex);
        count++;
    }
    return count;
}

Note however that this code will fail if any of the fields are empty.

Upvotes: 1

Related Questions