C 프로그래밍

C프로그래밍 2023.12.16 데이터 저장

Nohsw 2023. 12. 16. 23:34

오늘은 회원가입 프로그램의 업데이트를 진행했다.

기존에 되지않던 회원정보를 저장하는 것이였다.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <time.h>

enum userInputNum {
    input_SignUp = 1,
    input_Login = 2,
    input_Admin = 3,
    input_Exit = 4
};

struct Member {
    char username[50];
    char password[50];
    char checkPassword[50];
};

struct Member members[100];
int memberCount = 0;

void sleep() {
    printf("정보 확인 중입니다. 잠시만 기다려주세요.\n");
    Sleep(5000);
    system("cls"); 
}

void clearInputBuffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

void getPassword(char* password) {
    char ch;
    int i = 0;

    while (1) {
        ch = _getch();

        if (ch == 13) {
            break;
        }

        else if (ch == 8) {
            if (i > 0) {
                printf("\b \b");
                i--;
            }
        }

        else {
            password[i++] = ch;
            printf("*");
        }
    }

    password[i] = '\0';
    printf("\n");
}

void saveToFile() {
    FILE* file;

    if (fopen_s(&file, "members.txt", "w") != 0) {
        fprintf(stderr, "Error opening file for writing\n");
        return;
    }

    for (int i = 0; i < memberCount; i++) {
        fprintf(file, "%s %s\n", members[i].username, members[i].password);

    }

    fclose(file);
}

void loadFromFile() {
    FILE* file;

    if (fopen_s(&file, "members.txt", "r") != 0) {
        fprintf(stderr, "Error opening file for reading\n");
        return;
    }

    while (fscanf_s(file, "%s %s", members[memberCount].username, sizeof(members[memberCount].username), members[memberCount].password, sizeof(members[memberCount].password)) == 2) {
        memberCount++;
    }

    fclose(file);
}

//void showTime() {
//    while (1) {
//        time_t currentTime;
//        struct tm localTime;
//        time(&currentTime);
//
//#ifdef _MSC_VER
//        localtime_s(&localTime, &currentTime);  // Visual Studio에서는 localtime_s 사용
//#else
//        localtime_r(&currentTime, &localTime);  // 다른 컴파일러에서는 localtime_r 사용
//#endif
//
//        //system("cls"); // 화면을 지우고 새로운 시간을 출력하기 위함
//        printf("현재 시간: %02d:%02d:%02d\n", localTime.tm_hour, localTime.tm_min, localTime.tm_sec);
//        Sleep(1000); // 1초 대기
//    }
//}

void signUp() {
    struct Member newMember;
    printf("아이디 입력: ");
    scanf_s("%s", newMember.username, sizeof(newMember.username));

    printf("비밀번호 입력: ");
    getPassword(newMember.password);

    printf("비밀번호 한번 더 입력: ");
    getPassword(newMember.checkPassword);

    if (strcmp(newMember.password, newMember.checkPassword) == 0) {
        members[memberCount] = newMember;
        memberCount++;

        sleep();
        saveToFile();
        printf("회원가입 완료.\n");
        return;
    }
    sleep();
    printf("회원가입 실패.\n");
}

void login() {
    char username[50];
    char password[50];
    int i;
    printf("아이디 입력: ");
    scanf_s("%s", username, sizeof(username));

    printf("비밀번호 입력: ");
    getPassword(password);

    for (i = 0; i < memberCount; i++) {
        if (strcmp(username, members[i].username) == 0 && strcmp(password, members[i].password) == 0) {
            sleep();
            printf("로그인 성공\n");
            return;
        }
    }
    sleep();
    printf("아이디나 비밀번호가 다릅니다. 다시 입력해주세요.\n");
}



void displayMembers() {
    char password[50];
    printf("관리자 비밀번호 입력: ");
    getPassword(password);

    if (strcmp(password, "admin") == 0) {
        system("cls");
        printf("\n----- 사용자 리스트 -----\n");
        for (int i = 0; i < memberCount; i++) {
            printf("%d. %s\n", i + 1, members[i].username);
        }
        printf("------------------------\n");
    }
    else {
        printf("비밀번호가 다릅니다.\n");
    }
}

void displayMenu() {
    printf("\n----- 메뉴 -----\n");
    printf("1. 회원가입\n");
    printf("2. 로그인\n");
    printf("3. 회원 목록 보기\n");
    printf("4. 종료\n");
}

int main() {
    int choice;
    
    loadFromFile();
    int result = MessageBoxA(NULL, "로그인 프로그램을 시작하려면 \"예\"를, 종료하려면 \"아니오\"를 선택하세요.", "알림", MB_YESNO);
    if (result == IDYES) {
        do {
            displayMenu();
            //HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)showTime, NULL, 0, NULL);
            printf("숫자를 입력해주세요.: ");
            scanf_s("%d", &choice);
            enum userInputNum UserInputNum = choice;
            clearInputBuffer();

            switch (UserInputNum) {
            case input_SignUp:
                signUp();
                break;

            case input_Login:
                login();
                break;

            case input_Admin:
                displayMembers();
                break;

            case input_Exit:
                printf("프로그램을 종료합니다.\n");
                MessageBoxA(NULL, "프로그램을 종료합니다.", "알림", MB_OK);
                break;

            default:
                printf("잘못 입력하였습니다. 다시 입력해주세요.\n");
            }

        } while (choice != 4);
    }
    else {
        MessageBoxA(NULL, "프로그램을 종료합니다.", "알림", MB_OK);
    }

    return 0;
}

아직 암호화는 하지 못해 비밀번호가 그대로 노출된다는 단점이 있지만 데이터를 저장하고 불러올 수 있다는 점에서 유용한 부분인 것 같아 몇 번 연습하여 적용하면 괜찮을 것 같다.

saveToFile 함수로 데이터를 txt로 저장하고 loadFromFile함수로 txt를 불러와 프로그램을 종료해도 데이터가 사라지지 않는 장점이 있다.

아무래도 프로젝트를 회원가입 프로그램을 계속 추가하고 수정하며 코드를 정리하는 것이 실력을 올리는데 큰 도움이 될 것 같아 새로운 것을 도전하지 않고 업데이트를 꾸준히 하는 방향으로 정하게되었다.

실시간 시간을 구현하여 우측 상단에 시간을 적용시키고 싶었지만 system(cls);를 하다보니 메뉴까지 사라지는 현상때문에 주석처리 후 코드를 올리게 되었다. 이 부분도 좋은 아이디어가 생기면 다시 적용시켜 테스트를 진행해봐야겠다.