??內(nèi)容專欄:【C語言】進階部分
??本文概括: 結(jié)合自定義類型、動態(tài)內(nèi)存管理知識,對靜態(tài)版本的通訊錄進行優(yōu)化。
??本文作者:花 碟
??發(fā)布時間:2023.4.2
?
目錄
前言:
一、靜態(tài)版本代碼實現(xiàn):
二、動態(tài)通訊錄?
三、代碼整理?
前言:
前面我們學過了結(jié)構(gòu)體、枚舉等自定義類型的學習,寫了一個靜態(tài)版本的通訊錄【傳送門】點擊進入靜態(tài)版通訊錄界面,我們知道,我們寫的通訊錄其實本質(zhì)用的是一個結(jié)構(gòu)體數(shù)組,數(shù)組的大小是固定的,這時我們就可以使用動態(tài)內(nèi)存管理相關知識,對內(nèi)存空間進行一個合理的分配,而不至于一下開辟一個較大的數(shù)組空間,用的時候卻很少,造成了內(nèi)存浪費的問題等。如果在內(nèi)存不夠時,也可以進行申請一定的空間來存儲數(shù)據(jù)。
一、靜態(tài)版本代碼實現(xiàn):
這里我就直接將完整代碼放過來,具體分析,可以點擊傳送門鏈接,看實現(xiàn)思路哦~~
test.c文件代碼(測試通訊錄的相關功能)
#include "contact.h" void Menu() { printf("********************************\n"); printf("****** 0.exit 1.add ******\n"); printf("****** 2.delete 3.modify******\n"); printf("****** 4.search 5.show *****\n"); printf("****** 6.sort *****\n"); printf("********************************\n"); } enum Option { EXIT, ADD, DELETE, MODIFY, SEARCH, SHOW, SORT }; int main() { Contact con;//創(chuàng)建一個名為con的結(jié)構(gòu)體變量 InitContact(&con); int input = 0; do { Menu(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DELETE: DeleteContact(&con); break; case MODIFY: ModifyContact(&con); break; case SEARCH: SearchContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: SortContact(&con); break; case EXIT: printf("退出通訊錄\n"); break; default: printf("輸入有誤,請重新輸入\n"); break; } } while (input); }
contact.h文件(用來聲明函數(shù)、結(jié)構(gòu)體變量)
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<errno.h> #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 15 #define MAX_ADDR 20 #define MAX 20 //創(chuàng)建個人信息 typedef struct PeoInfo { char name[MAX_NAME]; int age; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo; //靜態(tài)版本的通訊錄 //聲明一個通訊錄結(jié)構(gòu)體 typedef struct Contact { PeoInfo data[MAX]; int sz; }Contact; //初始化結(jié)構(gòu)體 void InitContact(Contact* pc); //添加聯(lián)系人 void AddContact(Contact* pc); //顯示通訊錄 void ShowContact(const Contact* pc); //刪除指定聯(lián)系人 void DeleteContact(Contact* pc); //查找指定聯(lián)系人 void SearchContact(const Contact* pc); //修改指定聯(lián)系人 void ModifyContact(Contact* pc); //排序通訊錄 void SortContact(Contact* pc);
contact.c文件(用來具體實現(xiàn)函數(shù)內(nèi)部的功能)
#define _CRT_SECURE_NO_WARNINGS #include"contact.h" //靜態(tài)版本 //初始化通訊錄 void InitContact(Contact* pc) { pc->sz = 0; memset(pc->data, 0, sizeof(pc->data)); } //添加聯(lián)系人 void AddContact(Contact* pc) { //CheckContact(pc); if (pc->data == pc->sz) { printf("通訊錄已滿,無法添加聯(lián)系人\n"); return; } 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].tele); printf("請輸入地址:>"); scanf("%s", pc->data[pc->sz].addr); printf("添加成功\n"); pc->sz++; } //顯示通訊錄 void ShowContact(const Contact* pc) { printf("%-15s %-5s %-5s %-15s %-20s\n","姓名", "年齡", "性別", "電話", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s %-5d %-5s %-15s %-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex,pc->data[i].tele, pc->data[i].addr); } } //查找姓名 static int Findname(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i;//找到返回i } } return -1;//沒找到返回-1 } //刪除指定聯(lián)系人 void DeleteContact(Contact* pc) { if (0 == pc->sz) { printf("通訊錄為空,無法刪除聯(lián)系人\n"); return; } printf("請輸入姓名:>"); char name[MAX_NAME] = { 0 }; scanf("%s",name); //查找姓名 int pos = Findname(pc,name); //刪除 if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } int i = 0; for (i = pos; i < pc->sz; i++) { pc->data[pos] = pc->data[pos + 1]; } printf("刪除成功\n"); pc->sz--; } //查找指定聯(lián)系人 void SearchContact(const Contact* pc) { char name[MAX_NAME] = { 0 }; printf("請輸入姓名:>"); scanf("%s", name); int pos = Findname(pc, name); if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } printf("%-15s %-5s %-5s %-15s %-20s\n", "姓名", "年齡", "性別", "電話", "地址"); printf("%-15s %-5d %-5s %-15s %-20s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } //修改指定聯(lián)系人 void ModifyContact(Contact* pc) { printf("請輸入要修改人的姓名:>"); char name[MAX_NAME] = { 0 }; scanf("%s", name); int pos = Findname(pc, name); if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } printf("請輸入姓名:>"); scanf("%s", pc->data[pos].name); printf("請輸入年齡:>"); scanf("%d", &(pc->data[pos].age)); printf("請輸入性別:>"); scanf("%s", pc->data[pos].sex); printf("請輸入電話:>"); scanf("%s", pc->data[pos].tele); printf("請輸入地址:>"); scanf("%s", pc->data[pos].addr); printf("修改成功\n"); } //通過名字來排序 int cmp_by_name(const void* e1,const void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } //排序通訊錄 void SortContact(Contact* pc) { qsort(pc->data, pc->sz,sizeof(PeoInfo),cmp_by_name); printf("排序成功\n"); }
二、動態(tài)通訊錄?
我們將動態(tài)的版本的通訊錄修改為:默認能夠存放3個人的信息,不夠的話,每次增加2個人的信息。
在contact.h文件中,我們宏定義 DEFAULT_SZ 表示?默認3個人的信息
INC_SZ 表示?容量不夠時,每次增加2個人的信息
#define DEFAULT_SZ 3 #define INC_SZ 2
在contact.h文件中。聲明結(jié)構(gòu)體部分:我們要讓動態(tài)申請的內(nèi)存空間可大可小,一定需要malloc函數(shù)來申請空間,所以我們應該將結(jié)構(gòu)體數(shù)組修改為一個結(jié)構(gòu)體指針data,指針類型是PeoInfo*,data指向了存放數(shù)據(jù)的空間,定義sz變量用來記錄當前通訊錄中的信息個數(shù),capacity變量用來記錄通訊錄的容量。
//動態(tài)版本的通訊錄 typedef struct Contact { PeoInfo* data;//data指向了存放數(shù)據(jù)的空間 int sz;//記錄通訊錄中的有效信息個數(shù) int capacity;//記錄通訊錄的容量 }Contact;
在contact.c文件中,初始化通訊錄函數(shù)里面的部分就需要大改了,我們需要首先開辟默認3個元素大小的空間,元素類型是PeoInfo* ,即malloc的參數(shù)為DEFAULT_SZ*sizeof(PeoInfo),
我們拿一個ptr的結(jié)構(gòu)體指針接收,如果ptr為NULL,就打印報錯的信息(strerror需要引用<string.h>頭文件,errno需要引用<errno.h>),然后返回空,不為NULL的話,就將ptr賦給data,元素的起始地址就為data,sz初始化為0,capacity容量初始化為默認值。
//靜態(tài)版本 初始化通訊錄 //void InitContact(Contact* pc) //{ // pc->sz = 0; // memset(pc->data, 0, sizeof(pc->data)); // //} //動態(tài)版本 //初始化通訊錄 void InitContact(Contact* pc) { PeoInfo* ptr= (PeoInfo* )malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (ptr == NULL) { printf("通訊錄初始化失敗::%s", strerror(errno)); return; } else { pc->data = ptr; pc->sz = 0; pc->capacity = DEFAULT_SZ; } }
在contact.c文件中,添加聯(lián)系人函數(shù)里面我們也需要進行大幅度改動。pc->data這里就不是靜態(tài)版本的數(shù)組了,我們直接將這個if語句給屏蔽掉,直接寫一個CheckContact函數(shù)用來判斷通訊錄是否滿了?是否需要擴容?//添加聯(lián)系人 void AddContact(Contact* pc) { CheckContact(pc); /*if (pc->data == pc->sz) { printf("通訊錄已滿,無法添加聯(lián)系人\n"); return; }*/ 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].tele); printf("請輸入地址:>"); scanf("%s", pc->data[pc->sz].addr); printf("添加成功\n"); pc->sz++; }
CheckContact函數(shù)
如果pc->sz 等于 pc->capacity ,即通訊錄當前有效個人信息等于目前的容量時,說明通訊錄已經(jīng)滿了,就需要擴容,此時就可以用realloc函數(shù)來擴容,pc->data表示通訊錄的起始地址,新的大小為新的元素個數(shù)*每個元素的大小。返回值暫存在ptr指針之中,如果ptr為NULL,則打印報錯的信息,不為NULL,則將ptr賦值給pc->data,容量+2,為了顯示擴容效果,我們順便打印當前容量值。
//檢測通訊錄是否滿了 void CheckContact(Contact* pc) { //如果通訊錄滿了 就增容 if (pc->sz == pc->capacity) { PeoInfo* ptr= (PeoInfo*)realloc(pc->data,(pc->capacity+ INC_SZ)*sizeof(PeoInfo)); if (ptr == NULL) { printf("CheckContact::%s", strerror(errno)); return; } else { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功,當前容量為:%d\n", pc->capacity); } } //沒滿直接跳過以上語句 }
最后,我們退出通訊錄的時候,也可以將自己申請的內(nèi)存空間給釋放掉。我們在contact.h文件中聲明一個DestroyContact函數(shù)表示銷毀通訊錄。
在contact.c文件下面接著編寫代碼:
//銷毀通訊錄 void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; printf("釋放成功...\n"); }
?代碼測試:
為了測試方便,作者直接將信息用數(shù)字測試,當我們輸入三個有效信息之后,此時有效空間等于當前的通訊錄容量了,當我們再次選擇1,繼續(xù)添加聯(lián)系人,就“顯示增容成功,當前容量為5”。
三、代碼整理?
將代碼整理在下面,需要的自取吶~
test.c文件
#include "contact.h" void Menu() { printf("********************************\n"); printf("****** 0.exit 1.add ******\n"); printf("****** 2.delete 3.modify******\n"); printf("****** 4.search 5.show *****\n"); printf("****** 6.sort *****\n"); printf("********************************\n"); } enum Option { EXIT, ADD, DELETE, MODIFY, SEARCH, SHOW, SORT }; int main() { Contact con;//創(chuàng)建一個名為con的結(jié)構(gòu)體變量 InitContact(&con); int input = 0; do { Menu(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DELETE: DeleteContact(&con); break; case MODIFY: ModifyContact(&con); break; case SEARCH: SearchContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: SortContact(&con); break; case EXIT: DestroyContact(&con); printf("退出通訊錄\n"); break; default: printf("輸入有誤,請重新輸入\n"); break; } } while (input); }
contact.h文件
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<errno.h> #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 15 #define MAX_ADDR 20 //#define MAX 20 #define DEFAULT_SZ 3 #define INC_SZ 2 //創(chuàng)建個人信息 typedef struct PeoInfo { char name[MAX_NAME]; int age; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo; 靜態(tài)版本的通訊錄 聲明一個通訊錄結(jié)構(gòu)體 //typedef struct Contact //{ // PeoInfo data[MAX]; // int sz; //}Contact; //動態(tài)版本的通訊錄 typedef struct Contact { PeoInfo* data;//data指向了存放數(shù)據(jù)的空間 int sz;//記錄通訊錄中的有效信息個數(shù) int capacity;//記錄通訊錄的容量 }Contact; //初始化結(jié)構(gòu)體 void InitContact(Contact* pc); //添加聯(lián)系人 void AddContact(Contact* pc); //顯示通訊錄 void ShowContact(const Contact* pc); //刪除指定聯(lián)系人 void DeleteContact(Contact* pc); //查找指定聯(lián)系人 void SearchContact(const Contact* pc); //修改指定聯(lián)系人 void ModifyContact(Contact* pc); //排序通訊錄 void SortContact(Contact* pc); //銷毀通訊錄 void DestroyContact(Contact* pc);
contact.c文件文章來源:http://www.zghlxwxcb.cn/news/detail-433029.html
#include"contact.h" //靜態(tài)版本 初始化通訊錄 //void InitContact(Contact* pc) //{ // pc->sz = 0; // memset(pc->data, 0, sizeof(pc->data)); // //} //動態(tài)版本 //初始化通訊錄 void InitContact(Contact* pc) { PeoInfo* ptr= (PeoInfo* )malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (ptr == NULL) { printf("通訊錄初始化失敗::%s", strerror(errno)); return; } else { pc->data = ptr; pc->sz = 0; pc->capacity = DEFAULT_SZ; } } //檢測通訊錄是否滿了 void CheckContact(Contact* pc) { //如果通訊錄滿了 就增容 if (pc->sz == pc->capacity) { PeoInfo* ptr= (PeoInfo*)realloc(pc->data,(pc->capacity+ INC_SZ)*sizeof(PeoInfo)); if (ptr == NULL) { printf("CheckContact::%s", strerror(errno)); return; } else { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功,當前容量為:%d\n", pc->capacity); } } //沒滿直接跳過以上語句 } //添加聯(lián)系人 void AddContact(Contact* pc) { CheckContact(pc); /*if (pc->data == pc->sz) { printf("通訊錄已滿,無法添加聯(lián)系人\n"); return; }*/ 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].tele); printf("請輸入地址:>"); scanf("%s", pc->data[pc->sz].addr); printf("添加成功\n"); pc->sz++; } //顯示通訊錄 void ShowContact(const Contact* pc) { printf("%-15s %-5s %-5s %-15s %-20s\n","姓名", "年齡", "性別", "電話", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s %-5d %-5s %-15s %-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex,pc->data[i].tele, pc->data[i].addr); } } //查找姓名= static int Findname(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i;//找到返回i } } return -1;//沒找到返回-1 } //刪除指定聯(lián)系人 void DeleteContact(Contact* pc) { if (0 == pc->sz) { printf("通訊錄為空,無法刪除聯(lián)系人\n"); return; } printf("請輸入姓名:>"); char name[MAX_NAME] = { 0 }; scanf("%s",name); //查找姓名 int pos = Findname(pc,name); //刪除 if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } int i = 0; for (i = pos; i < pc->sz; i++) { pc->data[pos] = pc->data[pos + 1]; } printf("刪除成功\n"); pc->sz--; } //查找指定聯(lián)系人 void SearchContact(const Contact* pc) { char name[MAX_NAME] = { 0 }; printf("請輸入姓名:>"); scanf("%s", name); int pos = Findname(pc, name); if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } printf("%-15s %-5s %-5s %-15s %-20s\n", "姓名", "年齡", "性別", "電話", "地址"); printf("%-15s %-5d %-5s %-15s %-20s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } //修改指定聯(lián)系人 void ModifyContact(Contact* pc) { printf("請輸入要修改人的姓名:>"); char name[MAX_NAME] = { 0 }; scanf("%s", name); int pos = Findname(pc, name); if (-1 == pos) { printf("聯(lián)系人不存在\n"); return; } printf("請輸入姓名:>"); scanf("%s", pc->data[pos].name); printf("請輸入年齡:>"); scanf("%d", &(pc->data[pos].age)); printf("請輸入性別:>"); scanf("%s", pc->data[pos].sex); printf("請輸入電話:>"); scanf("%s", pc->data[pos].tele); printf("請輸入地址:>"); scanf("%s", pc->data[pos].addr); printf("修改成功\n"); } //通過名字來排序 int cmp_by_name(const void* e1,const void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } //排序通訊錄 void SortContact(Contact* pc) { qsort(pc->data, pc->sz,sizeof(PeoInfo),cmp_by_name); printf("排序成功\n"); } //銷毀通訊錄 void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; printf("釋放成功...\n"); }
好了,動態(tài)版本的通訊錄就到這里,感謝各位讀者的支持~,如編寫有誤,還請聯(lián)系我???文章來源地址http://www.zghlxwxcb.cn/news/detail-433029.html
到了這里,關于【C語言】實現(xiàn)動態(tài)版通訊錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!