基于结构体与指针的图书馆借阅系统开发问题求助
图书馆借阅系统(多借阅者+动态内存实现)
需求回顾
需要实现支持多个借阅者的图书馆系统,记录借阅者姓名、ID、电话,最多3本借阅图书,支持归还全部图书后释放对应内存。原代码仅能处理单个借阅者,现需改造为动态管理多个借阅者。
修正后完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define CLEAR() system("CLS") #define INIT_CAPACITY 2 // 初始可容纳的借阅者数量 #define MAX_ID_LEN 7 #define MAX_NAME_LEN 20 #define MAX_PHONE_LEN 10 #define MAX_BOOK_TITLE 20 #define MAX_BOOKS 3 struct borrower { char name[MAX_NAME_LEN]; char lastName[MAX_NAME_LEN]; char id[MAX_ID_LEN]; char phoneNumber[MAX_PHONE_LEN]; char titleOfBook[MAX_BOOKS][MAX_BOOK_TITLE]; int bookCount; // 记录当前借阅图书数量,用于判断是否可删除 }; // 函数声明 void RegisterBorrower(struct borrower **borrowers, int *count, int *capacity); void FindByID(struct borrower *borrowers, int count); void ShowAll(struct borrower *borrowers, int count); void EraseByID(struct borrower **borrowers, int *count); void TrimNewline(char *str); // 去除fgets读取的换行符 int main(void) { char op; struct borrower *borrowers = malloc(INIT_CAPACITY * sizeof(struct borrower)); if (borrowers == NULL) { perror("Failed to allocate memory"); return 1; } int count = 0; // 当前已注册的借阅者数量 int capacity = INIT_CAPACITY; // 当前数组的容量 do { puts("\n1) Register borrower"); puts("2) Find by ID"); puts("3) Show All"); puts("4) Erase by ID"); puts("0) Exit"); printf("Option: "); setbuf(stdin, NULL); op = getchar(); switch(op) { case '1': RegisterBorrower(&borrowers, &count, &capacity); break; case '2': FindByID(borrowers, count); break; case '3': ShowAll(borrowers, count); break; case '4': EraseByID(&borrowers, &count); break; case '0': break; default: puts("Invalid option, try again."); } } while (op != '0'); // 程序退出前释放所有动态内存 free(borrowers); borrowers = NULL; return 0; } void RegisterBorrower(struct borrower **borrowers, int *count, int *capacity) { CLEAR(); // 检查容量,不够则扩容 if (*count >= *capacity) { *capacity *= 2; struct borrower *temp = realloc(*borrowers, *capacity * sizeof(struct borrower)); if (temp == NULL) { perror("Failed to reallocate memory"); return; } *borrowers = temp; } struct borrower *newBorrower = &(*borrowers)[*count]; memset(newBorrower, 0, sizeof(struct borrower)); // 初始化新借阅者内存 printf("ID: "); fgets(newBorrower->id, MAX_ID_LEN, stdin); TrimNewline(newBorrower->id); printf("Name: "); fgets(newBorrower->name, MAX_NAME_LEN, stdin); TrimNewline(newBorrower->name); printf("Last Name: "); fgets(newBorrower->lastName, MAX_NAME_LEN, stdin); TrimNewline(newBorrower->lastName); printf("Phone Number: "); fgets(newBorrower->phoneNumber, MAX_PHONE_LEN, stdin); TrimNewline(newBorrower->phoneNumber); int numberOfBooks = 0; char bookTitle[MAX_BOOK_TITLE]; printf("How many books do you want to take out?(max 3): "); scanf("%d", &numberOfBooks); setbuf(stdin, NULL); if (numberOfBooks <= MAX_BOOKS && numberOfBooks > 0) { newBorrower->bookCount = numberOfBooks; for(int i=0; i<numberOfBooks; i++) { printf("Book Title %d: ", i+1); fgets(bookTitle, MAX_BOOK_TITLE, stdin); TrimNewline(bookTitle); strcpy(newBorrower->titleOfBook[i], bookTitle); } }else { printf("You cannot take out this amount of books.\n"); newBorrower->bookCount = 0; } (*count)++; puts("Borrower registered successfully!"); system("pause"); } void FindByID(struct borrower *borrowers, int count) { CLEAR(); if (count == 0) { puts("No borrowers registered yet."); system("pause"); return; } char targetID[MAX_ID_LEN]; printf("Enter ID to find: "); fgets(targetID, MAX_ID_LEN, stdin); TrimNewline(targetID); for(int i=0; i<count; i++) { if (strcmp(borrowers[i].id, targetID) == 0) { puts("\nBorrower found:"); printf("ID: %s\n", borrowers[i].id); printf("Name: %s %s\n", borrowers[i].name, borrowers[i].lastName); printf("Phone: %s\n", borrowers[i].phoneNumber); printf("Borrowed Books (%d):\n", borrowers[i].bookCount); for(int j=0; j<borrowers[i].bookCount; j++) { printf("- %s\n", borrowers[i].titleOfBook[j]); } system("pause"); return; } } puts("Borrower not found."); system("pause"); } void ShowAll(struct borrower *borrowers, int count) { CLEAR(); if (count == 0) { puts("No borrowers registered yet."); system("pause"); return; } printf("Total borrowers: %d\n\n", count); for(int i=0; i<count; i++) { printf("Borrower %d:\n", i+1); printf("ID: %s\n", borrowers[i].id); printf("Name: %s %s\n", borrowers[i].name, borrowers[i].lastName); printf("Phone: %s\n", borrowers[i].phoneNumber); printf("Borrowed Books (%d):\n", borrowers[i].bookCount); for(int j=0; j<borrowers[i].bookCount; j++) { printf("- %s\n", borrowers[i].titleOfBook[j]); } puts("------------------------"); } system("pause"); } void EraseByID(struct borrower **borrowers, int *count) { CLEAR(); if (*count == 0) { puts("No borrowers registered yet."); system("pause"); return; } char targetID[MAX_ID_LEN]; printf("Enter ID to erase (only allowed if no books borrowed): "); fgets(targetID, MAX_ID_LEN, stdin); TrimNewline(targetID); int index = -1; for(int i=0; i<*count; i++) { if (strcmp((*borrowers)[i].id, targetID) == 0) { if ((*borrowers)[i].bookCount != 0) { puts("Cannot erase: Borrower still has books."); system("pause"); return; } index = i; break; } } if (index == -1) { puts("Borrower not found."); system("pause"); return; } // 将后面的元素前移,覆盖要删除的元素 for(int i=index; i<*count-1; i++) { (*borrowers)[i] = (*borrowers)[i+1]; } (*count)--; // 可选:如果容量远大于当前数量,缩小内存(节省空间) if (*count < (*capacity)/2 && *capacity > INIT_CAPACITY) { *capacity /= 2; struct borrower *temp = realloc(*borrowers, *capacity * sizeof(struct borrower)); if (temp != NULL) { *borrowers = temp; } } puts("Borrower erased successfully."); system("pause"); } void TrimNewline(char *str) { char *newline = strchr(str, '\n'); if (newline != NULL) { *newline = '\0'; } }
关键改动说明
- 动态数组管理:用
struct borrower**类型维护借阅者数组,初始分配固定容量,当注册数量达到容量时,用realloc扩容(翻倍);删除后若剩余数量远小于容量,可选择缩容节省内存。 - 新增
bookCount字段:记录每个借阅者当前借阅的图书数量,用于判断是否允许删除(归还全部图书后才可删除)。 - 替换
gets为fgets:gets存在缓冲区溢出风险,fgets更安全,配合TrimNewline函数去除读取时带入的换行符。 - 完善功能函数:实现了查找、展示所有、删除功能,删除时通过元素前移整理数组,并调整动态内存。
- 修复原代码错误:修正了变量名
opc笔误为op,函数参数p统一为上下文对应变量名,避免未定义行为。
内容的提问来源于stack exchange,提问作者mexicanburrito
相关产品推荐
相关产品推荐

