C語言靜態與動態通訊錄的實現流程詳解
本次通訊錄的代碼已經放到我的Gitee倉庫中,感興趣的小夥伴可以去看看
Gitee
靜態通訊錄
在我們學習完C語言的結構體、指針以及動態內存管理之後,我們就可以實現一些有意思的小項目瞭,通過這些小項目可以加深我們對於相關知識的理解。
靜態通訊錄主要要求有
- 靜態大小,可以記錄10個人的信息(大小自己定)
- 記錄的信息如下:名字、性別、年齡、電話、住址
- 可以實現聯系人的增刪查改
為瞭方便代碼的管理和維護,我們分文件實現以上的要求
- contact.h 用於聲明相關的接口
- contact.c 用於實現相關的接口
- test.c 用於測試相關的接口
contact.h
在contact.h中,我們統一用預處理指令來確定好通訊錄的大小,以及每一個聯系人信息的范圍大小,方便後續的修改
在確定好范圍後,我們通過定義結構體類型的方式來實現對數據的統一管理
結構體類型確定後,就是相關接口的聲明瞭
//首先引入需要用到的頭文件 #include<stdio.h> #include<stdlib.h> #include<string.h> //確定每一個聯系人名字、電話等信息的范圍大小 #define MAX_NAME 10 #define MAX_PHONE 20 #define MAX_ADDR 25 // 確定通訊錄的總大小 #define MAX_CAPACITY 10 //由於每一個聯系人都有多個信息,因此需要定義一個結構體類型來管理 //定義聯系人相關信息的結構體 typedef struct PeoInfo { char name[MAX_NAME]; char sex; int age; char phone[MAX_PHONE]; char address[MAX_ADDR]; }peo; //通訊錄內包含多個成員,因此也需要統一管理,所以還是使用結構體 //定義一個通訊錄結構體,管理通訊錄和記錄有效聯系人個數信息 typedef struct Contact { peo data[MAX_CAPACITY];//這裡是一個數組,數組的每一個元素都是一個結構體 int size; }con; //------------------------------------------------------ //以下是相關接口的聲明 //菜單接口 void menu(); //對結構體變量進行初始化 void InitContact(con* con); //打印通訊錄信息 void Print(con* con); //實現增加聯系人的接口 void AddContact(con* con); //實現刪除聯系人的接口 void DelContact(con* con); //實現查找聯系人的接口 void SearchContact(con* con); //實現修改聯系人的接口 void ModifyContact(con* con);
contact.c
contact.c是整個項目的關鍵,需要對相關接口進行定義
//通訊錄各個接口的實現 //首先引入.h文件 #include"Contact.h" //菜單接口 void menu() { printf("*******************************\n"); printf("********靜態簡易通訊錄*********\n"); printf("******* 0.退出通訊錄 ******\n"); printf("******* 1.增加聯系人 ******\n"); printf("******* 2.刪除聯系人 ******\n"); printf("******* 3.查找聯系人 ******\n"); printf("******* 4.修改聯系人 ******\n"); printf("******* 5.打印聯系人 ******\n"); printf("*******************************\n"); printf("\n"); } //對結構體變量進行初始化 void InitContact(con* con) { //結構體的初始化一般用memset //我們首先讓通訊錄結構體變量的數組一開始為0 memset(con->data, 0, sizeof(con->data)); con->size = 0;//同時由於此時一個聯系人的信息都沒有,所以size也是0 } //打印通訊錄信息 void Print(con* con){ int i = 0; if (con->size == 0) { printf("暫無可打印信息\n"); return ; } printf("name\tsex\tage\tphone\taddress\n"); for (i = 0; i < con->size; i++) { printf("%s\t%c\t%d\t%s\t%s\n", con->data[i].name, con->data[i].sex, con->data[i].age, con->data[i].phone, con->data[i].address); } } //實現增加聯系人的接口 void AddContact(con* con) { if (con->size == MAX_CAPACITY) { printf("容量已滿,無法增加\n"); return; } printf("請輸入姓名:\n"); scanf("%s", con->data[con->size].name); getchar(); printf("請選擇性別:(m表示男,w表示女)\n"); scanf("%c", &(con->data[con->size].sex)); printf("請輸入年齡:\n"); scanf("%d", &(con->data[con->size].age)); printf("請輸入手機號碼:\n"); scanf("%s", con->data[con->size].phone); printf("請輸入住址:\n"); scanf("%s", con->data[con->size].address); con->size++; } //實現刪除聯系人的接口 void DelContact(con* con) { if (con->size == 0) { printf("暫無可以刪除的信息"); return; } printf("請輸入你要刪除的聯系人的姓名:\n"); char name[MAX_NAME] = {0}; scanf("%s", name); int i = 0; for (i = 0; i < con->size; i++) { if (strcmp(name, (con->data)[i].name) == 0) { int j = 0; for (j = i; j < con->size - 1; j++) { memmove(&(con->data[j]), &(con->data[j + 1]), sizeof(con->data[0])); } con->size--; return; } } printf("你輸入的聯系人不存在\n"); } //實現查找聯系人的接口 void SearchContact(con* con) { if (con->size == 0) { printf("暫無查找的信息"); return; } printf("請輸入你要查找的聯系人的姓名:\n"); char name[MAX_NAME] = { 0 }; scanf("%s", name); int i = 0; for (i = 0; i < con->size; i++) { if (strcmp(name, (con->data)[i].name) == 0) { printf("%s\t%c\t%d\t%s\t%s\n", con->data[i].name, con->data[i].sex, con->data[i].age, con->data[i].phone, con->data[i].address); return; } } printf("你想要查找的聯系人不存在\n"); } //實現修改聯系人的接口 void ModifyContact(con* con) { if (con->size == 0) { printf("暫無可以修改的信息"); return; } printf("請輸入你要修改的聯系人的姓名:\n"); char name[MAX_NAME] = { 0 }; scanf("%s", name); int i = 0; for (i = 0; i < con->size; i++) { if (strcmp(name, (con->data)[i].name) == 0) { printf("請重新輸入姓名:\n"); scanf("%s", con->data[i].name); getchar(); printf("請重新選擇性別:(m表示男,w表示女)\n"); scanf("%c", &(con->data[i].sex)); printf("請重新輸入年齡:\n"); scanf("%d", &(con->data[i].age)); printf("請重新輸入手機號碼:\n"); scanf("%s", con->data[i].phone); printf("請重新輸入住址:\n"); scanf("%s", con->data[i].address); return; } } printf("你想要修改的聯系人不存在\n"); }
提示
我們在實現接口的時候,如果形參傳入的是指針,一般都需要先判斷一下傳入的指針是否為空指針,以免造成非法訪問,但是由於我的疏忽,就沒有寫上去瞭!
test.c
test.c就是用來測試相關接口的文件,可以根據自己的想法來設定
#include"Contact.h" int main() { //創建結構體並且初始化 con c; InitContact(&c); menu(); int input = 0; while (1) { printf("請輸入你的選擇:\n"); scanf("%d", &input); switch (input) { case 1: AddContact(&c); break; case 2: DelContact(&c); break; case 3: SearchContact(&c); break; case 4: ModifyContact(&c); break; case 5: Print(&c); break; case 0: printf("退出通訊錄\n"); break; default: printf("你的輸入有誤,請重新選擇\n"); break; } if (input == 0) { break; } } return 0; }
動態通訊錄
靜態通訊錄有一個缺點,那就是通訊錄的大小,也就是隻能存儲的聯系人是要求確定大小的,大小給多瞭浪費空間,給少瞭又不夠用。
動態通訊錄就是通過動態內存管理的函數來實現動態開辟空間大小,以滿足需要的。
contact.h
//動態版本通訊錄的實現 #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAX_NAME 15 #define MAX_PHONE 15 #define MAX_ADDR 25 //給定通訊錄默認大小為5,不夠可以增容 #define DefaultSize 5 //聯系人結構體的聲明 typedef struct PeoInfo { char name[MAX_NAME]; char sex; short age; char phone[MAX_PHONE]; char addr[MAX_ADDR]; }peo; //通訊錄結構體的聲明 typedef struct Contact { peo* p;//我們通過指針的方式來管理聯系人數組 int capacity; int size; }con; //菜單函數 void menu(); //初始化通訊錄 void InitCon(con* c); //銷毀通訊錄 void DestoryCon(con* c); //檢查容量的接口 void CheckCapacity(con* c); //打印聯系人信息 void Print(con* c); //聯系人的增加 void AddCon(con* c); //聯系人的刪除 void DelCon(con* c); //聯系人的查找 void SearchCon(con* c); //聯系人的修改 void ModifyCon(con* c); //------------------------------------------- //下面是我通過快排的原理,手寫的快排來實現一下通過聯系人名字和年齡排序的接口 //通過名字來排序 void SortByname(con* c); //通過年齡來排序 void SortByage(con* c); void Swap(char* p1, char* p2, int width); void QSort(void* p, int num, int width, int(*cmp)(const void* , const void* )); int cmpbyname(const void* p1,const void* p2); int cmpbyage(const void* p1,const void* p2);
contact.c
關鍵接口的實現和靜態通訊錄的大同小異,隻不過我們需要多定義一個檢查空間的接口
每次增加聯系人的時候,就調用這個接口,做到滿瞭就增容
其中增容接口使用的時realloc函數
#include"contact.h" //菜單函數 void menu() { printf("******************************************\n"); printf("************* 動態版通訊錄 ***********\n"); printf("************* 1.增加聯系人 ***********\n"); printf("************* 2.刪除聯系人 ***********\n"); printf("************* 3.查找聯系人 ***********\n"); printf("************* 4.修改聯系人 ***********\n"); printf("************* 5.按名字排序 ***********\n"); printf("************* 6.按年齡排序 ***********\n"); printf("************* 7.打印聯系人 ***********\n"); printf("************* 0.退出通訊錄 ***********\n"); printf("******************************************\n"); } //初始化通訊錄 void InitCon(con* c) { //這裡也可以用relloc函數來初始化,這樣的話就會有初始值 c->p = (con*)malloc(DefaultSize * sizeof(peo)); c->capacity = DefaultSize; c->size = 0; } //銷毀通訊錄 void DestoryCon(con* c) { free(c->p); c->p = NULL; c->capacity = 0; c->size = 0; } //檢查容量的接口 void CheckCapacity(con* c) { if (c->capacity == c->size) { //每次增容二倍 peo* tmp = (peo*)realloc(c->p, 2 * (c->capacity) * sizeof(peo)); if (tmp != NULL) { c->p = tmp; c->capacity = 2 * c->capacity; printf("增容成功\n"); } else { printf("增容失敗\n"); exit(1); } } } //打印聯系人信息 void Print(con* c) { if (c->size == 0) { printf("暫無可以打印的信息\n"); return; } printf("name\tsex\tage\tphone\taddress\n"); int i = 0; for (i = 0; i < c->size; i++) { printf("%s\t%c\t%d\t%s\t%s\n", c->p[i].name, c->p[i].sex, c->p[i].age, c->p[i].phone, c->p[i].addr); } } //聯系人的增加 void AddCon(con* c) { //每一次增加聯系人都要先檢查容量是否足夠 CheckCapacity(c); printf("請輸入名字:>\n"); scanf("%s", c->p[c->size].name); getchar(); printf("請輸入性別:>(m表示男,w表示女)\n"); scanf("%c", &(c->p[c->size].sex)); printf("請輸入年齡:>\n"); scanf("%d", &(c->p[c->size].age)); printf("請輸入電話:>\n"); scanf("%s", c->p[c->size].phone); printf("請輸入地址:>\n"); scanf("%s", c->p[c->size].addr); c->size++; printf("添加成功\n"); } //聯系人的刪除 void DelCon(con* c) { printf("請輸入你想要刪除的聯系人的名字\n"); char name[MAX_NAME]; scanf("%s", name); int i = 0; for (i = 0; i < c->size; i++) { if (strcmp(name, c->p[i].name) == 0) { int j = i; for (j = i; j < c->size - 1; j++) { memmove(&(c->p[j]), &(c->p[j + 1]), sizeof(c->p[0])); } c->size--; return; } } printf("你想要刪除的聯系人不存在\n"); } //聯系人的查找 void SearchCon(con* c) { printf("請輸入你想要查找的人的名字:\n"); char name[MAX_NAME]; scanf("%s", name); int i = 0; for (i = 0; i < c->size; i++) { if (strcmp(name, c->p[i].name) == 0) { printf("%s\t%c\t%d\t%s\t%s\n", c->p[i].name, c->p[i].sex, c->p[i].age, c->p[i].phone, c->p[i].addr); return; } } printf("你想要查找的聯系人不存在\n"); } //聯系人的修改 void ModifyCon(con* c) { printf("請輸入你想要修改的人的名字:\n"); char name[MAX_NAME]; scanf("%s", name); int i = 0; for (i = 0; i < c->size; i++) { if (strcmp(name, c->p[i].name) == 0) { printf("請重新輸入名字:>\n"); scanf("%s", c->p[i].name); getchar(); printf("請重新輸入性別:>(m表示男,w表示女)\n"); scanf("%c", &(c->p[i].sex)); printf("請重新輸入年齡:>\n"); scanf("%d", &(c->p[i].age)); printf("請重新輸入電話:>\n"); scanf("%s", c->p[i].phone); printf("請重新輸入地址:>\n"); scanf("%s", c->p[i].addr); return; } } printf("你想要修改的聯系人不存在\n"); } //通過名字來排序 void SortByname(con* c) { QSort(c->p, c->size, sizeof(c->p[0]),cmpbyname ); } //通過年齡來排序 void SortByage(con* c) { QSort(c->p, c -> size, sizeof(c->p[0]), cmpbyage); }
qsort.c
這是我根據快速排序的原理,手寫的快速排序
#include"contact.h" //快排的交換函數 void Swap(char* p1, char* p2, int width) { int i = 0; for (i = 0; i < width; i++) { char tmp = *p1; *p1 = *p2; *p2 = tmp; p1++; p2++; } } //手寫快排來進行通訊錄排序 void QSort(void* p, int num, int width, int(*cmp)(const void*, const void*)) { int i = 0; for (i = 0; i < num - 1; i++) { int j = 0; for (j = 0; j < num - 1 - i; j++) { if (cmp((char*)p + j * width, (char*)p + (j + 1) * width) > 0) { Swap((char*)p + j * width, (char*)p + (j + 1) * width, width); } } } } int cmpbyage(const void* p1, const void* p2) { return (*(peo*)p1).age - (*(peo*)p2).age; } int cmpbyname(const void* p1, const void* p2) { return strcmp(((peo*)p1)->name,((peo*)p2)->name); }
test.c
test.c用於測試相關的接口,可以根據自己的想法來測試
#include"contact.h" int main() { menu(); int input = 0; con c; InitCon(&c); while (1) { printf("請輸入你的選擇:\n"); scanf("%d", &input); switch (input) { case 1: AddCon(&c); break; case 2: DelCon(&c); break; case 3: SearchCon(&c); break; case 4: ModifyCon(&c); break; case 5: SortByname(&c); break; case 6: SortByage(&c); break; case 7: Print(&c); break; case 0: printf("退出通訊錄\n"); break; } if (input == 0) { DestoryCon(&c); break; } } return 0; }
到此這篇關於C語言靜態與動態通訊錄的實現流程詳解的文章就介紹到這瞭,更多相關C語言 通訊錄內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!