C语言通讯录进阶:从静态数组到动态内存与文件持久化

方予
方予
发布时间:2026-10-15| 6人浏览过
原创

在C语言基础项目中,通讯录是检验结构体、指针及内存管理的经典案例。本文从基础的静态版本出发,逐步重构为支持动态扩容和文件持久化的工业级版本,详细解析如何利用 realloc 管理不定长数据,以及如何通过二进制文件操作实现数据的本地保存。

一、程序整体架构设计

C语言通讯录通常分为三个核心文件:test.c 负责主循环与菜单交互,contact.c 实现具体业务逻辑(增删改查、内存管理、IO操作),contact.h 定义数据结构与函数原型。这种分层设计有助于降低耦合度。

第1步:定义通讯结构体与常量

在 contact.h 中,我们需要定义联系人信息结构体和通讯录容器结构体。

  • 静态版痛点:若直接使用固定大小数组(如 PeoInfo data[MAX]),一旦用户输入超过预设数量,程序将无法响应或发生溢出风险。
  • 动态版改进:使用指针 PeoInfo* data 指向堆区内存,并增加 capacity 字段记录当前容量。
// contact.h 核心定义
typedef struct PeoInfo
{
    char name[20];
    int age;
    char sex[10];
    char tele[12];
    char addr[30];
} PeoInfo;

// 动态版本结构体
typedef struct Contact
{
    PeoInfo* data;   // 存放人信息的动态数组指针
    int count;       // 当前有效联系人数
    int capacity;    // 当前分配的最大容量
} Contact;

第2步:菜单驱动的主流程

在 test.c 中,利用枚举类型提升代码可读性,并通过 do-while 循环维持程序运行。每次调用功能前,需确保传入通讯录结构的指针。

#include "contact.h"

enum Option {
    EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT
};

void menu() {
    printf("*******\ 1.add     2.del    /*******\n");
    printf("*******\ 3.search  4.modify /*******\n");
    printf("*******\ 5.show    6.sort   /*******\n");
}

int main() {
    Contact con;
    InitContact(&con); // 初始化
    
    do {
        menu();
        int input = 0;
        scanf("%d", &input);
        switch (input) {
            case ADD: AddContact(&con); break;
            case DEL: DelContact(&con); break;
            // ... 其他case ...
            case EXIT:
                SaveContact(&con);     // 退出前保存
                DestroyContact(&con);  // 释放内存
                printf("退出通讯录\n");
                break;
        }
    } while (input != EXIT);
    return 0;
}

二、核心功能实现细节

第3步:实现动态内存扩容 (CheckCapacity)

这是动态版本区别于静态版本的关键。当添加联系人时,先检查当前 count 是否等于 capacity。如果相等,说明内存已满,需使用 realloc 扩容。

void CheckCapacity(Contact* pc) {
    if (pc->count == pc->capacity) {
        // 扩容策略:原容量 + 增量(INC_SZ)
        PeoInfo* ptr = realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
        if (ptr == NULL) {
            printf("AddContact::%s\n", strerror(errno));
            return;
        }
        pc->data = ptr;
        pc->capacity += INC_SZ;
    }
}

注意:在使用 realloc 时,务必先判断返回值是否为空,再赋值给原指针,以免发生内存泄漏。

第4步:实现数据持久化 (Load/Save Contact)

为了让程序退出后数据不丢失,需将内存中的数据写入本地文件,并在启动时读取。这里推荐使用二进制模式(rb/wb)进行读写,因为可以直接拷贝结构体内存块,效率更高且无需处理格式化字符串。

// 加载文件数据到内存
void LoadContact(Contact* pc) {
    FILE* pfRead = fopen("contact.txt", "rb");
    if (pfRead == NULL) return; // 文件不存在则忽略
    
    PeoInfo tmp = {0};
    while (fread(&tmp, sizeof(PeoInfo), 1, pfRead) == 1) {
        CheckCapacity(pc); // 读取时也可能需要扩容
        pc->data[pc->count] = tmp;
        pc->count++;
    }
    fclose(pfRead);
}

// 将内存数据保存到文件
void SaveContact(const Contact* pc) {
    FILE* pfWrite = fopen("contact.txt", "wb");
    if (pfWrite == NULL) return;
    
    for (int i = 0; i < pc->count; i++) {
        fwrite(pc->data + i, sizeof(PeoInfo), 1, pfWrite);
    }
    fclose(pfWrite);
}

第5步:完善增删改查与排序逻辑

删除:通常采用“覆盖法”,即找到目标索引后,将后续所有元素前移一位,并 count--。
查找:遍历数组比对姓名。
排序:使用标准库函数 qsort,自定义比较函数 strcmp 按名字排序。

三、效果验证与测试

在实际运行中,我们可以通过以下现象验证功能是否正常:

1. 动态扩容触发验证

初始容量通常设为3(DEFAULT_SZ)。连续添加联系人,当第4个联系人加入时,控制台应输出“增容成功”提示,且此后继续添加不再受限,直到手动退出。

上述截图展示了从静态版本向动态版本过渡时的内存变化,以及多批次数据录入后的界面状态。

2. 文件持久化验证

添加若干联系人后,选择“退出”。此时检查当前目录下是否生成 contact.txt 文件。重新运行程序,选择“显示通讯录”,之前录入的数据应完整呈现,证明 LoadContact 功能生效。

四、总结与优化建议

本案例完整实现了C语言通讯录从理论到实践的全过程。相比静态数组,动态内存管理大幅提升了程序的健壮性和扩展性;文件IO操作则弥补了RAM易失性的短板。在实际开发中,还可进一步优化:例如增加错误处理机制(如输入非法字符)、使用更复杂的链表替代数组以优化删除性能,或集成 SQLite 数据库进行高效查询。

以上就是C语言动态/文件/静态功能版本的通讯录实现详细内容,更多关于C语言结构体实战的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。