我们将创建一个基于文件存储的命令行通讯录管理系统,这个程序可以实现以下核心功能:
- 添加联系人:可以输入姓名、电话、性别、邮箱等信息。
- 显示所有联系人:以表格形式列出通讯录中的所有人。
- 按姓名查找联系人:根据姓名精确查找并显示信息。
- 删除联系人:根据姓名删除指定的联系人。
- 修改联系人信息:根据姓名找到联系人并修改其信息。
- 数据持久化:所有联系人信息会自动保存在一个名为
contacts.dat的文件中,程序关闭后重新打开,数据依然存在。 - 清空通讯录:一键清空所有联系人。
- 退出系统:安全退出系统,并保存数据。
项目结构
为了代码清晰,我们将代码分成三个文件:
main.c: 主程序文件,包含主菜单和函数调用逻辑。contacts.h: 头文件,包含结构体定义、函数声明和常量。contacts.c: 功能实现文件,包含所有核心功能的函数实现。
代码实现
1 头文件 contacts.h
这个文件定义了联系人的数据结构、程序用到的常量以及所有需要被其他文件调用的函数。
// contacts.h
#ifndef CONTACTS_H
#define CONTACTS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义最大姓名长度和电话号码长度
#define MAX_NAME_LEN 50
#define MAX_PHONE_LEN 20
#define MAX_EMAIL_LEN 50
#define MAX_GENDER_LEN 10
// 定义联系人结构体
typedef struct {
char name[MAX_NAME_LEN];
char phone[MAX_PHONE_LEN];
char gender[MAX_GENDER_LEN];
char email[MAX_EMAIL_LEN];
} Contact;
// 定义通讯录结构体,可以存储多个联系人
typedef struct {
Contact contacts[1000]; // 假设最多存储1000个联系人
int count; // 当前联系人数量
} AddressBook;
// 函数声明
void initAddressBook(AddressBook *book);
void saveToFile(AddressBook *book);
void loadFromFile(AddressBook *book);
void showMenu();
void addContact(AddressBook *book);
void displayContacts(AddressBook *book);
void findContact(AddressBook *book);
void deleteContact(AddressBook *book);
void modifyContact(AddressBook *book);
void clearContacts(AddressBook *book);
#endif // CONTACTS_H
2 功能实现文件 contacts.c
这个文件包含了所有核心功能的C语言代码实现。
// contacts.c
#include "contacts.h"
// 初始化通讯录
void initAddressBook(AddressBook *book) {
book->count = 0;
loadFromFile(book); // 启动时自动加载数据
}
// 将通讯录数据保存到文件
void saveToFile(AddressBook *book) {
FILE *fp = fopen("contacts.dat", "wb");
if (fp == NULL) {
printf("错误:无法打开文件进行保存!\n");
return;
}
fwrite(book, sizeof(AddressBook), 1, fp);
fclose(fp);
}
// 从文件加载通讯录数据
void loadFromFile(AddressBook *book) {
FILE *fp = fopen("contacts.dat", "rb");
if (fp == NULL) {
// 文件不存在是正常情况(第一次运行)
return;
}
fread(book, sizeof(AddressBook), 1, fp);
fclose(fp);
}
// 显示主菜单
void showMenu() {
printf("\n\n");
printf("========== 小组通讯录管理系统 ==========\n");
printf(" 1. 添加联系人\n");
printf(" 2. 显示所有联系人\n");
printf(" 3. 查找联系人\n");
printf(" 4. 删除联系人\n");
printf(" 5. 修改联系人\n");
printf(" 6. 清空通讯录\n");
printf(" 0. 退出系统\n");
printf("========================================\n");
printf("请输入您的选择 (0-6): ");
}
// 添加联系人
void addContact(AddressBook *book) {
if (book->count >= 1000) {
printf("通讯录已满,无法添加!\n");
return;
}
Contact newContact;
printf("请输入姓名: ");
scanf("%s", newContact.name);
printf("请输入电话: ");
scanf("%s", newContact.phone);
printf("请输入性别: ");
scanf("%s", newContact.gender);
printf("请输入邮箱: ");
scanf("%s", newContact.email);
book->contacts[book->count] = newContact;
book->count++;
printf("联系人添加成功!\n");
saveToFile(book); // 保存到文件
}
// 显示所有联系人
void displayContacts(AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,没有联系人可显示,\n");
return;
}
printf("\n%-20s %-15s %-10s %-30s\n", "姓名", "电话", "性别", "邮箱");
printf("------------------------------------------------------------\n");
for (int i = 0; i < book->count; i++) {
printf("%-20s %-15s %-10s %-30s\n",
book->contacts[i].name,
book->contacts[i].phone,
book->contacts[i].gender,
book->contacts[i].email);
}
}
// 按姓名查找联系人
void findContact(AddressBook *book) {
char name[MAX_NAME_LEN];
printf("请输入要查找的联系人姓名: ");
scanf("%s", name);
int found = 0;
for (int i = 0; i < book->count; i++) {
if (strcmp(book->contacts[i].name, name) == 0) {
printf("\n找到联系人!\n");
printf("姓名: %s\n", book->contacts[i].name);
printf("电话: %s\n", book->contacts[i].phone);
printf("性别: %s\n", book->contacts[i].gender);
printf("邮箱: %s\n", book->contacts[i].email);
found = 1;
break; // 找到第一个后停止
}
}
if (!found) {
printf("未找到姓名为 '%s' 的联系人,\n", name);
}
}
// 删除联系人
void deleteContact(AddressBook *book) {
char name[MAX_NAME_LEN];
printf("请输入要删除的联系人姓名: ");
scanf("%s", name);
int foundIndex = -1;
for (int i = 0; i < book->count; i++) {
if (strcmp(book->contacts[i].name, name) == 0) {
foundIndex = i;
break;
}
}
if (foundIndex == -1) {
printf("未找到姓名为 '%s' 的联系人,\n", name);
return;
}
// 将后面的联系人前移,覆盖要删除的联系人
for (int i = foundIndex; i < book->count - 1; i++) {
book->contacts[i] = book->contacts[i + 1];
}
book->count--;
printf("联系人 '%s' 删除成功!\n", name);
saveToFile(book); // 保存到文件
}
// 修改联系人
void modifyContact(AddressBook *book) {
char name[MAX_NAME_LEN];
printf("请输入要修改的联系人姓名: ");
scanf("%s", name);
int foundIndex = -1;
for (int i = 0; i < book->count; i++) {
if (strcmp(book->contacts[i].name, name) == 0) {
foundIndex = i;
break;
}
}
if (foundIndex == -1) {
printf("未找到姓名为 '%s' 的联系人,\n", name);
return;
}
printf("找到了联系人 '%s',请输入新的信息:\n", name);
printf("请输入新电话 (原: %s): ", book->contacts[foundIndex].phone);
scanf("%s", book->contacts[foundIndex].phone);
printf("请输入新性别 (原: %s): ", book->contacts[foundIndex].gender);
scanf("%s", book->contacts[foundIndex].gender);
printf("请输入新邮箱 (原: %s): ", book->contacts[foundIndex].email);
scanf("%s", book->contacts[foundIndex].email);
printf("联系人信息修改成功!\n");
saveToFile(book); // 保存到文件
}
// 清空通讯录
void clearContacts(AddressBook *book) {
char confirm;
printf("警告:此操作将清空所有联系人数据,且无法恢复!\n");
printf("您确定要继续吗?(y/n): ");
scanf(" %c", &confirm); // 注意前面的空格,用于吸收回车
if (confirm == 'y' || confirm == 'Y') {
book->count = 0;
// 删除文件以清空数据
remove("contacts.dat");
printf("通讯录已清空,\n");
} else {
printf("操作已取消,\n");
}
}
3 主程序文件 main.c
这个文件是程序的入口,负责调用其他函数,形成完整的交互流程。
// main.c
#include "contacts.h"
int main() {
AddressBook book;
initAddressBook(&book); // 初始化通讯录,加载文件数据
int choice;
do {
showMenu();
scanf("%d", &choice);
switch (choice) {
case 1:
addContact(&book);
break;
case 2:
displayContacts(&book);
break;
case 3:
findContact(&book);
break;
case 4:
deleteContact(&book);
break;
case 5:
modifyContact(&book);
break;
case 6:
clearContacts(&book);
break;
case 0:
printf("感谢使用,再见!\n");
break;
default:
printf("无效的输入,请重新输入 (0-6)!\n");
}
} while (choice != 0);
return 0;
}
如何编译和运行
-
保存文件:将上面的三段代码分别保存为
main.c、contacts.c和contacts.h,并将它们放在同一个文件夹下。 -
编译:打开你的终端(Windows上是CMD或PowerShell,Linux或macOS上是Terminal),进入文件所在的目录,然后使用GCC编译器进行编译。
# 编译 main.c 和 contacts.c,并生成一个名为 address_book 的可执行文件 gcc main.c contacts.c -o address_book
-
运行:
- 在Windows上:
address_book.exe
- 在Linux或macOS上:
./address_book
- 在Windows上:
程序启动后,你就可以通过输入数字来选择不同的功能了,当你添加或修改联系人后,一个名为 contacts.dat 的文件会自动创建或更新在同一个目录下,用于存储数据。
项目特点与改进方向
特点:
- 模块化设计:代码结构清晰,职责分明,易于维护和扩展。
- 数据持久化:使用文件保存数据,解决了程序关闭后数据丢失的问题。
- 用户友好:提供清晰的菜单和提示信息。
- 健壮性:处理了文件打开失败等基本错误情况。
可以进一步改进的方向(适合进阶学习):
- 输入验证:增加对电话号码(必须是数字)、邮箱格式的验证。
- 动态内存分配:目前使用固定大小的数组(1000人),可以改为动态分配内存,实现按需增长。
- 排序功能:增加按姓名或电话号码排序的功能。
- 模糊查找:实现不输入完整姓名即可查找的功能(输入“张”可以查到所有姓张的人)。
- 更美观的界面:使用一些简单的控制台库(如
ncurses)来美化界面。 - 加密存储:对存储的文件进行加密,保护隐私。
这个项目是一个非常好的C语言综合练习,涵盖了结构体、文件操作、函数、指针、循环和条件判断等核心知识点,希望对你有帮助!
