2

I'm working on something small and I have run into a really small but disturbing problem - the program works in gcc, but crashes in visual studio, when it gets to the fgets command:

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

void registerUser(char *username);

char path[256] = "C:\\Users\\magshimim\\Desktop\\cproject\\bank\\";

int main() {
    int choice = 0;
    char username[10];
    printf("Welcome to nikitosik's bank program!\n"
           "Choose an option :\n"
           "0 - Register\n"
           "1 - Login to existing account\n");
    scanf("%d", &choice);
    getchar(); // catch enter
    if (!choice) {
        registerUser(username);
    } else {
        //login();
    }
}

void registerUser(char *username) { // username is passed, for verification later
    FILE *userinfo; // file that contains info of all registered users
    FILE *userpathf; // file to open for txt file
    char usertxt[256]; // path of data
    char userpath[256]; // path of new user data file
    char password[15];
    strcat(userpath, path);
    strcat(usertxt, path);
    strcat(usertxt, "users.txt");
    userinfo = fopen(usertxt, "a");
    printf("Choose a username(max 10 letters): ");
    fgets(username, 10, stdin);
    username[strcspn(username, "\n")] = 0;
    strcat(userpath, username);
    strcat(userpath, ".txt");
    userpathf = fopen(userpath, "w");
    fclose(userpathf);
    printf("Choose a password(max 15 letters): ");
    fgets(password, 15, stdin);
    fprintf(userinfo, "%s\n%s", username, password);
    fclose(userinfo);
}

thanks in advance

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • `strcat(userpath, path)` --> `strcpy(userpath, path)`, `strcat(usertxt, path);` --> `strcpy(usertxt, path);` – BLUEPIXY Aug 27 '17 at 16:45
  • I've thought about it but haven't really come to any conclusion if one of the options is better, and why? – Nikita Zaliven Aug 27 '17 at 16:48
  • 2
    It crashes because `userpath` has not been initialized when you do `strcat(userpath, path);` – Paul Ogilvie Aug 27 '17 at 16:48
  • 1
    Also `"Choose a password(max 15 letters): "` should be `"max 13 letters"` because `char password[15];` can hold 13 characters plus the newline `'\n'` that you type, and the `NUL` terminator. – Weather Vane Aug 27 '17 at 16:53
  • Ditto for `char username[10];` Where `"max 10 letters"` it should be `"max 8 letters"`. You will probably want to [remove the trailing newline character from fgets() input](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/28462221#28462221). – Weather Vane Aug 27 '17 at 16:56
  • @NikitaZaliven: you can accept one of the answers by clicking on the grey checkmark below its score. – chqrlie Sep 03 '17 at 06:39

2 Answers2

0

As above really or initialize the strings first.

memset(userpath, 0, sizeof(userpath));
memset(usertxt, 0, sizeof(usertxt));
AdyB
  • 11
  • 1
  • 1
    The usual way is with `char userpath[256] = "";` or with `char userpath[256] = {'\0'};` but as commented above it is better to use `strcpy` anyway. – Weather Vane Aug 27 '17 at 17:07
0

Your program has multiple issues:

  • you concatenate a string into an uninitialized array: this has undefined behavior and may well explain the observed behavior on different systems as undefined behavior may take multiple forms from no consequence at all to a crash or possibly even worse misfortune.
  • you do not test the return values of scanf, fopen, fgets(). Any invalid or unexpected input may trigger more undefined behavior.
  • you do not check for potential buffer overflow in strcat(). You should instead use snprintf().

Here is a safer version:

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

int registerUser(char *username, size_t size);

char path[] = "C:\\Users\\magshimim\\Desktop\\cproject\\bank\\";

int main(void) {
    int choice = 0;
    int c;
    char username[10];
    printf("Welcome to nikitosik's bank program!\n"
           "Choose an option :\n"
           "0 - Register\n"
           "1 - Login to existing account\n");
    if (scanf("%d", &choice) != 1)
        return 1;
    // consume the rest if the input line
    while ((c = getchar()) != EOF && c != '\n')
        continue;
    if (choice == 0) {
        registerUser(username, sizeof(username));
    } else {
        //login();
    }
    return 0;
}

int registerUser(char *username, size_t size) { // username is passed, for verification later
    char usertxt[256];  // path of data
    char userpath[256]; // path of new user data file
    char password[17];
    FILE *userinfo;     // file that contains info of all registered users
    FILE *userpathf;    // file to open for txt file

    printf("Choose a username(max %d letters): ", (int)(size - 2));
    if (!fgets(username, size, stdin))
        return -1;
    username[strcspn(username, "\n")] = 0;  // strip newline if any

    printf("Choose a password(max 15 letters): ");
    if (!fgets(password, sizeof(password), stdin))
        return -1;
    password[strcspn(password, "\n")] = 0;  // strip newline if any

    if (snprintf(usertxt, sizeof(usertxt), "%s%s", path, "users.txt") >= (int)sizeof(usertxt))
        return -1;
    if (snprintf(userpath, sizeof(userpath), "%s%s.txt", path, username) >= (int)sizeof(userpath))
        return -1;

    userinfo = fopen(usertxt, "a");
    if (userinfo == NULL)
        return -1;

    // create user file
    userpathf = fopen(userpath, "w");
    if (userpathf != NULL)
        fclose(userpathf);

    // add user info
    fprintf(userinfo, "%s\n%s\n", username, password);
    fclose(userinfo);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189