C語言代碼實現通訊錄管理系統
本文實例為大家分享了C語言實現通訊錄管理系統,供大家參考,具體內容如下
一、需求分析
運用C語言實現一個簡單的通訊錄管理系統,要求對數據有 增刪改查清排顯 等功能的實現(這里由于還沒學到文件,所以下面所有的存儲都是在內存中,也就是當程序結束的時候添加的信息都會清空掉 - 后續(xù)會加以改進的)
二、程序結構
在基本的程序設計中,都會將項目分為三個文件:
1、test.c - 主函數(負責調用各個功能的接口)
2、contact.c - 實現各個模塊的功能
3、contact.h - 用于存放頭文件、宏定義、函數聲明等
三、頭文件內容的介紹
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 50
#define TELE_MAX 12
#define DEFAULT_SZ 3
// 數組版本
//typedef struct PeoInfo
//{
//?? ?char name[NAME_MAX];
//?? ?int age;
//?? ?char sex[SEX_MAX];
//?? ?char addr[ADDR_MAX];
//?? ?char tele[TELE_MAX];
//}PeoInfo;
//
//typedef struct Contact
//{
//?? ?//PeoInfo data[MAX]; ?// 存放信息
//?? ?PeoInfo data[MAX];
//?? ?int sz; // 存放通訊錄有幾個人的信息
//}Contact;
// 每個人的基本信息
typedef struct PeoInfo
{
?? ?char name[NAME_MAX];
?? ?int age;
?? ?char sex[SEX_MAX];
?? ?char addr[ADDR_MAX];
?? ?char tele[TELE_MAX];
}PeoInfo;
typedef struct Contact
{
?? ?//PeoInfo data[MAX]; ?// 存放信息
?? ?PeoInfo* data;
?? ?int sz; // 存放通訊錄有幾個人的信息
?? ?int capacity; // 記錄當前通訊錄的最大容量
}Contact;
void DestoryContact(Contact* pc);
void InitContact(Contact* pc);
void AddContact(Contact* pc);
void ShowContact(const Contact* pc);
void DeleteContact(Contact* pc);
void SearchContact(const Contact* pc);
void ModifyContact(Contact* pc);
void SortContact(Contact* pc);里面被注釋的代碼則是之前的數組版本,規(guī)定死了通訊錄大?。欢旅嫖覀儠脛討B(tài)增容來進行實現。頭文件里面用宏定義主要為了之后我們更改對應的大小的時候更加的方便;結構體主要存放的就是三大部分:
1. 一個指向每個人基本信息的結構體指針;2. sz記錄著通訊錄的記錄條數;3. capacity 存放通訊錄的容量
四、模塊化實現各個功能
(1)主函數實現
int main()
{
?? ?int input = 0;
?? ?Contact con; // 創(chuàng)建通訊錄
?? ?InitContact(&con);
?? ?do
?? ?{
?? ??? ?menu();
?? ??? ?printf("請選擇:->");
?? ??? ?scanf("%d", &input);
?? ??? ?switch (input)
?? ??? ?{
?? ??? ?case ADD:
?? ??? ??? ?AddContact(&con);
?? ??? ??? ?break;
?? ??? ?case DEL:
?? ??? ??? ?DeleteContact(&con);
?? ??? ??? ?break;
?? ??? ?case SEARCH:
?? ??? ??? ?SearchContact(&con);
?? ??? ??? ?break;
?? ??? ?case MODIFY:
?? ??? ??? ?ModifyContact(&con);
?? ??? ??? ?break;
?? ??? ?case SORT:
?? ??? ??? ?SortContact(&con);
?? ??? ??? ?break;
?? ??? ?case SHOW:
?? ??? ??? ?ShowContact(&con);
?? ??? ??? ?break;
?? ??? ?case EXIT:
?? ??? ??? ?DestoryContact(&con);
?? ??? ??? ?printf("退出\n");
?? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?printf("輸入錯誤,請重新輸入\n");
?? ??? ??? ?break;
?? ??? ?}
?? ?} while (input);
?? ?return 0;
}一般函數的主函數里面都可以用do ……while結構來控制程序的執(zhí)行順序,在case后面用的則是 枚舉常量 ,這樣能做到更好的見名知意。
(2)初始化通訊錄
void InitContact(Contact* pc)
{
?? ?assert(pc);
?? ?pc->sz = 0;
?? ?PeoInfo* tmp = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
?? ?if (tmp != NULL)
?? ?{
?? ??? ?pc->data = tmp;
?? ?}
?? ?else
?? ?{
?? ??? ?printf("InitContact()::%s\n", strerror(errno));
?? ?}
?? ?pc->capacity = DEFAULT_SZ;
}這里設定了通訊錄的起始大小,后面可以通過動態(tài)增容來擴大(而數組版本的話就沒有這么靈活了)
(3)添加聯系人信息
void check_capacity(Contact* pc)
{
?? ?assert(pc);
?? ?if (pc->sz == pc->capacity)
?? ?{
?? ??? ?// 增容
?? ??? ?PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2)*sizeof(PeoInfo));
?? ??? ?if (tmp != NULL)
?? ??? ?{
?? ??? ??? ?pc->data = tmp;
?? ??? ??? ?pc->capacity += 2;
?? ??? ??? ?printf("增容成功\n");
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("InitContact()::%s\n", strerror(errno));
?? ??? ?}
?? ?}
}
void AddContact(Contact* pc)
{
?? ?assert(pc);
?? ?check_capacity(pc);
?? ?// 添加內容
?? ?printf("名字:");
?? ?scanf("%s", pc->data[pc->sz].name);
?? ?printf("年齡:");
?? ?scanf("%d", &(pc->data[pc->sz].age));
?? ?printf("性別:");
?? ?scanf("%s", pc->data[pc->sz].sex);
?? ?printf("地址:");
?? ?scanf("%s", pc->data[pc->sz].addr);
?? ?printf("電話:");
?? ?scanf("%s", pc->data[pc->sz].tele);
?? ?
?? ?pc->sz++;
?? ?printf("添加成功\n");
}這里實現了一個check_capacity 的接口,用來判斷當前通訊錄是否存滿了;若滿了則進行擴容(一般按2倍進行擴容),注意:添加成功后需要對 sz++
(4)刪除聯系人信息
int FindByName(const Contact* pc, char* name)
{
?? ?int i = 0;
?? ?for (i = 0; i < pc->sz; i++)
?? ?{
?? ??? ?if (strcmp(pc->data[i].name, name) == 0)
?? ??? ?{
?? ??? ??? ?return i;
?? ??? ?}
?? ?}
?? ?return -1;
}
void DeleteContact(Contact* pc)
{
?? ?char name[NAME_MAX] = { 0 };
?? ?assert(pc);
?? ?if (pc->sz == 0)
?? ?{
?? ??? ?printf("通訊錄為空\n");
?? ??? ?return;
?? ?}
?? ?// 根據輸入的人名進行刪除
?? ?printf("請輸入要刪除的人名:");
?? ?scanf("%s", name);
?? ?int pos = FindByName(pc, name);
?? ?if (pos == -1)
?? ?{
?? ??? ?printf("要刪除的人不存在\n");
?? ?}
?? ?else
?? ?{
?? ??? ?// 刪除
?? ??? ?//int j = 0;
?? ??? ?//for (j = pos; j < pc->sz-1; j++) ?// sz-1為了防止j+1非法訪問
?? ??? ?//{
?? ??? ?//?? ?pc->data[j] = pc->data[j + 1];
?? ??? ?//}
?? ??? ?//pc->sz--;
?? ??? ?//printf("刪除成功\n");
?? ??? ?//if (pc->sz>1)
?? ??? ?memmove((pc->data) + pos, (pc->data) + pos + 1, (pc->sz - pos)*sizeof(PeoInfo));
?? ??? ?pc->sz--;
?? ?}
}這里我就只做了按照名字進行刪除,你們也可以都嘗試一下喲。下面寫了兩種刪除方法(這里的按名字刪除前需要進行查找,因此我們也可以直接使用我們下面要實現的查找函數,但如果查找里面進行了其他功能,那時不能直接使用的喲)
(5)查找聯系人信息
void SearchContact(const Contact* pc)
{
?? ?char name[NAME_MAX] = { 0 };
?? ?assert(pc);
?? ?if (pc->sz == 0)
?? ?{
?? ??? ?printf("通訊錄為空\n");
?? ??? ?return;
?? ?}
?? ?printf("請輸入要查找的姓名:");
?? ?scanf("%s", name);
?? ?int i = FindByName(pc, name);
?? ?if(-1 == i)
?? ?{
?? ??? ?// 沒有找到
?? ??? ?printf("你要查找的人不存在\n");
?? ?}
?? ?else
?? ?{
?? ??? ?// 找到了
?? ??? ?printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n",?
?? ??? ??? ??? ?"姓名", "年齡", "性別", "地址", "電話");
?? ??? ?printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
?? ??? ??? ?pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
?? ?}
}這里如果查找到了后,我打印顯示了一下
(6)更改聯系人信息
void ModifyContact(Contact* pc)
{
?? ?char name[NAME_MAX] = { 0 };
?? ?assert(pc);
?? ?if (pc->sz == 0)
?? ?{
?? ??? ?printf("通訊錄為空\n");
?? ??? ?return;
?? ?}
?? ?printf("請輸入要修改信息的姓名:");
?? ?scanf("%s", name);
?? ?int i = FindByName(pc, name);
?? ?// 修改內容
?? ?printf("新的名字:");
?? ?scanf("%s", pc->data[i].name);
?? ?printf("新的年齡:");
?? ?scanf("%d", &(pc->data[i].age));
?? ?printf("新的性別:");
?? ?scanf("%s", pc->data[i].sex);
?? ?printf("新的地址:");
?? ?scanf("%s", pc->data[i].addr);
?? ?printf("新的電話:");
?? ?scanf("%s", pc->data[i].tele);
?? ?printf("修改后的信息為:\n");
?? ?printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n", "姓名", "年齡", "性別", "地址", "電話");
?? ?printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
?? ??? ?pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
}(7)顯示所有聯系人信息
void ShowContact(const Contact* pc)
{
?? ?assert(pc);
?? ?// 打印標題
?? ?printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n", "姓名", "年齡", "性別", "地址", "電話");
?? ?int i = 0;
?? ?for (i = 0; i < pc->sz; i++)
?? ?{
?? ??? ?printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
?? ??? ??? ?pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
?? ?}
}直接遍歷打印即可
(8)對聯系人信息進行排序
int cmp_by_name(const void* e1, const void* e2)
{
?? ?return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
int cmp_by_age(const void* e1, const void* e2)
{
?? ?return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
?? ?// return strcmp(, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
?? ?int choice = 0;
?? ?printf("請選擇:(1、按姓名;2、按年齡)");
?? ?scanf("%d", &choice);
?? ?if (1 == choice)
?? ?{
?? ??? ?qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
?? ??? ?printf("排序后的數據:\n");
?? ??? ?ShowContact(pc);
?? ?}
?? ?else if (2 == choice)
?? ?{
?? ??? ?qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age);
?? ??? ?printf("排序后的數據:\n");
?? ??? ?ShowContact(pc);
?? ?}
?? ?else
?? ?{
?? ??? ?printf("輸入有誤\n");
?? ?}
}這里使用qsort實現的排序,可以對 姓名 或 年齡進行排序的
(9)退出時銷毀通訊錄
void DestoryContact(Contact* pc)
{
?? ?assert(pc);
?? ?free(pc->data);
?? ?pc->data = NULL;
}直接將里面指向有效內容的 pc->data 進行free釋放就行,因為它本來就是動態(tài)開辟的,后面要有個好習慣,free之后將其置為NULL,不然就為野指針了。
總結:
以上就是動態(tài)增容版本通訊錄的全部代碼,盡管用了動態(tài)增容,里面仍然會存在很多的空間浪費,后面等博主學了鏈表后,在進行改進。
希望這篇文章對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
利用C語言模擬實現qsort,strcpy,strcat,strcmp函數
這篇文章主要為大家詳細介紹了如何通過C語言模擬實現qsort(采用冒泡的方式),strcpy,strcat,strcmp等函數,文中的示例代碼講解詳細,感興趣的可以了解一下2022-11-11
C++靜態(tài)庫與動態(tài)庫文件的生成和使用教程
庫文件是計算機上的一類文件,可以簡單的把庫文件看成一種代碼倉庫,它提供給使用者一些可以直接拿來用的變量、函數和類,下面這篇文章主要給大家介紹了關于C++靜態(tài)庫與動態(tài)庫文件的生成和使用的相關資料,需要的朋友可以參考下2023-03-03

