当前位置: 首页 > news >正文

基于动态顺序表实现【通讯录系统】:有文件操作部分哦!

基于动态顺序表实现通讯录

在掌握了C语言语法基础数据结构之顺序表两个技术关键后,我们就到了将理论知识转化为实际应用是至关重要的环节。本文将通过实现一个完整的通讯录系统,展示如何将C语言基础知识和数据结构中的顺序表概念结合起来,构建一个实用的程序。

文章目录

  • 基于动态顺序表实现通讯录
    • 一、功能需求分析
    • 二、数据结构设计
      • 2.1 联系人信息结构
      • 2.2 动态顺序表结构
    • 三、核心功能实现详解
      • 3.1 初始化与扩容
        • 初始化通讯录
        • 动态扩容机制
      • 3.2 联系人管理功能
        • 添加联系人
        • 查找联系人
        • 删除联系人
        • 修改联系人
        • 销毁通讯录数据
      • 3.3 数据展示功能
      • 3.4 数据持久化
        • 保存到文件
        • 从文件读取
    • 五、源码汇总
      • 头文件 Contact.h
      • 源文件 Contact.c
      • 主程序 main.c
    • 结语


一、功能需求分析

通讯录系统需要具备以下核心功能:

  1. 基本存储功能

    • 至少能够存储100个人的通讯信息
    • 能够保存用户详细信息:姓名、性别、年龄、电话、地址等
  2. 核心操作功能

    • 增加联系人信息
    • 删除指定联系人
    • 查找指定联系人
    • 修改指定联系人
    • 显示所有联系人信息
  3. 数据持久化

    • 程序退出后自动保存数据
    • 程序启动时自动加载历史数据

二、数据结构设计

2.1 联系人信息结构

#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 12
#define ADDR_MAX 100typedef struct PersonInfo {char name[NAME_MAX];  // 姓名char sex[SEX_MAX];   // 性别int age;             // 年龄char tel[TEL_MAX];   // 电话char addr[ADDR_MAX]; // 地址
} PeoInfo;

2.2 动态顺序表结构

typedef struct Contact {PeoInfo* arr;    // 指向动态数组的指针int size;       // 当前联系人数量int capacity;   // 当前容量
} Contact;

三、核心功能实现详解

3.1 初始化与扩容

初始化通讯录
void ContactInit(Contact* con) {assert(con);con->arr = NULL;con->size = con->capacity = 0;
}
动态扩容机制
#define INIT_CAPACITY 4static void ConCheckCapacity(Contact* ps) {assert(ps);if (ps->capacity == ps->size) {int newcapacity = ps->capacity == 0 ? INIT_CAPACITY : ps->capacity * 2;PeoInfo* tmp = (PeoInfo*)realloc(ps->arr, sizeof(PeoInfo) * newcapacity);if (!tmp) {perror("realloc");exit(EXIT_FAILURE);}ps->arr = tmp;ps->capacity = newcapacity;}
}

3.2 联系人管理功能

