main.c

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

#define MAX_USERS 100

typedef struct Utilizadores{
    char *login;
    char *pwd;
} USERS;

void ReadUsers(USERS user[]);

int u = 0;

int main(){
    USERS user[MAX_USERS];

    ReadUsers(user);

    return 0;
}

void ReadUsers(USERS user[]){
    FILE *fp;

    fp = fopen("/home/Jiwe/Desktop/users.txt", "r");

    while(fscanf(fp, "%s[^=]=%s\n", user[u].login, user[u].pwd) != EOF){
        u++;
    }

    fclose(fp);
}

Hey guys, I get a segmentation fault error using the code above. For now I just want to read the login name and password of a user from a text file, so later I can show it.

The text file is filled like this:

LOGIN=PASS
LOGIN2=PASS2
... etc

I just don't understand why I'm getting that error, I've been searching for hours for a solution and still haven't found one.

You're getting that error because pointers aren't magic. If you want a pointer to point to N bytes of memory, you must ensure yourself that the memory exists and assign the base address of that memory to the pointer.

The specific problem here is that you're using uninitialized pointers as the destination objects for scanf(). scanf() expects there to be sufficient memory (which in and of itself is problematic with the %s specifier and no field width) when no such memory exists.

erik's suggestion will work, though it will certainly lead to that problem I mentioned briefly concerning %s without a field width. Alternatively you can allocate memory to the pointers with malloc(). However, I think a better solution would be using "large" buffers to hold each string and then allocate just enough on a case by case basis:

char login[1024];
char pwd[1024];

while (fscanf(fp, "%1023s[^=]=%1023s\n", login, pwd) == 2) {
    user[u].login = strdup(login);
    user[u].pwd = strdup(pwd);
    ++u;
}

I made a few changes:

  1. Each %s is now given a field width to ensure that buffer overflow doesn't occur.
  2. Instead of testing for EOF, I test for 2 (the number of expected matches) to account for formatting errors in the file.
  3. Two input buffers are used instead of the destinations at user[u]. Then user[u] is filled in using the non-standard strdup().
  4. A minor nit: while it's unlikely to make a difference, prefix increment is conceptually faster and more intuitive.

Since strdup() is a non-standard function, here's an example implementation:

char* strdup(char const* s)
{
    char* result = malloc(strlen(s) + 1);

    if (result)
    {
        strcpy(result, s);
    }

    return result;
}

Given that example, also note that I didn't add any error handling for the case where strdup() returns NULL.

Hey deceptikon, I've tried your code as follows:

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

#define MAX_USERS 100

typedef struct Utilizadores{
    char *login;
    char *pwd;
} USERS;

void ReadUsers(USERS user[]);
char *strdup(char const *s);

int u = 0;
char login[1024], pwd[1024];

int main(){
    USERS user[MAX_USERS];

    ReadUsers(user);

    return 0;
}

void ReadUsers(USERS user[]){
    FILE *fp;

    fp = fopen("/home/Jiwe/Desktop/users.txt", "r");

    while(fscanf(fp, "%1023s[^=]=%1023s\n", login, pwd) != 2){
        user[u].login = strdup(login);
        user[u].pwd = strdup(pwd);
        ++u;
    }

    fclose(fp);
}

char *strdup(char const *s){
    char *result = malloc(strlen(s) + 1);

    if(result)
        strcpy(result, s);

    return result;
}

It still gives me Segmentation Fault error, I really don't understand what's going on.. this should've been working...

Edited 4 Years Ago by mcjiwe: Code block wasn't showing line numbers

Try calling perror() after fopen(). I notice you're not checking to see if the file was successfully opened before trying to read from it.

Comments
Thank you so much =)

Oh my god.. I've been going on and on and on, trying to figure out what was wrong and with just that function I finally figured it out... the path I had in my program was "/home/Jiwe/Desktop/users.txt", when it should be "/home/jiwe/Desktop/users.txt".

That's what I get for not being used to linux case sensitive paths. Anyways thank you so much deceptikon for you help, much appreciated :). I hereby flag this thread as closed.

This question has already been answered. Start a new discussion instead.