You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于结构体与指针的图书馆借阅系统开发问题求助

图书馆借阅系统(多借阅者+动态内存实现)

需求回顾

需要实现支持多个借阅者的图书馆系统,记录借阅者姓名、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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 06:40:19