添加联系人
void ContactAdd(Contact* con) {assert(con);PeoInfo pe;printf("请输入姓名: ");scanf("%99s", pe.name);printf("请输入性别: ");scanf("%3s", pe.sex);printf("请输入年龄: ");scanf("%d", &pe.age);while(getchar() != '\n'); // 清除输入缓冲区printf("请输入联系电话: ");scanf("%11s", pe.tel);printf("请输入地址: ");scanf("%99s", pe.addr);ConCheckCapacity(con);con->arr[con->size++] = pe;printf("添加成功!\n");
}
查找联系人
// 通过姓名查找联系人索引
int ContactFindByName(const Contact* con, const char* name) {assert(con && name);for (int i = 0; i < con->size; i++) {if (strcmp(con->arr[i].name, name) == 0)return i;}return -1;
}
void ContactFind(const Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}char findname[NAME_MAX];printf("请输入要查找的联系人姓名: ");scanf("%99s", findname);int ret = ContactFindByName(con, findname);if (ret >= 0) {printf("┌────────┬────────┬────────┬──────────────┬────────────────────┐\n");printf("│ 姓名   │ 性别   │ 年龄   │ 电话         │ 地址               │\n");printf("├────────┼────────┼────────┼──────────────┼────────────────────┤\n");printf("│ %-6s │ %-6s │ %-6d │ %-12s │ %-18s │\n",con->arr[ret].name,con->arr[ret].sex,con->arr[ret].age,con->arr[ret].tel,con->arr[ret].addr);printf("└────────┴────────┴────────┴──────────────┴────────────────────┘\n");} else {printf("未找到该联系人!\n");}
}
删除联系人
void ContactDel(Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}char delname[NAME_MAX];printf("请输入要删除的联系人姓名: ");scanf("%99s", delname);int ret = ConFindName(con, delname);if (ret >= 0) {for (int i = ret; i < con->size - 1; i++) {con->arr[i] = con->arr[i + 1];}con->size--;printf("删除成功!\n");} else {printf("未找到该联系人!\n");}
}
修改联系人
void ContactModify(Contact* con){assert(con);assert(con->size);printf("请输入你要修改的联系人姓名\n");char findname[NAME_MAX];scanf("%s", findname);int ret;if ((ret = ConFinename(con, findname)) >= 0){printf("请输入新的联系人信息\n");PeoInfo pe;printf("请输入姓名\n");scanf("%s", pe.name);printf("请输入性别\n");scanf("%s", pe.sex);printf("请输入年龄\n");scanf("%d", &pe.age);printf("请输入联系电话\n");scanf("%s", pe.tel);printf("请输入地址\n");scanf("%s", pe.addr);con->arr[ret] = pe;printf("修改成功\n");return;}printf("没有此联系人\n");
}
销毁通讯录数据
void ContactDestroy(Contact* con) {assert(con);free(con->arr);con->arr = NULL;con->size = con->capacity = 0;
}

3.3 数据展示功能

void ContactShow(const Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}printf("┌────────┬────────┬────────┬──────────────┬────────────────────┐\n");printf("│ 姓名   │ 性别   │ 年龄   │ 电话         │ 地址               │\n");printf("├────────┼────────┼────────┼──────────────┼────────────────────┤\n");for (int i = 0; i < con->size; i++) {printf("│ %-6s │ %-6s │ %-6d │ %-12s │ %-18s │\n",con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}printf("└────────┴────────┴────────┴──────────────┴────────────────────┘\n");
}

3.4 数据持久化

