Search code examples
cfilefgetsstrlen

c fgets retrieves the whole array?


I have a file named phobebook where i retrieve the number of contacts I have(here the int is assigned on variable cc), then saved the names, address etc. problem is when I display the info, the details are there but they are separated with new lines. I tried to put the \0 but it seems it does not work.

typedef struct myphonebook{
  char name[31];
  char address[101];
  char cellphone[11];
  char email[21];
} Myphonebooktype;

FILE*db;

db = fopen("db.txt", "r");

fscanf(db, "%d" , &cc);

pb = (Myphonebooktype*)malloc(cc*sizeof(Myphonebooktype));
addcounter = cc;

for(i = 0; i<cc ; i++){
  size_t lenn = strlen(pb[i].name);
  if (pb[i].name[lenn - 1] == '\n') {
    pb[i].name[lenn - 1] = '\0';
  }
  fgets(pb[i].name, sizeof(pb[i].name), db);

  size_t lena = strlen(pb[i].address);
  if (pb[i].address[lena - 1] == '\n') {
    pb[i].address[lena - 1] = '\0';
  }
  fgets(pb[i].address, sizeof(pb[i].address), db);

  size_t lenc = strlen(pb[i].cellphone);
  if (pb[i].cellphone[lenc - 1] == '\n') {
    pb[i].cellphone[lenc - 1] = '\0';
  }
  fgets(pb[i].cellphone, sizeof(pb[i].cellphone), db);

  size_t lene = strlen(pb[i].email);
  if (pb[i].email[lene - 1] == '\n') {
    pb[i].email[lene - 1] = '\0';
  }
  fgets(pb[i].email, sizeof(pb[i].email), db);
}

Solution

  • As @unwind said, code is referencing uninitialized data before writing to it

      size_t lenn = strlen(pb[i].name);  // pb[i].name contents are not defined yet.
      ...
      fgets(pb[i].name, sizeof(pb[i].name), db);
    

    Suggest creating a function to handle the reading of the line.

    void ReadLine(FILE *db, char *dest, size_t size) {
      char buffer[size+2];
      dest[0] = '\0';
      if (fgets(buffer, sizeof buffer, db) != NULL) {
        size_t len = strlen(buffer);
        // Get rid of potential \n
        if (len > 0 && buffer[len-1] == '\n') buffer[--len] = '\0';
        strncpy(dest, buffer, size);
      }
    } 
    
    
    for(i = 0; i<cc ; i++) {
      ReadLine(db, pb[i].name, sizeof pb[i].name);
      ReadLine(db, pb[i].address, sizeof pb[i].address);
      ReadLine(db, pb[i].cellphone, sizeof pb[i].cellphone);
      ReadLine(db, pb[i].email, sizeof pb[i].email);
    }
    

    Additions could be made to ReadLine() to return EOF on NULL read, excessively long lines or \r concern as raised by @MadHatter. It's all in one function, so easier to maintain and enhance code.