0

I have a function getData() where it is supposed to read a text file "Users.txt" and store the data of the text file in an array of structures declared as user[20].

the struct is defined as:

typedef struct userTag {
    int ID;
    string10 password;
    string20 name;
    string30 address;
    string15 contactNum;
} userType;

the text file format is as follows:

<ID> <password>
<name>
<address>
<contact num>

112 pass222
Ginge Akerwood
Camella Homes
0922294812

119 h3yo2
Marian Nilza Ginge
Camella
0999222444

this is my main program:

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


int main(int argc, char *argv[]) {
    userType user[20];

    getData(user);
    display(user, 3);

    return 0;
}

void display(userType u[], int nElem) {
    int i;

    for(i = 0; i < nElem; i++)
        printf("User ID: %d\n", u[i].ID);
}

void getData(userType u[]) {
    int i = 0;
    FILE* fp_users;
    char dump;

    fp_users = fopen("Users.txt", "r");

    while(fscanf(fp_users,"%d %s", &u[i].ID, u[i].password) == 2) {

        fgets(u[i].name, 20, fp_users);
        fgets(u[i].address, 30, fp_users);
        fgets(u[i].contactNum, 15, fp_users);
        fscanf(fp_users, "%c", &dump);
        i++;
    } 

    fclose(fp_users);
}

the output of the function display() is:

User ID: 112
User ID: 922294812
User ID: 999222444

I can't really find good resources on how to read files on the net so i had to ask here. also the format of the text file can't be changed so it has to be read that way.

Ethan
  • 5
  • 1
  • After the scanf, the file pointer is on the newline at the end of the line. The first fgets just returns that newline. – William Pursell Feb 28 '20 at 12:58
  • Please don't mix the use of `fgets` and `fscanf`. Note that with `fgets` there will be a trailing newline *in the string* that needs to be [removed](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/28462221#28462221). Your trick `fscanf(fp_users, "%c", &dump);` is attempting to remove the *next* character. – Weather Vane Feb 28 '20 at 13:05
  • How/where are types `string10` `string20` `string30` `string15` defined – ryyker Feb 28 '20 at 13:09

1 Answers1

0

After the scanf, the file pointer is on the newline at the end of the line. The first fgets returns the buffer with just that newline in it, and nothing else. The second fgets reads the line containing the name. Simplest fix is probably to use:

fscanf(fp_users,"%d %s\n")

but IMO this is hacky and fragile. It would be better to use either scanf or fgets exclusively, and don't mix the two. For example, instead of fgets, use fscanf(" %19[^\n]", u->name) to read the name. The leading space in the format string strips the whitespace for you. Note that I've assumed you are going to increment u so that -> is valid. It is a much cleaner syntax than u[i].name, and ought to be used.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • This has helped, the only problem left was the extra \n so i had to manually remove it. thank you. – Ethan Feb 28 '20 at 13:18
  • Note that `'\n'` in `scanf` format string is equal to space, ie. any whitespace, so it is less confusing to use just space. – hyde Feb 28 '20 at 13:23
  • @hyde raises a valid point, but IMO the explicit `\n` is actually better here, since it conveys to the reader exactly what is intended to match. But that is still the wrong approach. – William Pursell Feb 28 '20 at 13:25
  • So show a better approach... (i.e. _Simplest fix is probably to use_ is very unsatisfying, especially when you allude to a better approach.) – ryyker Feb 28 '20 at 13:26
  • 1
    @rykker. I did. Use `" %19[^\n]"` format string instead of `fgets` – William Pursell Feb 28 '20 at 13:27
  • @WilliamPursell Subjective, but I think it's misleading, because even if it (plain `\n`) is *intended* to match newline, it matches more. If I encountered that in some "real" code, I'd wonder if the programmer thought it would actually do something special. It would not convey the intended meaning to me. – hyde Feb 28 '20 at 13:31
  • Okay, that's fair. I guess I just have a natural aversion to using `fscanf` and family to read text files when using `fgets()` allows so much more freedom to parse the content organically. – ryyker Feb 28 '20 at 13:31
  • 1
    @ryyker I tend to agree. I would almost certainly only use `fgets`, and have merely started to answer questions regarding `scanf` to overcome my natural inclination to avoid it like the plague. Turns out it's not so bad, but I am very much reconfirmed in my belief that it ought not be used at all by anyone learning the language. It is a disaster that it is so often taught in introductory courses. – William Pursell Feb 28 '20 at 13:40