保存到文件
void ContactWrite(Contact* con) {assert(con);FILE* pf = fopen("Contact.dat", "wb");if (!pf) {perror("fopen");return;}for (int i = 0; i < con->size; i++) {if (fwrite(&con->arr[i], sizeof(PeoInfo), 1, pf) != 1) {perror("fwrite");break;}}fclose(pf);printf("数据已保存!\n");
}
从文件读取
void ContactRead(Contact* con) {assert(con);FILE* pf = fopen("Contact.dat", "rb");if (!pf) {// 文件不存在是正常情况return;}PeoInfo pe;while (fread(&pe, sizeof(PeoInfo), 1, pf) == 1) {ConCheckCapacity(con);con->arr[con->size++] = pe;}if (!feof(pf)) {perror("fread");}fclose(pf);printf("数据已加载!\n");
}

五、源码汇总

头文件 Contact.h

#ifndef __CONTACT_H__
#define __CONTACT_H__#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 12
#define ADDR_MAX 100
#define INIT_CAPACITY 4// 联系人信息结构
typedef struct PersonInfo {char name[NAME_MAX];  // 姓名char sex[SEX_MAX];    // 性别int age;              // 年龄char tel[TEL_MAX];    // 电话char addr[ADDR_MAX];  // 地址
} PeoInfo;// 动态顺序表结构
typedef struct Contact {PeoInfo* arr;        // 指向动态数组的指针int size;           // 当前联系人数量int capacity;       // 当前容量
} Contact;// 初始化通讯录
void ContactInit(Contact* con);// 销毁通讯录
void ContactDestroy(Contact* con);// 添加联系人
void ContactAdd(Contact* con);// 删除联系人
void ContactDel(Contact* con);// 查找联系人
void ContactFind(const Contact* con);// 修改联系人
void ContactModify(Contact* con);// 显示所有联系人
void ContactShow(const Contact* con);// 保存数据到文件
void ContactWrite(Contact* con);// 从文件读取数据
void ContactRead(Contact* con);#endif // __CONTACT_H__

源文件 Contact.c

#include "Contact.h"// 检查容量并扩容
void ContactCheckCapacity(Contact* ps) {assert(ps);if (ps->capacity == ps->size) {int newcapacity = ps->capacity == 0 ? INIT_CAPACITY : ps->capacity * 2;PeoInfo* tmp = (PeoInfo*)realloc(ps->arr, sizeof(PeoInfo) * newcapacity);if (!tmp) {perror("realloc");exit(EXIT_FAILURE);}ps->arr = tmp;ps->capacity = newcapacity;}
}// 通过姓名查找联系人索引
int ContactFindByName(const Contact* con, const char* name) {assert(con && name);for (int i = 0; i < con->size; i++) {if (strcmp(con->arr[i].name, name) == 0)return i;}return -1;
}void ContactInit(Contact* con) {assert(con);con->arr = NULL;con->size = con->capacity = 0;
}void ContactDestroy(Contact* con) {assert(con);free(con->arr);con->arr = NULL;con->size = con->capacity = 0;
}void ContactAdd(Contact* con) {assert(con);PeoInfo pe;printf("请输入姓名: ");scanf("%99s", pe.name);printf("请输入性别: ");scanf("%3s", pe.sex);printf("请输入年龄: ");scanf("%d", &pe.age);while(getchar() != '\n'); // 清除输入缓冲区printf("请输入联系电话: ");scanf("%11s", pe.tel);printf("请输入地址: ");scanf("%99s", pe.addr);ContactCheckCapacity(con);con->arr[con->size++] = pe;printf("添加成功!\n");
}void ContactDel(Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}char delname[NAME_MAX];printf("请输入要删除的联系人姓名: ");scanf("%99s", delname);int ret = ContactFindByName(con, delname);if (ret >= 0) {for (int i = ret; i < con->size - 1; i++) {con->arr[i] = con->arr[i + 1];}con->size--;printf("删除成功!\n");} else {printf("未找到该联系人!\n");}
}void ContactFind(const Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}char findname[NAME_MAX];printf("请输入要查找的联系人姓名: ");scanf("%99s", findname);int ret = ContactFindByName(con, findname);if (ret >= 0) {printf("┌────────┬────────┬────────┬──────────────┬────────────────────┐\n");printf("│ 姓名   │ 性别   │ 年龄   │ 电话         │ 地址               │\n");printf("├────────┼────────┼────────┼──────────────┼────────────────────┤\n");printf("│ %-6s │ %-6s │ %-6d │ %-12s │ %-18s │\n",con->arr[ret].name,con->arr[ret].sex,con->arr[ret].age,con->arr[ret].tel,con->arr[ret].addr);printf("└────────┴────────┴────────┴──────────────┴────────────────────┘\n");} else {printf("未找到该联系人!\n");}
}void ContactModify(Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}char modname[NAME_MAX];printf("请输入要修改的联系人姓名: ");scanf("%99s", modname);int ret = ContactFindByName(con, modname);if (ret >= 0) {PeoInfo pe;printf("请输入新的姓名: ");scanf("%99s", pe.name);printf("请输入新的性别: ");scanf("%3s", pe.sex);printf("请输入新的年龄: ");scanf("%d", &pe.age);while(getchar() != '\n');printf("请输入新的联系电话: ");scanf("%11s", pe.tel);printf("请输入新的地址: ");scanf("%99s", pe.addr);con->arr[ret] = pe;printf("修改成功!\n");} else {printf("未找到该联系人!\n");}
}void ContactShow(const Contact* con) {assert(con);if (con->size == 0) {printf("通讯录为空!\n");return;}printf("┌────────┬────────┬────────┬──────────────┬────────────────────┐\n");printf("│ 姓名   │ 性别   │ 年龄   │ 电话         │ 地址               │\n");printf("├────────┼────────┼────────┼──────────────┼────────────────────┤\n");for (int i = 0; i < con->size; i++) {printf("│ %-6s │ %-6s │ %-6d │ %-12s │ %-18s │\n",con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}printf("└────────┴────────┴────────┴──────────────┴────────────────────┘\n");
}void ContactWrite(Contact* con) {assert(con);FILE* pf = fopen("Contact.txt", "wb");if (!pf) {perror("fopen");return;}for (int i = 0; i < con->size; i++) {if (fwrite(&con->arr[i], sizeof(PeoInfo), 1, pf) != 1) {perror("fwrite");break;}}fclose(pf);printf("数据已保存!\n");
}void ContactRead(Contact* con) {assert(con);FILE* pf = fopen("Contact.txt", "rb");if (!pf) {// 文件不存在是正常情况return;}PeoInfo pe;while (fread(&pe, sizeof(PeoInfo), 1, pf) == 1) {ContactCheckCapacity(con);con->arr[con->size++] = pe;}if (!feof(pf)) {perror("fread");}fclose(pf);printf("数据已加载!\n");
}

主程序 main.c

#include "Contact.h"void menu() {printf("\n========== 通讯录管理系统 ==========\n");printf("1. 添加联系人\n");printf("2. 删除联系人\n");printf("3. 查找联系人\n");printf("4. 修改联系人\n");printf("5. 显示所有联系人\n");printf("6. 保存数据\n");printf("0. 退出系统\n");printf("==================================\n");
}int main() {Contact con;ContactInit(&con);ContactRead(&con); // 启动时加载数据int choice = -1;do {menu();printf("请选择操作(0-6): ");scanf("%d", &choice);while(getchar() != '\n'); // 清除输入缓冲区switch (choice) {case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactFind(&con);break;case 4:ContactModify(&con);break;case 5:ContactShow(&con);break;case 6:ContactWrite(&con);break;case 0:printf("感谢使用,再见!\n");break;default:printf("无效输入,请重新选择!\n");break;}printf("\n按Enter键继续...");while(getchar() != '\n');} while (choice != 0);ContactDestroy(&con);return 0;
}

接下来,就可以得到一个完整的通讯录项目了。

结语

通过这个通讯录系统的实现,我们不仅巩固了C语言的基本语法,更重要的是理解了如何将数据结构的知识应用到实际问题中。这种从理论到实践的转化能力,才是我们在学习中最宝贵的收获。
友情链接:从零开始构建【顺序表】:C语言实现与项目实战准备

http://www.lryc.cn/news/617658.html

相关文章:

  • 用 Docker 安装并启动 Redis:从入门到实战
  • Spring AI赋能图像识别:大数据模型驱动下的智能化变革
  • Webpack Loader 完全指南:从原理到配置的深度解析
  • 关于JavaScript 性能优化的实战指南
  • MySQL的索引(索引的数据结构-B+树索引):
  • Godot ------ 平滑拖动01
  • vue3中的子组件向父组件通信和父组件向子组件通信
  • 对抗样本攻击检测与防御
  • STM32 ESP8266 WiFi模块驱动
  • JVM管理数据的方式
  • CV 医学影像分类、分割、目标检测,之分类项目拆解
  • 【Lua】题目小练10
  • explicit的作用是什么
  • GaussDB安全配置全景指南:构建企业级数据库防护体系
  • Mybatis学习之逆向工程(十)
  • Java项目基本流程(三)
  • SSM+Dubbo+Zookeeper框架和springcloud框架,写业务的时候主要区别在哪?
  • K8S学习----应用部署架构:传统、虚拟化与容器的演进与对比
  • Jenkins 搭建鸿蒙打包
  • 基于 ZooKeeper 的分布式锁实现原理是什么?
  • 车载软件架构 --- 车辆量产后怎么刷写Flash Bootloader
  • 品质检验·稽核管理·客诉管理一站式数字化平台——全星质量管理 QMS 软件系统
  • 打烊频率?阶段说了算
  • 【AI论文】R-Zero:从零数据起步的自进化推理大语言模型
  • 从源码看 Coze:Agent 的三大支柱是如何构建的?
  • AI测试平台实战:深入解析自动化评分和多模型对比评测
  • [CSP-J 2021] 小熊的果篮
  • 记录一些sonic自动化运行中的问题
  • “一车一码一池一充”:GB 17761-2024新国标下电动自行车的安全革命
  • 【C++竞赛】核桃CSP-J模拟赛题解