Miraj Tasnim Miraj Tasnim - 1 month ago 8
C Question

Segmentation Fault: 11 (C programming)

I was trying to write a code for a login program and I must use a C structure in order to do it. Now the code compiles but when the user inputs username and password, I get a

Segmentation error: 11
.

additional note: the code is working fine on linux and windows but under unix environment it's having segmentation fault. So far I have written this:

typedef struct {
char username[20], password[20];
} DATA;

DATA user[10];
char iusername[20], ipassword[20];

DATA saveToStructforlogin(char* str) {
DATA res;
int flag = 0;
int size;
char *token = strtok(str, ";");

while (token != NULL) {
if (0 == flag) {
strcpy(res.username, token);
} else {
strcpy(res.password, token);
}
flag++;
token = strtok( NULL, ";" );
}
return res;
}

char *getUsername(DATA* arr, int size) {
int i;
for (i = 0; i < size; i++) {
return arr[i].username;
}
return 0;
}

char *getPassword(DATA* arr, int size) {
int i;
for (i = 0; i < size; i++) {
return arr[i].password;
}
return 0;
}

char *trimwhitespace(char *str) {
char *end;

// Trim leading space
while (isspace((unsigned char)*str))
str++;

if (*str == 0) // All spaces?
return str;

// Trim trailing space
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end))
end--;

*(end+1) = 0;
return str;
}

int main() {
FILE *fp;
char buffer[BUFFER_SIZE];
int i = 0, flag = 0, a, status = 0;
DATA arr[10];
char *mUsername[10];
char *mPassword[10];

fp = fopen("admin.txt", "r");
if (!fp) {
return -1;
}

printf("Admin Login\n");
printf("Username: ");
scanf("%s", iusername);
printf("Password: ");
scanf("%s", ipassword);

while (fgets(buffer, BUFFER_SIZE, fp)) {
arr[flag] = saveToStructforlogin(buffer);
mUsername[flag] = getUsername(arr, flag);
mPassword[flag] = getPassword(arr, flag);
if (strcmp(trimwhitespace(mUsername[flag]), iusername) == 0 &&
strcmp(trimwhitespace(mPassword[flag]), ipassword) == 0) {
status = 1;
break;
}
flag++;
}

if (status == 1) {
printf("Welcome to Admin Dashboard \n");
} else {
printf("Username or Password was wrong. please try again \n");
main();
}

fclose(fp);
return 0;
}

Answer Source

Your program has multiple issues:

  • The functions getUsername and getPassword only return the first entry of the array or NULL if it is empty.

  • The loop to check username and password is too complicated.

    Here is a simpler version:

    while (fgets(buffer, BUFFER_SIZE, fp)) {
        DATA user = saveToStructforlogin(buffer);
        if (strcmp(user.username, iusername) == 0 &&
            strcmp(user.password, ipassword) == 0) {
                status = 1;
                break;
        }
    }
    
  • The function saveToStructforlogin should trim the strings from the file:

    DATA saveToStructforlogin(char* str) {
        DATA res = { 0 };
        char *token = strtok(str, ";");
    
        if (token != NULL) {
            strcpy(res.username, trimwhitespace(token));
            token = strtok(NULL, ";");
            if (token != NULL) {
                strcpy(res.password, trimwhitespace(token));
            }
        }
        return res;
    }
    
  • calling main recursively is incorrect. You should use a for(;;) loop.

  • returning structures is legal, but not a very good API: it does not allow for proper error detection.

Here is a simplified and corrected version of the code:

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

typedef struct {
    char username[20], password[20];
} DATA;

char iusername[20], ipassword[20];

char *trimwhitespace(char *str) {
    char *end = str + strlen(str);

    // Trim trailing space
    while (end > str && isspace((unsigned char)end[-1])) {
        *--end = '\0';
    }
    // Trim leading space
    while (isspace((unsigned char)*str)) {
        str++;
    }
    return str;
}

size_t bstrcpy(char *dest, size_t size, const char *src) {
    size_t len = strlen(src);
    if (len < size) {
        memcpy(dest, src, len + 1);
    } else
    if (size > 0) {
        memcpy(dest, src, size - 1);
        dest[size - 1] = '\0';
    }
    return len;
}

DATA *saveToStructforlogin(DATA *res, char* str) {
    char *token = strtok(str, ";");
    if (token != NULL) {
        bstrcpy(res->username, sizeof(res->username), trimwhitespace(token));
        token = strtok(NULL, ";");
        if (token != NULL) {
            bstrcpy(res->password, sizeof(res->password), trimwhitespace(token));
            return res;
        }
    }
    return NULL;
}

int main(void) {
    char buffer[1024];
    FILE *fp;
    int status;

    fp = fopen("admin.txt", "r");
    if (!fp) {
        return 1;
    }

    for (;;) {
        printf("Admin Login\n");
        printf("Username: ");
        if (scanf("%s", iusername) != 1)
            break;
        printf("Password: ");
        if (scanf("%s", ipassword) != 1)
            break;

        status = 0;
        rewind(fp);
        while (fgets(buffer, sizeof(buffer), fp)) {
            DATA user;
            if (saveToStructforlogin(&user, buffer)
            &&  !strcmp(user.username, iusername)
            &&  !strcmp(user.password, ipassword)) {
                status = 1;
                break;
            }
        }

        if (status == 0) {
            printf("Username or Password was wrong, please try again\n");
            continue;
        }
        printf("Welcome to Admin Dashboard \n");
        // handle the session here.
        break;
    }
    fclose(fp);
    return 0;
}