摘要:之前的通訊錄在程序退出后內(nèi)部的數(shù)據(jù)就會(huì)消失,再次打開(kāi)程序后只能重新輸入數(shù)據(jù),為此我們?cè)黾恿艘粋€(gè)保存功能來(lái)保存信息。
前言:
- 由于之前實(shí)現(xiàn)的通訊錄在存儲(chǔ)方面只能支持靜態(tài)的1000人的存儲(chǔ)量,但是如果聯(lián)系人較少,則會(huì)造成較大的內(nèi)存浪費(fèi)。
- 而當(dāng)聯(lián)系人一旦超過(guò)1000時(shí),就不能再繼續(xù)存儲(chǔ)信息了。因此我將通訊錄改成動(dòng)態(tài)擴(kuò)容版本,就不會(huì)減少內(nèi)存的浪費(fèi),同時(shí)也可以無(wú)限增加通訊錄的內(nèi)部信息。
- 之前的通訊錄在程序退出后內(nèi)部的數(shù)據(jù)就會(huì)消失,再次打開(kāi)程序后只能重新輸入數(shù)據(jù),為此我們?cè)黾恿艘粋€(gè)保存功能來(lái)保存信息。
此版本將實(shí)現(xiàn)的功能:
- 新增聯(lián)系人
- 查找聯(lián)系人
- 刪除聯(lián)系人
- 修改聯(lián)系人
- 查看所有聯(lián)系人
清空所有聯(lián)系人(新增)
- 按姓名排序聯(lián)系人
- 保存聯(lián)系人信息(新增)
注:之前版本寫(xiě)過(guò)的代碼就不多做贅述了
如果有代碼上的疑惑可以移步去?手把手教你用C語(yǔ)言實(shí)現(xiàn)通訊錄(簡(jiǎn)易版? 查看
本次僅對(duì)新增的內(nèi)容進(jìn)行解釋和說(shuō)明
目錄
新增:
清空所有聯(lián)系人選項(xiàng)(7)
保存聯(lián)系人信息選項(xiàng)(8)
?代碼如下:?
void menu(){ printf("*********************************/n"); printf("** 1. 添加聯(lián)系人 **/n"); printf("** 2. 刪除聯(lián)系人 **/n"); printf("** 3. 查找聯(lián)系人 **/n"); printf("** 4. 修改聯(lián)系人 **/n"); printf("** 5. 顯示所有聯(lián)系人 **/n"); printf("** 6. 按姓名排序聯(lián)系人 **/n"); printf("** 7. 清空所有聯(lián)系人 **/n"); printf("** 8. 保存聯(lián)系人信息 **/n"); printf("** 0. exit **/n"); printf("*********************************/n");}
?執(zhí)行結(jié)果:
?新增:
case 分支中 清空通訊錄選項(xiàng) & 清空實(shí)現(xiàn)函數(shù)
case 分支中 保存通訊錄選項(xiàng) & 保存實(shí)現(xiàn)函數(shù)
case 分支中 退出時(shí)自動(dòng)保存實(shí)現(xiàn)函數(shù)
?代碼如下:?
int main(){ int input = 0; //創(chuàng)建通訊錄 struct Contact con;//通訊錄 //初始化通訊錄 InitContact(&con); do { menu(); printf("請(qǐng)選擇:>"); scanf("%d", &input); switch(input) { case ADD: AddContact(&con); break; case DEL: DelContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: MoidfyContact(&con); break; case SHOW: ShowContact(&con); break; case DESTROY: DestroyContact(&con); break; case SORT: SortContact(&con); break; case SAVE: SaveContact(&con); break; case EXIT: SaveContact(&con); printf("退出通訊錄/n"); break; default: printf("選擇錯(cuò)誤/n"); break; } } while (input); return 0;}
新增:
enum枚舉?選擇中新增 DESTROY? &??SAVE? ?的選項(xiàng),通過(guò)枚舉的方法對(duì)應(yīng) main 函數(shù)中的 case 分支。
?代碼如下:?
//枚舉:選擇功能enum Choose{ EXIT, //0 ADD, //1 DEL, //2 SEARCH, //3 MODIFY, //4 SHOW, //5 SORT, //6 DESTROY, //7 SAVE //8};
新增:
typedef 定義 Contact 函數(shù),使其能直接使用不需要 struct 修飾
整型 capacity 變量來(lái)表示當(dāng)前通訊錄的最大容量
?代碼如下:
//結(jié)構(gòu)體:通訊錄類(lèi)型typedef struct Contact{ struct PeoInform *data;//存放信息 int size;//記錄當(dāng)前結(jié)構(gòu)體內(nèi)已經(jīng)有的元素個(gè)數(shù) int capacity;//當(dāng)前通訊錄的最大容量}Contact;
新增:
為了實(shí)現(xiàn)動(dòng)態(tài),我們將初始空間 Org_SPACE?(orignial space 初始空間)?設(shè)置為5個(gè)
修改:
刪去了最大空間為1000個(gè)的靜態(tài)內(nèi)存空間
?代碼如下:?
//初始空間為5個(gè)#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30
新增:
通過(guò) malloc 函數(shù)動(dòng)態(tài)開(kāi)辟一塊地址,初始容量 ORG_SPACE 可以存放 5 個(gè)聯(lián)系人信息,同時(shí)初始化最大容量 ORG_SPACE??
下方的 LoadContact 函數(shù)是為了讀取信息來(lái)存放到通訊錄中,來(lái)實(shí)現(xiàn)文件保存功能
?代碼如下:?
//初始化通訊錄的函數(shù)void InitContact(struct Contact *ps){ ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform)); if(ps->data == NULL) { return; } ps->size = 0; ps->capacity = ORG_SPACE; //把文件中已經(jīng)存放的通訊錄中的信息加載到通訊錄中 LoadContact(ps);}
那么既然上方的初始化通訊錄中已經(jīng)出現(xiàn)了這個(gè)讀取函數(shù),那么我們就來(lái)設(shè)計(jì)一下:
這里的 FR 來(lái)臨時(shí)讀取 contact.txt 保存文件中的信息,一旦FR內(nèi)部為空,就代表文件內(nèi)沒(méi)有保存任何信息。
而后面是讀取文件中的信息,存放到通訊錄中的臨時(shí)變量 tmp 中去,此時(shí)我們要考慮讀取到通訊錄的數(shù)據(jù)是否會(huì)溢出,所以我們要進(jìn)行判斷,一旦超過(guò)了5個(gè)的初始空間,就進(jìn)行擴(kuò)充。
最后關(guān)閉文件時(shí),將 FR 內(nèi)部的數(shù)據(jù)清空
//讀取通訊錄信息void LoadContact(Contact *ps){ PeoInform tmp = {0};//臨時(shí)變量tmp FILE *FR = fopen("contact.txt", "rb"); if(FR == NULL) { printf("LoadContact::%s/n", strerror(errno)); return; } //讀取文件,存放到通訊錄中 while(fread(&tmp, sizeof(PeoInform), 1, FR)) { ExpandCapacity(ps); ps->data[ps->size] = tmp; ps->size++; } fclose(FR); FR = NULL;}
我們此時(shí)來(lái)設(shè)計(jì)一下通訊錄擴(kuò)充函數(shù),同時(shí)使其能夠?qū)崿F(xiàn)檢測(cè)當(dāng)前通訊錄的容量:
1. 如果滿(mǎn)了,就增加空間
2. 如果不滿(mǎn),啥事都不干
3. 一旦存儲(chǔ)達(dá)到5個(gè)以后就再使用realloc函數(shù)擴(kuò)充5個(gè)動(dòng)態(tài)空間
代碼如下:
void ExpandCapacity(struct Contact *ps){ if(ps->size == ps->capacity) { struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform)); if(ptr != NULL) { ps->data = ptr; ps->capacity += 5; //自動(dòng)開(kāi)辟五個(gè)動(dòng)態(tài)空間 printf("擴(kuò)充成功/n"); } else { printf("擴(kuò)充失敗/n"); } }}
新增:
errno 函數(shù) 需要引用的
頭文件 malloc 函數(shù) 需要引用的
頭文件
???代碼如下:
#include #include #include #include #include
? ?代碼如下:
//銷(xiāo)毀通訊錄中的所有信息void DestroyContact(Contact* ps){ printf("您確定要清空所有聯(lián)系人嗎? y/n/n"); char choice[2]; scanf("%s", &choice); if (strcmp(choice, "y") == 0) { ps->size = 0; printf("已清空所有聯(lián)系人!/n"); } if (strcmp(choice, "n") == 0) { printf("指令已取消/n"); } //同時(shí)釋放之前所開(kāi)辟的動(dòng)態(tài)空間 free(ps->data); ps->data = NULL;}
???執(zhí)行效果:
? ?代碼如下:
//保存聯(lián)系人到文件void SaveContact(Contact* ps){ FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { printf("SaveContact::%s/n", strerror(errno)); return; } //寫(xiě)通訊錄中數(shù)據(jù)到為文件中 int i = 0; for (i = 0; i < ps->size; i++) { fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp); printf("已保存聯(lián)系人!/n"); }}
?執(zhí)行效果:
?
?關(guān)閉程序后再次打開(kāi):
#include #include #include #include #include //初始空間為5個(gè)#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30//枚舉:選擇功能enum Choose{ EXIT, //0 ADD, //1 DEL, //2 SEARCH, //3 MODIFY, //4 SHOW, //5 SORT, //6 DESTROY, //7 SAVE //8}; //結(jié)構(gòu)體:通訊錄中每個(gè)成員的信息typedef struct PeoInform//將結(jié)構(gòu)體指針類(lèi)型命名為PeoInform{ char name[MAX_NAME]; int age; char sex[MAX_SEX]; char phone[MAX_PHONE]; char address[MAX_ADDRESS];}PeoInform; //結(jié)構(gòu)體:通訊錄類(lèi)型typedef struct Contact{ struct PeoInform *data;//存放信息 int size;//記錄當(dāng)前結(jié)構(gòu)體內(nèi)已經(jīng)有的元素個(gè)數(shù) int capacity;//當(dāng)前通訊錄的最大容量}Contact;//通訊錄擴(kuò)充void ExpandCapacity(struct Contact *ps){ if(ps->size == ps->capacity) { struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform)); if(ptr != NULL) { ps->data = ptr; ps->capacity += 5; //自動(dòng)開(kāi)辟五個(gè)動(dòng)態(tài)空間 printf("擴(kuò)充成功/n"); } else { printf("擴(kuò)充失敗/n"); } }}//讀取通訊錄信息void LoadContact(Contact *ps){ PeoInform tmp = {0};//臨時(shí)變量tmp FILE *FR = fopen("contact.txt", "rb"); if(FR == NULL) { printf("LoadContact::%s/n", strerror(errno)); return; } //讀取文件,存放到通訊錄中 while(fread(&tmp, sizeof(PeoInform), 1, FR)) { ExpandCapacity(ps); ps->data[ps->size] = tmp; ps->size++; } fclose(FR); FR = NULL;}//初始化通訊錄的函數(shù)void InitContact(struct Contact *ps){ ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform)); if(ps->data == NULL) { return; } ps->size = 0; ps->capacity = ORG_SPACE; //把文件中已經(jīng)存放的通訊錄中的信息加載到通訊錄中 LoadContact(ps);}//按姓名查找聯(lián)系人是否存在static int FindByName(const struct Contact *ps, char name[MAX_NAME]){ int i = 0; for(i = 0; i < ps->size; i++) { if(0 == strcmp(ps->data[i].name, name)) { return i; } } return -1;//找不到的情況}//增加一個(gè)信息到通訊錄void AddContact(struct Contact *ps){ ExpandCapacity(ps); //增加數(shù)據(jù) printf("請(qǐng)輸入名字:>"); scanf("%s", ps->data[ps->size].name); printf("請(qǐng)輸入年齡:>"); scanf("%d", &(ps->data[ps->size].age)); printf("請(qǐng)輸入性別:>"); scanf("%s", ps->data[ps->size].sex); printf("請(qǐng)輸入電話(huà):>"); scanf("%s", ps->data[ps->size].phone); printf("請(qǐng)輸入家庭地址:>"); scanf("%s", ps->data[ps->size].address); ps->size++; printf("添加成功/n");} //刪除指定的聯(lián)系人void DelContact(struct Contact *ps){ int pos = 0; char name[MAX_NAME]; printf("請(qǐng)輸入要?jiǎng)h除人的名字:>"); scanf("%s", name); //1.查找要?jiǎng)h除的人在什么位置 //找到了返回名字所在元素的下標(biāo) //找不到返回 -1 pos = FindByName(ps, name); //2.刪除 //查詢(xún)不到聯(lián)系人 if (pos == -1) { printf("查詢(xún)不到要?jiǎng)h除的聯(lián)系人,請(qǐng)重試/n"); } else { //刪除數(shù)據(jù) int j = 0; for(j = pos; j < ps->size-1; j++) { ps->data[j] = ps->data[j + 1]; //由于刪除了這個(gè)數(shù)據(jù),所以后面的數(shù)據(jù)會(huì)頂替上來(lái) } ps->size--; printf("刪除成功/n"); }} //查找指定的人的信息void SearchContact(const struct Contact *ps){ char name[MAX_NAME]; printf("請(qǐng)輸入要查找人的名字:>"); scanf("%s", name); int pos = 0; //查找聯(lián)系人的位置 pos = FindByName(ps, name); //2.刪除 if (pos == -1) { printf("要查找的人不存在,請(qǐng)重試/n"); } else { printf("%-20s/t%-4s/t%-5s/t%-12s/t%-20s/n", "名字", "年齡", "性別", "電話(huà)", "地址"); printf("%-20s/t%-4d/t%-5s/t%-12s/t%-20s/n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex, ps->data[pos].phone, ps->data[pos].address); }} //修改指定聯(lián)系人的信息void MoidfyContact(struct Contact *ps){ char name[MAX_NAME]; printf("請(qǐng)輸入要修改聯(lián)系人的名字:>"); scanf("%s", name); int pos = 0; pos = FindByName(ps, name); if (pos == -1) { printf("要修改聯(lián)系人的信息不存在,請(qǐng)重試/n"); } else { printf("請(qǐng)輸入名字:>"); scanf("%s", ps->data[pos].name); printf("請(qǐng)輸入年齡:>"); scanf("%d", &(ps->data[pos].age)); printf("請(qǐng)輸入性別:>"); scanf("%s", ps->data[pos].sex); printf("請(qǐng)輸入電話(huà):>"); scanf("%s", ps->data[pos].phone); printf("請(qǐng)輸入家庭地址:>"); scanf("%s", ps->data[pos].address); printf("修改完成/n"); }} //展示通訊錄中的信息void ShowContact(const struct Contact *ps){ if(ps->size == 0) { printf("通訊錄為空/n"); } else { int i = 0; //標(biāo)題 printf("%-20s/t%-4s/t%-5s/t%-12s/t%-20s/n", "名字", "年齡", "性別", "電話(huà)", "地址"); //數(shù)據(jù) for(i = 0; i < ps->size; i++) { printf("%-20s/t%-4d/t%-5s/t%-12s/t%-20s/n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].phone, ps->data[i].address); } }}//銷(xiāo)毀通訊錄中的所有信息void DestroyContact(Contact* ps){ printf("您確定要清空所有聯(lián)系人嗎? y/n/n"); char choice[2]; scanf("%s", &choice); if (strcmp(choice, "y") == 0) { ps->size = 0; printf("已清空所有聯(lián)系人!/n"); } if (strcmp(choice, "n") == 0) { printf("指令已取消/n"); } //同時(shí)釋放之前所開(kāi)辟的動(dòng)態(tài)空間 free(ps->data); ps->data = NULL;}//按姓名排序通訊錄內(nèi)容void SortContact(struct Contact *ps){ if (ps->size <= 0){ printf("通訊錄中沒(méi)有聯(lián)系人,請(qǐng)?zhí)砑?/n"); } int i = 0; int j = 0; for (i = 0; i< ps->size - 1; i++) { for (j = 0; j< ps->size - i - 1; j++) { if (strcmp( ps->data[j].name, ( ps->data[j + 1]).name) > 0) { PeoInform tmp; tmp = ps->data[j]; ps->data[j] = ps->data[j + 1]; ps->data[j + 1] = tmp; } } printf("排序成功!/n"); }} //保存聯(lián)系人到文件void SaveContact(Contact* ps){ FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { printf("SaveContact::%s/n", strerror(errno)); return; } //寫(xiě)通訊錄中數(shù)據(jù)到為文件中 int i = 0; for (i = 0; i < ps->size; i++) { fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp); printf("已保存聯(lián)系人!/n"); }} void menu(){ printf("*********************************/n"); printf("** 1. 添加聯(lián)系人 **/n"); printf("** 2. 刪除聯(lián)系人 **/n"); printf("** 3. 查找聯(lián)系人 **/n"); printf("** 4. 修改聯(lián)系人 **/n"); printf("** 5. 顯示所有聯(lián)系人 **/n"); printf("** 6. 按姓名排序聯(lián)系人 **/n"); printf("** 7. 清空所有聯(lián)系人 **/n"); printf("** 8. 保存聯(lián)系人信息 **/n"); printf("** 0. exit **/n"); printf("*********************************/n");} int main(){ int input = 0; //創(chuàng)建通訊錄 struct Contact con;//con就是通訊錄,里面包含:1000個(gè)元素的數(shù)和size //初始化通訊錄 InitContact(&con); do { menu(); printf("請(qǐng)選擇:>"); scanf("%d", &input); switch(input) { case ADD: AddContact(&con); break; case DEL: DelContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: MoidfyContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: SortContact(&con); break; case DESTROY: DestroyContact(&con); break; case SAVE: SaveContact(&con); break; case EXIT: SaveContact(&con); printf("退出通訊錄/n"); break; default: printf("選擇錯(cuò)誤/n"); break; } } while (input); return 0;}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/119672.html
摘要:本篇文章將用語(yǔ)言代碼實(shí)現(xiàn)一個(gè)通訊錄管理系統(tǒng),本片文章博主將會(huì)運(yùn)用到架構(gòu)提,枚舉,動(dòng)態(tài)內(nèi)存開(kāi)辟和文件操作等。這里存放數(shù)據(jù)的結(jié)構(gòu)是線性表。這個(gè)指針就可以通過(guò)動(dòng)態(tài)開(kāi)辟內(nèi)存來(lái)調(diào)整存放信息的大小。擴(kuò)容成功這樣就實(shí)現(xiàn)了檢查通訊錄是否需要擴(kuò)容的函數(shù)。 ...
摘要:導(dǎo)航前言功能函數(shù)結(jié)構(gòu)設(shè)定菜單交互主函數(shù)通訊錄初始化新增聯(lián)系人查找聯(lián)系人刪除聯(lián)系人修改聯(lián)系人查看所有聯(lián)系人清空所有聯(lián)系人以名字排序所有聯(lián)系人結(jié)尾語(yǔ)前言本文將實(shí)現(xiàn)一個(gè)簡(jiǎn)易的電話(huà)簿管理。信息包括名字,性別,電話(huà)號(hào)碼,年齡,住址。 ...
摘要:外部設(shè)備會(huì)自己處理字節(jié)序的問(wèn)題。本地序和網(wǎng)絡(luò)序從前面對(duì)于字節(jié)序的介紹可以知道采用小端序,而等采用大端序。協(xié)議很好的解決了這個(gè)問(wèn)題,協(xié)議規(guī)定使用大端字節(jié)序作為網(wǎng)絡(luò)字節(jié)序。提供了一組接口用于整型數(shù)據(jù)在本地序和網(wǎng)絡(luò)序之間的轉(zhuǎn)換。 ...
摘要:本文收錄于技術(shù)專(zhuān)家修煉文中配套資料合集路線導(dǎo)圖高清源文件點(diǎn)擊跳轉(zhuǎn)到文末點(diǎn)擊底部卡片回復(fù)資料領(lǐng)取哈嘍,大家好,我是一條最近粉絲問(wèn)我有沒(méi)有自學(xué)路線,有了方向才能按圖索驥,事半功倍。 ...
閱讀 1828·2021-10-09 09:44
閱讀 2702·2021-09-22 15:38
閱讀 2499·2021-09-09 09:33
閱讀 702·2021-09-07 09:58
閱讀 1830·2021-09-02 15:41
閱讀 2515·2019-08-30 15:55
閱讀 1803·2019-08-30 15:55
閱讀 548·2019-08-30 15:44