C語(yǔ)言實(shí)現(xiàn)一個(gè)文件版動(dòng)態(tài)通訊錄流程詳解
通訊錄思維導(dǎo)圖
?
一、Contact.h
#include<stdio.h> #include<assert.h> #include<string.h> #include<stdlib.h> #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 11 #define ADDR_MAX 30 #define INIT_CAPA 3 #define INC_CAPA 2 typedef struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char addr[ADDR_MAX]; }PeoInfo; //動(dòng)態(tài)版本 typedef struct Contact { PeoInfo* data; int sz;//表示通訊錄有多少個(gè)聯(lián)系人 int capacity;//表示通訊錄的最大容量 }Contact; //初始化通訊錄 void InitContact(Contact* pc); //添加聯(lián)系人 void AddContact(Contact* pc); //刪除聯(lián)系人 void DelContact(Contact* pc); //顯示通訊錄 void ShowContact(const Contact* pc); //查找聯(lián)系人 void SearchContact(Contact*pc); //修改聯(lián)系人' void ModifyContact(Contact*pc); //通過(guò)名字排序聯(lián)系人 void ByNameSortContact(Contact* pc); //銷(xiāo)毀聯(lián)系人 void DestroyContact(Contact* pc); //保存聯(lián)系人到文本文件中 void SaveContact(Contact* pc); //從文件中讀取聯(lián)系人的信息 void GetContact(Contact* pc);
這些是頭文件的包含,函數(shù)的聲明,以及#define定義的常量,為了以后修改方便
二、Contact.c
1.初始化通訊錄
void InitContact(Contact* pc)//初始化通訊錄 { assert(pc!=NULL); pc-> sz = 0; pc->capacity = INIT_CAPA; PeoInfo * ptr = (PeoInfo*)calloc(INIT_CAPA, sizeof(PeoInfo)); if (ptr == NULL) { perror("InitContact"); return; } pc->data = ptr; GetContact(pc); }
初始化通訊錄的容量開(kāi)始為3,sz初始時(shí)為0,動(dòng)態(tài)開(kāi)辟的ptr開(kāi)辟成功在賦給data。
2.檢查容量是否滿
void check_capacity(Contact* pc)//檢查容量是否滿 { assert(pc); if (pc->capacity == pc->sz) { PeoInfo*ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo)); if (ptr == NULL) { perror("check_capacity"); return; } pc->data = ptr; pc->capacity += INC_CAPA; printf("增容成功\n"); } }
如果容量滿,則每次增容兩個(gè),如果想要增容更多,則修改define定義的常量就可以修改了。
realloc開(kāi)辟的時(shí)候有可能是用pc->data來(lái)往后擴(kuò)大增容,也有可能是用新的空間來(lái)開(kāi)辟,為了防止開(kāi)辟失敗,使原有的數(shù)據(jù)丟失,則先使用新的指針變量來(lái)接收動(dòng)態(tài)開(kāi)辟的空間,如果開(kāi)辟成功,再將它賦給data。
3.添加聯(lián)系人
void AddContact(Contact* pc)//添加聯(lián)系人 { assert(pc != NULL); check_capacity(pc); printf("請(qǐng)輸入姓名:\n"); scanf("%s", pc->data[pc->sz].name); printf("請(qǐng)輸入年齡:\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("請(qǐng)輸入性別:\n"); scanf("%s", pc->data[pc->sz].sex); printf("請(qǐng)輸入號(hào)碼:\n"); scanf("%s", pc->data[pc->sz].tele); printf("請(qǐng)輸入地址:\n"); scanf("%s", pc->data[pc->sz].addr); printf("添加聯(lián)系人成功\n"); pc->sz++; }
添加聯(lián)系人前,需要先判斷是否需要增容
4.顯示聯(lián)系人
void ShowContact(const Contact* pc)//顯示聯(lián)系人 { assert(pc != NULL); printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n","姓名","年齡","性別","電話號(hào)碼","地址"); for (int i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-4s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } }
5.查找聯(lián)系人
int ByNameFind(Contact* pc, char name[])//通過(guò)名字查找聯(lián)系人 { for (int i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } void SearchContact(Contact* pc)//查找聯(lián)系人 { assert(pc); char name[NAME_MAX]; printf("請(qǐng)輸入要查找的聯(lián)系人\n"); scanf("%s", name); int ret = ByNameFind(pc, name); if (ret == -1) { printf("查無(wú)此人\n"); return; } printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話號(hào)碼", "地址"); printf("%-20s\t%-4d\t%-4s\t%-12s\t%-30s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr); }
注意:名字屬于字符串,名字的比較需要用strcmp來(lái)比較,如果返回-1,則是沒(méi)有找到聯(lián)系人,如果找到了,則就打印這個(gè)聯(lián)系人的信息出來(lái)
6.修改聯(lián)系人
void ModifyContact(Contact* pc)//修改聯(lián)系人 { assert(pc); char name[NAME_MAX]; printf("請(qǐng)輸入要修改的聯(lián)系人姓名\n"); scanf("%s", name); int pos = ByNameFind(pc, name); if (pos == -1) { printf("找不到該聯(lián)系人\n"); return; } printf("請(qǐng)輸入姓名:\n"); scanf("%s", pc->data[pos].name); printf("請(qǐng)輸入年齡:\n"); scanf("%d", &(pc->data[pos].age)); printf("請(qǐng)輸入性別:\n"); scanf("%s", pc->data[pos].sex); printf("請(qǐng)輸入號(hào)碼:\n"); scanf("%s", pc->data[pos].tele); printf("請(qǐng)輸入地址:\n"); scanf("%s", pc->data[pos].addr); printf("修改聯(lián)系人成功\n"); }
注意:想要修改這個(gè)聯(lián)系人,也需要通訊錄中有這個(gè)聯(lián)系人,所以要先查找到這個(gè)聯(lián)系人,所以調(diào)用封裝好的通過(guò)名字查找聯(lián)系人這個(gè)函數(shù)就可以了,如果返回-1,則就是沒(méi)有該聯(lián)系人,無(wú)法修改,如果找到了,則才能夠修改此聯(lián)系人的信息。
7.通過(guò)名字來(lái)排序聯(lián)系人
void ByNameSortContact(Contact* pc)//通過(guò)名字來(lái)排序 { assert(pc); if (pc->sz == 0) { printf("無(wú)聯(lián)系人,無(wú)法排序\n"); return; } PeoInfo temp; for (int i = 0; i < pc->sz - 1; i++) { for(int j = 0 ;j<pc->sz-1-i;j++) { if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0) { temp = pc->data[j]; pc->data[j] = pc->data[j + 1]; pc->data[j + 1] = temp; } } } printf("排序成功\n"); }
注意:這里通過(guò)名字來(lái)排序聯(lián)系人,也是需要用到strcmp這個(gè)庫(kù)函數(shù)的,strcmp是一個(gè)字符來(lái)比較的,如果有一個(gè)字符大的話就要進(jìn)行交換,利用的是冒泡排序思想來(lái)排序聯(lián)系人的
8.保存聯(lián)系人到文本文件中
void SaveContact(Contact* pc) { assert(pc); FILE* pf = fopen("Contact.txt", "wb"); if (pf == NULL) { perror("fopen"); } else { for (int i = 0; i < pc->sz; i++) { fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); } fclose(pf); pf = NULL; printf("保存數(shù)據(jù)成功\n"); } }
?
注意:FILE是C語(yǔ)言標(biāo)準(zhǔn)的指針,wb是用二進(jìn)制的方式寫(xiě)入文本文件中,而fwrite的用法我們可以利用cplusplus來(lái)查找它的用法,里面介紹了它的每個(gè)參數(shù)的用法,第一個(gè)參數(shù)ptr其實(shí)就是傳我們的data的指針進(jìn)去,第二個(gè)參數(shù)本質(zhì)就是求大小的,求得是PeoInfo得大小,第三個(gè)參數(shù)就是每次添加幾個(gè)聯(lián)系人,每次添加1個(gè)。第四個(gè)參數(shù)是把文件流放入
9.從文件中讀取聯(lián)系人的信息
//從文件中初始化聯(lián)系人 void GetContact(Contact* pc) { assert(pc); FILE* pf = fopen("Contact.txt", "rb"); if (pf == NULL) { perror("GetContact::fopen"); } else { PeoInfo ptr = { 0 }; int i = 0; while (fread(&ptr, sizeof(PeoInfo), 1, pf)) { check_capacity(pc); pc->data[i] = ptr; i++; pc->sz++; } fclose(pf); pf = NULL; } }
?
注意:rb是利用二進(jìn)制來(lái)讀取聯(lián)系人的,fread的用法如上圖所示。
10.銷(xiāo)毀聯(lián)系人
//銷(xiāo)毀聯(lián)系人 void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; }
注意:在我們退出通訊錄時(shí),要將它進(jìn)行銷(xiāo)毀
三、text.c
#include"Contact.h" void menu() { printf("**********************************\n"); printf("*******1.Add 2.Del ********\n"); printf("*******3.Search 4.Modify********\n"); printf("*******5.Show 6.Sort ********\n"); printf("*******0.exit ********\n"); printf("**********************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { Contact con; InitContact(&con); int input = 0; do { menu(); printf("請(qǐng)輸入數(shù)字:\n"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL : DelContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: ModifyContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: ByNameSortContact(&con); break; case EXIT: SaveContact(&con); DestroyContact(&con); printf("退出程序\n"); break; default: printf("輸入錯(cuò)誤,請(qǐng)重新輸入\n"); break; } } while (input); return 0;
注意:首先要建立菜單,然后用枚舉來(lái)定義case后面,這樣為了可以讓我們看代碼更清晰,在運(yùn)行程序時(shí)要將聯(lián)系人從文件中讀取出來(lái),在退出文件時(shí),要把聯(lián)系人保存到文本文件中去,在進(jìn)行銷(xiāo)毀。
好了,小編的分享到這里就結(jié)束了,如果有什么不足的地方請(qǐng)大佬多多指教?。。?/p>
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)一個(gè)文件版動(dòng)態(tài)通訊錄流程詳解的文章就介紹到這了,更多相關(guān)C語(yǔ)言動(dòng)態(tài)通訊錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單三子棋游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09關(guān)于C語(yǔ)言中弱符號(hào)與弱引用的實(shí)際應(yīng)用問(wèn)題
在編碼過(guò)程中,我們經(jīng)常遇到符號(hào)重定義的錯(cuò)誤問(wèn)題,本文通過(guò)實(shí)例代碼展示給大家介紹了C語(yǔ)言弱符號(hào)與弱引用的實(shí)際應(yīng)用問(wèn)題,一起看看吧2021-09-09C語(yǔ)言順序表實(shí)現(xiàn)代碼排錯(cuò)
這篇文章主要介紹了C語(yǔ)言順序表實(shí)現(xiàn)方法,大家參考使用吧2013-12-12用32位int型變量表示單引號(hào)括起來(lái)的四個(gè)字符的深入探討
本篇文章是對(duì)用32位int型變量表示單引號(hào)括起來(lái)的四個(gè)字符進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++基于boost asio實(shí)現(xiàn)sync tcp server通信流程詳解
這篇文章主要介紹了C++基于boost asio實(shí)現(xiàn)sync tcp server通信的流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量
這篇文章主要為大家詳細(xì)介紹了C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06