#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STOCKS 20 // 최대 주식 종목 수
#define MAX_USERS 100
#define FILE_NAME "stocks.csv"
#define USER_FILE "users.csv"
// 주식 구조체 정의
typedef struct {
char name[30];
double price;
} Stock;
// 사용자 구조체 정의
typedef struct {
char username[30];
double balance; // 보유 자산
double avgPrice[MAX_STOCKS]; // 평균 매수가
int quantity[MAX_STOCKS]; // 보유 수량
} User;
// 주식 종목 및 초기 가격 데이터
const char* initial_stock_names[MAX_STOCKS] = {
"FedEx", "DHL", "Amazon", "UPS", "Coupang",
"CJ Logistics", "Hanjin", "DSV A/S",
"Singapore Post", "Yamato Holdings",
NULL
};
double initial_prices[MAX_STOCKS] = {
230.5, 45.0, 3400.0, 200.0, 23.5,
12.3, 15.5, 100.8, 2.4, 17.2,
0.0
};
// 함수: 초기 주식 데이터 설정
void initializeStocks(Stock stocks[], int* stockCount) {
*stockCount = 0;
for (int i = 0; initial_stock_names[i] != NULL && i < MAX_STOCKS; i++) {
strncpy(stocks[i].name, initial_stock_names[i], sizeof(stocks[i].name) - 1);
stocks[i].name[sizeof(stocks[i].name) - 1] = '\0';
stocks[i].price = initial_prices[i];
(*stockCount)++;
}
}
// 함수: 주식 데이터 로드 (파일 읽기)
void loadStockData(Stock stocks[], int* stockCount) {
FILE* file = fopen(FILE_NAME, "r");
if (file == NULL) {
initializeStocks(stocks, stockCount);
return;
}
char line[100];
*stockCount = 0;
while (fgets(line, sizeof(line), file) && *stockCount < MAX_STOCKS) {
int sscanfResult = sscanf(line, "%[^,],%lf", stocks[*stockCount].name, &stocks[*stockCount].price);
if (sscanfResult == 2) {
(*stockCount)++;
}
}
fclose(file);
}
// 함수: 주식 데이터 저장
void saveStockData(Stock stocks[], int stockCount) {
FILE* file = fopen(FILE_NAME, "w");
if (file == NULL) {
perror("파일 저장 실패");
return;
}
for (int i = 0; i < stockCount; i++) {
fprintf(file, "%s,%.2f\n", stocks[i].name, stocks[i].price);
}
fclose(file);
}
// 사용자 데이터 로드
void loadUserData(User users[], int* userCount, int stockCount) {
FILE* file = fopen(USER_FILE, "r");
if (file == NULL) {
*userCount = 0;
return;
}
char line[1024]; // 라인 버퍼 크기 증가
if (fgets(line, sizeof(line), file) == NULL) {
*userCount = 0;
fclose(file);
return;
}
*userCount = atoi(line);
for (int i = 0; i < *userCount; i++) {
if (fgets(line, sizeof(line), file) == NULL)
break;
char* token;
token = strtok(line, ",");
if (token != NULL) {
strncpy(users[i].username, token, sizeof(users[i].username) - 1);
users[i].username[strcspn(users[i].username, "\n")] = '\0';
}
else {
users[i].username[0] = '\0';
}
token = strtok(NULL, ",");
if (token != NULL)
users[i].balance = atof(token);
else
users[i].balance = 0.0;
for (int j = 0; j < stockCount; j++) {
token = strtok(NULL, ",");
if (token != NULL)
users[i].quantity[j] = atoi(token);
else
users[i].quantity[j] = 0;
token = strtok(NULL, ",");
if (token != NULL)
users[i].avgPrice[j] = atof(token);
else
users[i].avgPrice[j] = 0.0;
}
}
fclose(file);
}
// 함수: 사용자 데이터 저장
void saveUserData(User users[], int userCount, int stockCount) {
FILE* file = fopen(USER_FILE, "w");
if (file == NULL) {
perror("파일 저장 실패");
return;
}
fprintf(file, "%d\n", userCount);
for (int i = 0; i < userCount; i++) {
fprintf(file, "%s,%.2f", users[i].username, users[i].balance);
for (int j = 0; j < stockCount; j++) {
fprintf(file, ",%d,%.2f", users[i].quantity[j], users[i].avgPrice[j]);
}
fprintf(file, "\n");
}
fclose(file);
printf("사용자 데이터를 저장했습니다.\n");
}
// 함수: 사용자 목록 출력
void printUserList(User users[], int userCount) {
printf("--- 사용자 목록 ---\n");
if (userCount == 0) {
printf("등록된 사용자가 없습니다.\n");
return;
}
printf("%-5s %-20s\n", "번호", "이름");
printf("---------------------------\n");
for (int i = 0; i < userCount; i++) {
printf("%-5d %-20s\n", i + 1, users[i].username);
}
printf("---------------------------\n");
}
// 함수: 사용자 추가 (기본 자산 4000 지급)
void addUser(User users[], int* userCount, int stockCount) {
if (*userCount >= MAX_USERS) {
printf("사용자 수 초과!\n");
return;
}
User newUser;
printf("새 사용자 이름 입력: ");
fgets(newUser.username, sizeof(newUser.username), stdin);
newUser.username[strcspn(newUser.username, "\n")] = '\0';
if (strlen(newUser.username) == 0) {
printf("이름이 입력되지 않았습니다. 다시 시도해주세요.\n");
return;
}
newUser.balance = 4000;
for (int i = 0; i < stockCount; i++) {
newUser.quantity[i] = 0;
newUser.avgPrice[i] = 0.0;
}
users[*userCount] = newUser;
(*userCount)++;
printf("새 사용자 추가 완료! 기본 자산: 4000유로 지급\n");
}
// 함수: 사용자 삭제
void deleteUser(User users[], int* userCount) {
if (*userCount == 0) {
printf("삭제할 사용자가 없습니다.\n");
return;
}
printf("삭제할 사용자 번호 입력:\n");
printUserList(users, *userCount);
int deleteIndex;
if (scanf("%d", &deleteIndex) != 1) {
printf("잘못된 선택!\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
deleteIndex--;
for (int i = deleteIndex; i < *userCount - 1; i++) {
users[i] = users[i + 1];
}
(*userCount)--;
printf("사용자가 삭제되었습니다.\n");
}
// 함수: 사용자 이름 변경
void changeUsername(User users[], int userCount) {
printf("이름을 변경할 사용자 번호를 선택하세요:\n");
printUserList(users, userCount);
int userIndex;
if (scanf("%d", &userIndex) != 1 || userIndex < 1 || userIndex > userCount) {
printf("잘못된 선택!\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
userIndex--;
printf("새 사용자 이름 입력: ");
char newUsername[30];
fgets(newUsername, sizeof(newUsername), stdin);
newUsername[strcspn(newUsername, "\n")] = '\0';
if (strlen(newUsername) == 0) {
printf("이름이 입력되지 않아 변경하지 않습니다.\n");
return;
}
strncpy(users[userIndex].username, newUsername, sizeof(users[userIndex].username) - 1);
users[userIndex].username[sizeof(users[userIndex].username) - 1] = '\0';
printf("사용자 이름이 %s로 변경되었습니다.\n", users[userIndex].username);
}
// 함수: 주식 매수
void buyStock(User* user, Stock stocks[], int stockCount) {
int choice, amount;
printf("\n[ 주식 구매 ]\n");
printf("%-5s %-20s %-10s\n", "번호", "주식명", "현재가");
printf("----------------------------------\n");
for (int i = 0; i < stockCount; i++) {
printf("%-5d %-20s %.2f€\n", i, stocks[i].name, stocks[i].price);
}
printf("----------------------------------\n");
printf("구매할 주식 번호 입력: ");
if (scanf("%d", &choice) != 1 || choice < 0 || choice >= stockCount) {
printf("잘못된 입력입니다.\n");
while (getchar() != '\n');
return;
}
printf("구매 수량 입력: ");
if (scanf("%d", &amount) != 1 || amount <= 0) {
printf("잘못된 수량!\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
double cost = stocks[choice].price * amount;
if (cost > user->balance) {
printf("잔액이 부족합니다! 현재 잔액: %.2f유로\n", user->balance);
return;
}
user->balance -= cost;
if (user->quantity[choice] > 0) {
user->avgPrice[choice] = (user->avgPrice[choice] * user->quantity[choice] + cost) /
(user->quantity[choice] + amount);
}
else {
user->avgPrice[choice] = stocks[choice].price;
}
user->quantity[choice] += amount;
printf("%s %d주 구매 완료!\n", stocks[choice].name, amount);
printf("남은 잔액: %.2f유로\n", user->balance);
}
// 주식 가격표 출력 함수
void printStockPriceTable(Stock stocks[], int stockCount) {
printf("\n==== 증권 시장 ====\n");
printf("%-5s %-20s %-10s\n", "번호", "주식명", "가격");
printf("===================================\n");
for (int i = 0; i < stockCount; i++) {
printf("%-5d %-20s %.2f€\n", i, stocks[i].name, stocks[i].price);
}
printf("===================================\n");
}
// 함수: 주식 매도
void sellStock(User* user, Stock stocks[], int stockCount) {
int choice, amount;
printf("\n[ 주식 판매 ]\n");
printf("%-5s %-20s %-10s %-10s\n", "번호", "주식명", "보유수량", "현재가");
printf("------------------------------------------\n");
for (int i = 0; i < stockCount; i++) {
printf("%-5d %-20s %-10d %.2f€\n", i, stocks[i].name, user->quantity[i], stocks[i].price);
}
printf("------------------------------------------\n");
printf("판매할 주식 번호 입력: ");
if (scanf("%d", &choice) != 1 || choice < 0 || choice >= stockCount) {
printf("잘못된 선택!\n");
while (getchar() != '\n');
return;
}
if (user->quantity[choice] == 0) {
printf("보유 수량이 없습니다!\n");
while (getchar() != '\n');
return;
}
printf("판매 수량 입력: ");
if (scanf("%d", &amount) != 1 || amount <= 0 || amount > user->quantity[choice]) {
printf("잘못된 수량!\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
double revenue = stocks[choice].price * amount;
user->balance += revenue;
user->quantity[choice] -= amount;
if (user->quantity[choice] == 0) {
user->avgPrice[choice] = 0;
}
printf("%s %d주 판매 완료!\n", stocks[choice].name, amount);
printf("총 판매 금액: %.2f유로, 현재 잔액: %.2f유로\n", revenue, user->balance);
}
// 함수: 수익률 계산 및 출력
void printProfitRates(User* user, Stock stocks[], int stockCount) {
printf("\n==== %s 님의 포트폴리오 ====\n", user->username);
printf("-------------------------------------------------------------------------\n");
printf("%-20s %-10s %-10s %-10s %-10s\n", "주식명", "보유수량", "매수평균가", "현재가", "수익률(%%)");
printf("-------------------------------------------------------------------------\n");
double totalAssetValue = user->balance;
for (int i = 0; i < stockCount; i++) {
if (user->quantity[i] > 0) {
double profitRate = ((stocks[i].price - user->avgPrice[i]) / user->avgPrice[i]) * 100;
printf("%-20s %-10d %-10.2f %-10.2f %-10.2f\n",
stocks[i].name, user->quantity[i], user->avgPrice[i], stocks[i].price, profitRate);
totalAssetValue += user->quantity[i] * stocks[i].price;
}
}
printf("-------------------------------------------------------------------------\n");
printf("현금 잔고: %.2f유로\n", user->balance);
printf("총 자산 가치: %.2f유로\n", totalAssetValue);
printf("=========================================================================\n");
}
// 함수: 주식 가격 일괄 변경
void updateAllStockPricesSequentially(Stock stocks[], int stockCount) {
printf("\n--- 주식 가격 일괄 변경 ---\n");
for (int i = 0; i < stockCount; i++) {
double change;
printf("[%s] 현재 가격: %.2f€\n", stocks[i].name, stocks[i].price);
printf("변경할 가격 비율(%%) 입력: ");
if (scanf("%lf", &change) != 1) {
printf("잘못된 금액 입력!\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
stocks[i].price += stocks[i].price * (change / 100);
printf("-> %s의 가격이 %.2f%% 변경되어 현재 가격: %.2f€\n\n", stocks[i].name, change, stocks[i].price);
}
}
// 사용자 자산 강제변경
void changeUserBalance(User* user, Stock stocks[], int stockCount) {
int choice;
printf("\n--- 사용자 자산 강제 변경 ---\n");
printf("1. 현금 잔액 변경\n");
printf("2. 특정 주식 보유 수량 변경\n");
printf("선택: ");
if (scanf("%d", &choice) != 1 || (choice != 1 && choice != 2)) {
printf("잘못된 선택입니다.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
if (choice == 1) {
double newBalance;
printf("현재 잔액: %.2f유로\n", user->balance);
printf("새로운 잔액 입력: ");
if (scanf("%lf", &newBalance) != 1 || newBalance < 0) {
printf("잘못된 입력입니다.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
user->balance = newBalance;
printf("현금 잔액이 %.2f유로로 변경되었습니다.\n", user->balance);
}
else if (choice == 2) {
int stockIndex, newQuantity;
printf("\n주식 목록:\n");
for (int i = 0; i < stockCount; i++) {
printf("%d. %s (현재 보유: %d주)\n", i, stocks[i].name, user->quantity[i]);
}
printf("변경할 주식 번호 입력: ");
if (scanf("%d", &stockIndex) != 1 || stockIndex < 0 || stockIndex >= stockCount) {
printf("잘못된 선택입니다.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
printf("현재 보유 수량: %d주\n", user->quantity[stockIndex]);
printf("새로운 보유 수량 입력: ");
if (scanf("%d", &newQuantity) != 1 || newQuantity < 0) {
printf("잘못된 입력입니다.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
user->quantity[stockIndex] = newQuantity;
if (newQuantity == 0) {
user->avgPrice[stockIndex] = 0.0;
}
printf("%s의 보유 수량이 %d주로 변경되었습니다.\n", stocks[stockIndex].name, user->quantity[stockIndex]);
}
}
// 새로운 주식 상장 함수
void listNewStock(Stock stocks[], int* stockCount, User users[], int userCount) {
if (*stockCount >= MAX_STOCKS) {
printf("최대 주식 수에 도달했습니다. 더 이상 상장할 수 없습니다.\n");
return;
}
printf("\n--- 신규 주식 상장 ---\n");
char newName[30];
double newPrice;
printf("상장할 기업 이름 입력: ");
fgets(newName, sizeof(newName), stdin);
newName[strcspn(newName, "\n")] = '\0';
if (strlen(newName) == 0) {
printf("이름이 입력되지 않아 취소합니다.\n");
return;
}
printf("초기 가격 입력: ");
if (scanf("%lf", &newPrice) != 1 || newPrice <= 0) {
printf("잘못된 가격입니다. 상장 취소.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
strncpy(stocks[*stockCount].name, newName, sizeof(stocks[*stockCount].name) - 1);
stocks[*stockCount].name[sizeof(stocks[*stockCount].name) - 1] = '\0';
stocks[*stockCount].price = newPrice;
for (int i = 0; i < userCount; i++) {
users[i].quantity[*stockCount] = 0;
users[i].avgPrice[*stockCount] = 0.0;
}
(*stockCount)++;
printf("%s 주식이 %.2f€의 가격으로 신규 상장되었습니다!\n", newName, newPrice);
}
// 주식 상장폐지 함수
void delistStock(Stock stocks[], int* stockCount, User users[], int userCount) {
if (*stockCount <= 0) {
printf("상장폐지할 주식이 없습니다.\n");
return;
}
printf("\n--- 주식 상장폐지 ---\n");
printf("상장폐지할 주식 번호를 선택하세요:\n");
printf("%-5s %-20s %-10s\n", "번호", "주식명", "현재가");
printf("----------------------------------\n");
for (int i = 0; i < *stockCount; i++) {
printf("%-5d %-20s %.2f€\n", i, stocks[i].name, stocks[i].price);
}
printf("----------------------------------\n");
int choice;
printf("선택: ");
if (scanf("%d", &choice) != 1 || choice < 0 || choice >= *stockCount) {
printf("잘못된 선택입니다.\n");
while (getchar() != '\n');
return;
}
while (getchar() != '\n');
char delistedName[30];
strncpy(delistedName, stocks[choice].name, sizeof(delistedName) - 1);
delistedName[sizeof(delistedName) - 1] = '\0';
// 해당 주식을 보유한 모든 사용자의 자산 정리
for (int i = 0; i < userCount; i++) {
if (users[i].quantity[choice] > 0) {
double liquidationValue = users[i].quantity[choice] * stocks[choice].price;
users[i].balance += liquidationValue;
printf("사용자 %s의 %s 주식 %d주가 %.2f€에 청산되어 잔고에 합산되었습니다.\n",
users[i].username, delistedName, users[i].quantity[choice], liquidationValue);
}
}
// stocks 배열에서 주식 제거 및 재배열
for (int i = choice; i < (*stockCount) - 1; i++) {
stocks[i] = stocks[i + 1];
}
(*stockCount)--;
printf("주식 %s가 상장폐지되었습니다.\n", delistedName);
}
// 메인 함수
int main() {
Stock stocks[MAX_STOCKS];
User users[MAX_USERS];
int userCount = 0;
int stockCount = 0;
int currentUser = -1;
loadStockData(stocks, &stockCount);
loadUserData(users, &userCount, stockCount);
printf("======================================\n");
printf(" 가상 주식 거래 시스템에 오신 것을 환영합니다!\n");
printf("======================================\n");
int mainChoice;
while (1) {
printf("\n");
printf("================ [ 메인 메뉴 ] ================\n");
printf(" --- 사용자 관리 ---\n");
printf(" 1. 사용자 선택\n");
printf(" 2. 사용자 추가\n");
printf(" 3. 사용자 삭제\n");
printf(" 4. 사용자 이름 변경\n");
printf(" --- 증권시장 관리 ---\n");
printf(" 5. 주식 상장 (새로운 기업 추가)\n");
printf(" 6. 주식 상장폐지\n");
printf(" 7. 주식 가격 일괄 변경\n");
printf(" 8. 증권시장 출력\n");
printf(" --- 기타 기능 ---\n");
printf(" 9. 사용자 데이터 강제 저장\n");
printf(" 10. 프로그램 종료\n");
printf("==============================================\n");
printf("선택: ");
if (scanf("%d", &mainChoice) != 1) {
printf("잘못된 입력입니다.\n");
while (getchar() != '\n');
continue;
}
while (getchar() != '\n');
switch (mainChoice) {
case 1: {
if (userCount == 0) {
printf("사용자가 없습니다. 먼저 사용자를 추가해주세요.\n");
continue;
}
printf("\n--- 사용자 선택 ---\n");
printUserList(users, userCount);
printf("사용자 번호 입력 (1부터 %d까지): ", userCount);
if (scanf("%d", ¤tUser) != 1 || currentUser < 1 || currentUser > userCount) {
printf("잘못된 선택입니다.\n");
currentUser = -1;
while (getchar() != '\n');
continue;
}
while (getchar() != '\n');
currentUser--;
printf("--> 현재 선택된 사용자: %s\n", users[currentUser].username);
int userMenuChoice = 0;
int exitUserMenu = 0;
while (1) {
exitUserMenu = 0;
printf("\n--- [ 사용자 메뉴 - %s ] ---\n", users[currentUser].username);
printf("1. 주식 구매\n");
printf("2. 주식 판매\n");
printf("3. 수익률 확인\n");
printf("4. 사용자 자산 강제변경\n");
printf("5. 메인 메뉴로 돌아가기\n");
printf("----------------------------------\n");
printf("선택: ");
if (scanf("%d", &userMenuChoice) != 1) {
printf("잘못된 입력!\n");
while (getchar() != '\n');
break;
}
while (getchar() != '\n');
switch (userMenuChoice) {
case 1: buyStock(&users[currentUser], stocks, stockCount); break;
case 2: sellStock(&users[currentUser], stocks, stockCount); break;
case 3: printProfitRates(&users[currentUser], stocks, stockCount); break;
case 4: changeUserBalance(&users[currentUser], stocks, stockCount); break;
case 5: exitUserMenu = 1; break;
default: printf("잘못된 선택입니다.\n"); break;
}
if (exitUserMenu) {
saveUserData(users, userCount, stockCount);
saveStockData(stocks, stockCount);
break;
}
}
break;
}
case 2: addUser(users, &userCount, stockCount); saveUserData(users, userCount, stockCount); break;
case 3: deleteUser(users, &userCount); saveUserData(users, userCount, stockCount); break;
case 4: changeUsername(users, userCount); saveUserData(users, userCount, stockCount); break;
case 5: listNewStock(stocks, &stockCount, users, userCount); saveStockData(stocks, stockCount); saveUserData(users, userCount, stockCount); break;
case 6: delistStock(stocks, &stockCount, users, userCount); saveStockData(stocks, stockCount); saveUserData(users, userCount, stockCount); break;
case 7: updateAllStockPricesSequentially(stocks, stockCount); saveStockData(stocks, stockCount); break;
case 8: printStockPriceTable(stocks, stockCount); break;
case 9: saveUserData(users, userCount, stockCount); break;
case 10:
saveUserData(users, userCount, stockCount);
saveStockData(stocks, stockCount);
printf("프로그램을 종료합니다.\n");
return 0;
default:
printf("잘못된 선택입니다.\n");
while (getchar() != '\n');
break;
}
}
return 0;
}
— 쇼샤