首页 > 应用开发 > IT综合 > C语言项目实战:动态通讯录系统开发全流程解析
**C语言项目实战:动态通讯录系统开发全流程解析**
通讯录系统是学习C语言的经典项目,它综合运用了结构体、指针、动态内存管理和文件操作等核心概念。本文将完整展示从零构建一个功能完善的动态通讯录系统。
### 项目需求分析与设计
首先明确通讯录系统的功能需求和技术架构。
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_NAME_LEN 50
#define MAX_PHONE_LEN 20
#define MAX_ADDRESS_LEN 100
#define INITIAL_CAPACITY 10
// 联系人结构体设计
typedef struct {
int id; // 联系人ID
char name[MAX_NAME_LEN]; // 姓名
char phone[MAX_PHONE_LEN]; // 电话
char address[MAX_ADDRESS_LEN]; // 地址
int age; // 年龄
char group[20]; // 分组
} Contact;
// 通讯录管理系统结构体
typedef struct {
Contact *contacts; // 动态数组指针
int count; // 当前联系人数量
int capacity; // 当前容量
int next_id; // 下一个可用的ID
} AddressBook;
// 函数声明
void initAddressBook(AddressBook *book);
void addContact(AddressBook *book);
void displayContacts(const AddressBook *book);
void searchContact(const AddressBook *book);
void deleteContact(AddressBook *book);
void modifyContact(AddressBook *book);
void saveToFile(const AddressBook *book);
void loadFromFile(AddressBook *book);
void freeAddressBook(AddressBook *book);
void sortContacts(AddressBook *book);
```
### 核心数据结构实现
实现通讯录的初始化、扩容和内存管理。
```c
// 初始化通讯录
void initAddressBook(AddressBook *book) {
book->contacts = (Contact *)malloc(INITIAL_CAPACITY * sizeof(Contact));
if (book->contacts == NULL) {
printf("内存分配失败!\n");
exit(1);
}
book->count = 0;
book->capacity =<"BN.6370.HK"> INITIAL_CAPACITY;
book->next_id = 1;
printf("通讯录初始化成功,初始容量:%d\n", INITIAL_CAPACITY);
}
// 动态扩容
void expandCapacity(AddressBook *book) {
int new_capacity = book->capacity * 2;
Contact *new_contacts = (Contact *)realloc(book->contacts, new_capacity * sizeof(Contact));
if (new_contacts == NULL) {
printf("内存扩容失败!\n");
return;
}
book->contacts = new_contacts;
book->capacity = new_capacity;
printf("通讯录已扩容,新容量:%d\n", new_capacity);
}
// 释放内存
void freeAddressBook(AddressBook *book) {
if (book->contacts != NULL) {
free(book->contacts);
book->contacts = NULL;
}
book->count = 0;
book->capacity = 0;
book->next_id = 1;
printf("通讯录内存已释放\n");
}
// 输入工具函数
void getInput(char *buffer, int max_len, const char *prompt) {
printf("%s", prompt);
fgets(buffer, max_len, stdin);
buffer[strcspn(buffer, "\n")] = '\0'; // 移除换行符
}
int getIntInput(const char *prompt) {
char buffer[20];
getInput(buffer, sizeof(buffer), prompt);
return atoi(buffer);
}
```
### 联系人管理功能实现
实现联系人的增删改查等核心功能。
```c
// 添加联系人
void addContact(AddressBook *book) {
// 检查是否需要扩容
if (book->count >= book->capacity) {
expandCapacity(book);
}
Contact *new_contact = &book->contacts[book->count];
// 自动分配ID
new_contact-><"ES.6370.HK">id = book->next_id++;
// 输入联系人信息
printf("\n=== 添加新联系人 ===\n");
getInput(new_contact->name, MAX_NAME_LEN, "请输入姓名: ");
getInput(new_contact->phone, MAX_PHONE_LEN, "请输入电话: ");
getInput(new_contact->address, MAX_ADDRESS_LEN, "请输入地址: ");
new_contact->age = getIntInput("请输入年龄: ");
getInput(new_contact->group, 20, "请输入分组: ");
book->count++;
printf("联系人添加成功!ID: %d\n", new_contact->id);
}
// 显示所有联系人
void displayContacts(const AddressBook *book) {
printf("\n=== 通讯录列表 (共%d个联系人) ===\n", book->count);
printf("%-4s %-15s %-15s %-8s %-10s %-20s\n",
"ID", "姓名", "电话", "年龄", "分组", "地址");
printf("------------------------------------------------------------------------\n");
for (int i = 0; i < book->count; i++) {
Contact *contact = &book->contacts[i];
printf("%-4d %-15s %-15s %-8d %-10s %-20s\n",
contact->id, contact->name, contact->phone,
contact->age, contact->group, contact->address);
}
}
// 查找联系人(支持按姓名和电话查找)
void searchContact(const AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,无法查找!\n");
return;
}
char keyword[MAX_NAME_LEN];
getInput(keyword, sizeof(keyword), "请输入姓名或电话进行搜索: ");
printf("\n=== 搜索结果 ===\n");
printf("%-4s %-15s %-15s %-8s %-10s %-20s\n",
"ID", "姓名", "电话", "年龄", "分组", "地址");
printf("------------------------------------------------------------------------\n");
int found = 0;
for (int i = 0; i < book->count; i++) {
Contact *contact = &book->contacts[i];
if (strstr(contact->name, keyword) != NULL ||
strstr(contact->phone, keyword) != NULL) {
printf("%-4d %-15s %-15s %-8d %-10s %-20s\n",
contact->id, contact->name, contact->phone,
contact->age, contact->group, contact->address);
found = 1;
}
}
if (!found) {
printf("未找到匹配的联系人!\n");
}
}
// 删除联系人
void deleteContact(AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,无法删除!\n");
return;
}
displayContacts(book);
int id = getIntInput("\n请输入要删除的联系人ID: ");
int found_index = -1;
for (int i = 0; i < book->count; i++) {
if (book->contacts[i].id == id) {
found_index = i;
break;
}
}
if (found_index == -1) {
printf("未找到ID为%d的联系人!\n", id);
return;
}
// 显示要删除的联系人信息
Contact *contact = &book->contacts[found_index];
printf("即将删除联系人:\n");
printf("ID: %d, 姓名: %s, 电话: %s\n", contact->id, contact->name, contact->phone);
char confirm;
printf("确认删除?(y/n): ");
scanf<"PX.6370.HK">(" %c", &confirm);
getchar(); // 清除缓冲区
if (confirm == 'y' || confirm == 'Y') {
// 将后面的元素前移
for (int i = found_index; i < book->count - 1; i++) {
book->contacts[i] = book->contacts[i + 1];
}
book->count--;
printf("联系人删除成功!\n");
} else {
printf("取消删除操作。\n");
}
}
// 修改联系人
void modifyContact(AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,无法修改!\n");
return;
}
displayContacts(book);
int id = getIntInput("\n请输入要修改的联系人ID: ");
int found_index = -1;
for (int i = 0; i < book->count; i++) {
if (book->contacts[i].id == id) {
found_index = i;
break;
}
}
if (found_index == -1) {
printf("未找到ID为%d的联系人!\n", id);
return;
}
Contact *contact = &book->contacts[found_index];
printf("\n当前联系人信息:\n");
printf("ID: %d\n", contact->id);
printf("1. 姓名: %s\n", contact->name);
printf("2. 电话: %s\n", contact->phone);
printf("3. 地址: %s\n", contact->address);
printf("4. 年龄: %d\n", contact->age);
printf("5. 分组: %s\n", contact->group);
int choice = getIntInput("\n请选择要修改的字段 (1-5): ");
switch (choice) {
case 1:
getInput(contact->name, MAX_NAME_LEN, "请输入新姓名: ");
break;
case 2:
getInput(contact->phone, MAX_PHONE_LEN, "请输入新电话: ");
break;
case 3:
getInput(contact->address, MAX_ADDRESS_LEN, "请输入新地址: ");
break;
case 4:
contact->age = getIntInput("请输入新年龄: ");
break;
case 5:
getInput(contact->group, 20, "请输入新分组: ");
break;
default:
printf("无效的选择!\n");
return;
}
printf("联系人信息修改成功!\n");
}
```
### 文件操作实现
实现数据的持久化存储和加载。
```c
// 保存到文件
void saveToFile(const AddressBook *book) {
FILE *file = fopen("addressbook.dat", "wb");
if (file == NULL) {
printf("无法创建文件!\n");
return;
}
// 先写入联系人数量
fwrite(&book->count, sizeof(int), 1, file);
fwrite(&book->next_id, sizeof(int), 1, file);
// 写入所有联系人数据
for (int i = 0; i < book->count; i++) {
fwrite(&book-><"QJ.6370.HK">contacts[i], sizeof(Contact), 1, file);
}
fclose(file);
printf("数据已保存到文件,共保存%d个联系人\n", book->count);
}
// 从文件加载
void loadFromFile(AddressBook *book) {
FILE *file = fopen("addressbook.dat", "rb");
if (file == NULL) {
printf("文件不存在或无法打开,将创建新的通讯录\n");
return;
}
// 读取联系人数量和下一个ID
int count, next_id;
fread(&count, sizeof(int), 1, file);
fread(&next_id, sizeof(int), 1, file);
if (count <= 0) {
fclose(file);
printf("文件数据无效\n");
return;
}
// 确保容量足够
while (book->capacity < count) {
expandCapacity(book);
}
// 读取联系人数据
for (int i = 0; i < count; i++) {
fread(&book->contacts[i], sizeof(Contact), 1, file);
}
book->count = count;
book->next_id = next_id;
fclose(file);
printf("从文件加载成功,共加载%d个联系人\n", count);
}
// 导出为文本文件
void exportToTextFile(const AddressBook *book) {
FILE *file = fopen("addressbook.txt", "w");
if (file == NULL) {
printf("无法创建文本文件!\n");
return;
}
fprintf(file, "=== 通讯录导出数据 ===\n");
fprintf(file, "总联系人数量: %d\n\n", book->count);
for (int i = 0; i < book->count; i++) {
Contact *contact = &book->contacts[i];
fprintf(file, "联系人 #%d:\n", i + 1);
fprintf(file, " ID: %d\n", contact->id);
fprintf(file, " 姓名: %s\n", contact->name);
fprintf(file, " 电话: %s\n", contact->phone);
fprintf(file, " 地址: %s\n", contact->address);
fprintf(file, " 年龄: %d\n", contact->age);
fprintf(file, " 分组: %s\n", contact->group);
fprintf(file, "------------------------\n");
}
fclose(file);
printf("数据已导出到文本文件 addressbook.txt\n");
}
```
### 排序和统计功能
```c
// 比较函数用于排序
int compareByName(const void *a, const void *b) {
const Contact *contactA = (const Contact *)a;
const Contact *contactB = (const Contact *)b;
return strcmp(contactA->name, contactB->name);
}
int compareByAge(const void *a, const void *b) {
const Contact *contactA = (const Contact *)a;
const Contact *contactB = (const Contact *)b;
return contactA->age - contactB->age;
}
// 排序联系人
void sortContacts(AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,无法排序!\n");
return;
}
printf("\n请选择排序方式:\n");
printf("1. 按姓名排序\n");
printf("2. 按年龄排序\n");
int choice = getIntInput("请选择 (1-2): ");
switch (choice) {
case 1:
qsort(book->contacts, book->count, sizeof(Contact), compareByName);
printf("已按姓名排序\n");
break;
case 2:
qsort(book->contacts, book->count, sizeof(Contact), compareByAge);
printf("已按年龄排序\n");
break;
default:
printf("无效的选择!\n");
return;
}
displayContacts(book);
}
// 统计信息
void showStatistics(const AddressBook *book) {
if (book->count == 0) {
printf("通讯录为空,无法统计!\n");
return;
}
printf("\n=== 通讯录统计信息 ===\n");
printf("总联系人数量: %d\n", book->count);
printf("当前容量: %d\n", book->capacity);
printf("空间使用率: %.1f%%\n", (float)book->count / book->capacity * 100);
// 分组统计
int group_count = 0;
char groups[100][20];
int group_sizes[100] = {0};
for (int i = 0; i < book->count; i++) {
char *group = book->contacts[i].group;
int found = 0;
for (int j = 0; j < group_count; j++) {
if (strcmp(groups[j], group) == 0) {
group_sizes[j]++;
found = 1;
break;
}
}
if (!found && group_count < 100) {
strcpy(groups[group_count], group);
group_sizes[group_count] = 1;
group_count++<"HL.6370.HK">;
}
}
printf("\n分组统计:\n");
for (int i = 0; i < group_count; i++) {
printf(" %s: %d人\n", groups[i], group_sizes[i]);
}
// 年龄统计
int age_groups[6] = {0}; // 0: <18, 1: 18-25, 2: 26-35, 3: 36-50, 4: 51-65, 5: >65
const char *age_labels[] = {"未成年(<18)", "青年(18-25)", "青壮年(26-35)",
"中年(36-50)", "中老年(51-65)", "老年(>65)"};
for (int i = 0; i < book->count; i++) {
int age = book->contacts[i].age;
if (age < 18) age_groups[0]++;
else if (age <= 25) age_groups[1]++;
else if (age <= 35) age_groups[2]++;
else if (age <= 50) age_groups[3]++;
else if (age <= 65) age_groups[4]++;
else age_groups[5]++;
}
printf("\n年龄分布:\n");
for (int i = 0; i < 6; i++) {
if (age_groups[i] > 0) {
printf(" %s: %d人 (%.1f%%)\n", age_labels[i], age_groups[i],
(float)age_groups[i] / book->count * 100);
}
}
}
```
### 主程序与用户界面
```c
// 显示菜单
void showMenu() {
printf("\n=== 动态通讯录管理系统 ===\n");
printf("1. 添加联系人\n");
printf("2. 显示所有联系人\n");
printf("3. 查找联系人\n");
printf("4. 删除联系人\n");
printf("5. 修改联系人\n");
printf("6. 排序联系人\n");
printf("7. 统计信息\n");
printf("8. 保存到文件\n");
printf("9. 从文件加载\n");
printf("10. 导出为文本文件\n");
printf("0. 退出系统\n");
printf("------------------------\n");
}
// 主函数
int main() {
AddressBook addressBook;
printf("欢迎使用动态通讯录管理系统!\n");
// 初始化通讯录
initAddressBook(&addressBook);
// 尝试从文件加载数据
loadFromFile(&addressBook);
int choice;
do {
showMenu();
choice = getIntInput("请选择操作 (0-10): ");
switch (choice) {
case 1:
addContact(&addressBook);
break;
case 2:
displayContacts(&addressBook);
break;
case 3:
searchContact(&addressBook);
break;
case 4:
deleteContact(&addressBook);
break;
case 5:
modifyContact(&addressBook);
break;
case 6:
sortContacts(&addressBook);
break;
case 7:
showStatistics(&addressBook);
break;
case 8:
saveToFile(&addressBook);
break;
case 9:
loadFromFile(&addressBook);
break;
case 10:
exportToTextFile(&addressBook);
break;
case 0:
printf("感谢使用通讯录管理系统!\n");
break;
default:
printf("无效的选择,请重新输入!\n");
}
// 每次操作后暂停
if (choice != 0) {
printf("\n按回车键继续...");
getchar();
}
} while (choice != 0);
// 退出前保存数据
char save;
printf("是否保存数据到文件?(y/n): ");
scanf(" %c", &save);
if (save == 'y' || save == 'Y') {
saveToFile(&addressBook);
}
// 释放内存
freeAddressBook(&addressBook);
return 0;
}
```
### 项目总结与扩展建议
通过这个动态通讯录系统项目,我们实践了以下C语言核心概念:
1. **结构体应用**:合理设计数据结构表示现实世界实体
2. **动态内存管理**:使用malloc/realloc/free实现动态数组
3. **文件操作**:二进制文件和文本文件的读写操作
4. **指针运用**:结构体指针、数组指针的灵活使用
5. **模块化设计**:功能分解为独立的函数模块
**扩展建议**:
- 添加联系人去重功能
- 实现分组管理和批量操作
- 添加生日提醒功能
- 支持多种排序方式
- 实现数据备份和恢复功能
- 添加密码保护功能
这个项目为学习更复杂的C语言应用程序开发奠定了坚实基础。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3103363/ ,如需转载,请注明出处,否则将追究法律责任。