要求:
實現一個通訊錄。
(1)人的信息:
? ? ? ? 包括姓名、年齡、性別、電話地址。
(2)功能:
? ? ? ? ①存放一百個人的信息。
? ? ? ? ②增加聯系人。
? ? ? ? ③刪除指定聯系人。
? ? ? ? ④查找指定聯系人。
? ? ? ? ⑤修改聯系人。
? ? ? ? ⑥排序。
? ? ? ? ⑦顯示聯系人。
(3)文件:
? ? ? ? ①contact.c:通訊錄實現的文件。
? ? ? ? ②contact.h:通訊錄聲明的文件。
? ? ? ? ③test.c? ? ? :測試通訊錄的文件。
目錄
1.框架的搭建
2. 結構體的聲明以及初始化
2.1 結構體的聲明
2.2 結構體的初始化
3. 通訊錄的增加功能
4. 展示通訊錄的功能
5.刪除、查找指定聯系人
6.查找聯系人
7. 修改聯系人
8.排序聯系人
9.完整代碼
9.1 contact.h
9.2 contact.c
9.3 test.c
10.功能演示
10.1添加、展示
10.2?刪除
10.3?查找
10.4?修改
10.5?排序
1.框架的搭建
? ? ? ? ?整體采用dowhile的結構,讀取用戶的輸入根據不同的輸入選項,調用不同的方法從而實現不同的功能。
在test.c中代碼如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>void menu()
{printf("=====================================");printf("======1.add 2.del ========");printf("======3.search 4.modify ========");printf("======5.show 6.sort ========");printf("======0.exit ========");printf("=====================================");
}int main()
{int input = 0;do{menu();printf("請輸入一個選項:\n");scanf("%d", &input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 0:printf("程序已退出!\n");break;default:printf("請正確輸入選項!\n");break;}} while (input);return 0;
}
2. 結構體的聲明以及初始化
2.1 結構體的聲明
? ? ? ? 這個部分需要在頭文件中contact.h,編寫完畢之后若要使用改結構體需要在test.c中引用該頭文件。
? ? ? ? 首先聲明一個人信息的結構體,具體成員變量詳見文章開頭。
? ? ? ? 我們思考一下,如果我們在主函數中創建了一個100個人信息的結構體數組,我們還需要一個變量來記錄這100個變量中實際存放的變量的個數,那么我們可以封裝成一個通訊錄結構體,通訊錄結構體中包含一個人信息結構體數組和實際存放結構體變量的數目。
? ? ? ? 此時可以在主函數聲明一個通訊錄結構體變量,這樣就會更加的方便。
2.2 結構體的初始化
? ? ? ? 需要將通訊錄結構體變量進行初始化,我們可以在頭文件聲明一個初始化函數形參傳入指針;將成員變量count置為0,將成員變量PeoInfo 類型的數組全部置為0,可以使用memset來實現。
????????這里需要注意一個細節,既然測試函數和邏輯函數都引用頭文件,那么不妨直接把第三方庫全部放在頭文件中,這樣一來只需要引用頭文件即可。
3. 通訊錄的增加功能
①在頭文件中進行方法的聲明,形參需要傳入通訊錄變量的地址;
②具體實現在contact.c中實現。
③首先需要判斷指針是否為空。
④如果通訊錄的count == 100,說明通訊錄已經滿了,提示用戶并且直接返回。
這里需要注意的是,在代碼中出現的數字都可以使用define關鍵字進行宏定義,后面方便修改。
⑤count可以當做結構體數組下標一用,使用scanf來輸入數據,這里需要注意的是數組名本就是地址,除了age需要取地址,剩余四個成員變量不需要取地址。
// 通訊錄的增加方法
void addContact(Contact* p)
{assert(p); // 斷言空指針if (p->count == N){printf("通訊錄已滿!存不下了!\n");return;}printf("請輸入姓名:\n");scanf("%s",(p->list)[p->count].name);printf("請輸入年齡:\n");scanf("%d", &((p->list)[p->count].age));printf("請輸入性別:\n");scanf("%s", (p->list)[p->count].gender);printf("請輸入電話號碼:\n");scanf("%s", (p->list)[p->count].tele);printf("請輸入地址:\n");scanf("%s", (p->list)[p->count].addr);(p->count)++;printf("通訊錄增加成功!");
}
4. 展示通訊錄的功能
①首先在頭文件定義方法,這個方法的形參是一個const Contact的指針,因為只需要展示無需修改。
②遍歷打印p指針指向的結構體即可。
③唯一需要注意的是:輸出的格式要對齊,使用左對齊,在%后加上一個-號。
// 通訊錄的顯示
void showContact(const Contact* p)
{assert(p);int i = 0;printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n","姓名","年齡","性別","電話","地址");for(i = 0;i < p->count; i++){printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[i].name,(p->list)[i].age,(p->list)[i].gender,(p->list)[i].tele,(p->list)[i].addr);}
}
左對齊的樣式:
5.刪除、查找指定聯系人
①首先需要判斷Contact數組有效元素是否為空,如果為空直接返回;
②刪除之前需要讀取聯系人姓名,根據姓名來查找,找到了就返回下標,沒找到就返回-1;
③查找這個動作在修改、查找等功能都會用到,所以可以先封裝成一個函數,具有兩個參數,第一個參數是結構體的指針,第二個是查找的名字。
? ? ? ? (1)查找的邏輯:
? ? ? ? ? ? ? ? a.遍歷通訊錄中的PeoInfo數組;
? ? ? ? ? ? ? ? b.判斷數組中的姓名是否和傳入姓名一致;
? ? ? ? ? ? ? ? c.一致就返回下標,沒找到就返回-1;
static int findByname(const Contact* p,char name[])
{assert(p);int i = 0;for ( i = 0; i < p->count; i++){if (strcmp(p->list[i].name,name ) == 0){return i;}}return -1;
}
查找函數不在外界暴露,所以不需要聲明,最好加上關鍵字static修飾,只有本文件能夠訪問。?
④查找到了之后需要根據下標進行刪除,其實就是將數組的此下標的后面元素向前覆蓋即可;需要將有效數據count再-1;
// 通訊錄的刪除
void deleContact(Contact* p)
{char name[NAME_LONG] = { 0 };assert(p);// 判斷通訊錄聯系人數量為0if (p->count == 0){printf("通訊錄為空,無法刪除\n");}printf("請輸入要刪除的聯系人姓名\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("刪除的聯系人不存在!\n");return;}else{// 刪除for (int i = ret; i < p->count - 1; i++){p->list[i] = p->list[i + 1];}p->count--; // 有效的數據-1printf("刪除成功!!\n");}
}
6.查找聯系人
? ? ? ? 我們之前已經寫過函數了,所以這里只需要封裝一層。
// 通訊錄的查找
void SearchContact(Contact* p)
{char name[NAME_LONG];printf("請輸入查找的姓名:\n");scanf("%s",name);int ret = findByname(p, name);if (ret == -1) {printf("該姓名不存在!\n");return;}else {printf("查找成功!以下是該聯系人的信息:\n");printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[ret].name,(p->list)[ret].age,(p->list)[ret].gender,(p->list)[ret].tele,(p->list)[ret].addr);}
}
7. 修改聯系人
①先根據姓名查找。
②找到了就根據下標來進行修改(和添加聯系人雷同);
③找不到就提示并返回。
// 通訊錄的修改
void ModifyContact(Contact* p)
{char name[NAME_LONG];printf("請輸入要修改的聯系人姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("請輸入修改姓名:\n");scanf("%s", (p->list)[ret].name);printf("請輸入修改年齡:\n");scanf("%d", &((p->list)[ret].age));printf("請輸入修改性別:\n");scanf("%s", (p->list)[ret].gender);printf("請輸入修改電話號碼:\n");scanf("%s", (p->list)[ret].tele);printf("請輸入修改地址:\n");scanf("%s", (p->list)[ret].addr);printf("通訊錄修改成功!\n");}
}
8.排序聯系人
①直接使用qsort函數即可,唯一需要注意的是明確按照什么來排序,這里按照姓名來排序
②首先保證傳入的指針有效。
③qsort的第一個參數是排序的起始地址,第二個參數是排序元素的個數,第三個參數是每一個元素的字節數,第四個是一個比較函數,這個比較函數的形參有兩個void*指針,需要強轉成排序的兩個元素的指針類型。
size_t contact_cmp(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}// 通訊錄的排序
void SortContact(Contact* p)
{assert(p);qsort(p->list, p->count, sizeof(p->list[0]), contact_cmp);printf("排序成功!\n");
}
9.完整代碼
9.1 contact.h
#define _CRT_SECURE_NO_WARNINGS
#define N 100
#define NAME_LONG 20
#define GENDER_LONG 10
#define TELE_LONG 12
#define ADDRESS_LONG 30
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
// 人信息的結構體聲明
typedef struct PeoInfo
{char name[NAME_LONG]; // 姓名int age; // 年齡char gender[GENDER_LONG]; // 性別char tele[TELE_LONG]; // 電話號碼char addr[ADDRESS_LONG]; // 地址
}PeoInfo;// 通訊錄結構體的聲明
typedef struct Contact
{// 通訊錄假如可以存放一百條信息PeoInfo list[N];// 真實存放的信息的條數int count;
}Contact;// 初始化通訊錄結構體變量
void InitContact(Contact* p);// 通訊錄的增加方法
void addContact(Contact* p);// 通訊錄的顯示
void showContact(const Contact* p);// 通訊錄的刪除
void deleContact(Contact* p);// 通訊錄的查找
void SearchContact(Contact* p);// 通訊錄的修改
void ModifyContact(Contact* p);// 通訊錄的排序
void SortContact(Contact* p);
9.2 contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"// 初始化通訊錄結構體變量
void InitContact(Contact* p)
{assert(p);p->count = 0;memset(p, 0, sizeof(p->list)); // list是PeoInfo的結構體數組
}// 通訊錄的增加方法
void addContact(Contact* p)
{assert(p);if (p->count == N){printf("通訊錄已滿!存不下了!\n");return;}printf("請輸入姓名:\n");scanf("%s", (p->list)[p->count].name);printf("請輸入年齡:\n");scanf("%d", &((p->list)[p->count].age));printf("請輸入性別:\n");scanf("%s", (p->list)[p->count].gender);printf("請輸入電話號碼:\n");scanf("%s", (p->list)[p->count].tele);printf("請輸入地址:\n");scanf("%s", (p->list)[p->count].addr);(p->count)++;printf("通訊錄增加成功!\n");
}// 通訊錄的顯示
void showContact(const Contact* p)
{assert(p);int i = 0;printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");for (i = 0; i < p->count; i++){printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[i].name,(p->list)[i].age,(p->list)[i].gender,(p->list)[i].tele,(p->list)[i].addr);}
}static int findByname(const Contact* p, char name[])
{assert(p);int i = 0;for (i = 0; i < p->count; i++){if (strcmp(p->list[i].name, name) == 0){return i;}}return -1;
}// 通訊錄的刪除
void deleContact(Contact* p)
{char name[NAME_LONG] = { 0 };assert(p);// 判斷通訊錄聯系人數量為0if (p->count == 0){printf("通訊錄為空,無法刪除\n");}printf("請輸入要刪除的聯系人姓名\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("刪除的聯系人不存在!\n");return;}else{// 刪除for (int i = ret; i < p->count - 1; i++){p->list[i] = p->list[i + 1];}p->count--; // 有效的數據-1printf("刪除成功!!\n");}
}// 通訊錄的查找
void SearchContact(Contact* p)
{char name[NAME_LONG];printf("請輸入查找的姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("查找成功!以下是該聯系人的信息:\n");printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話", "地址");printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",(p->list)[ret].name,(p->list)[ret].age,(p->list)[ret].gender,(p->list)[ret].tele,(p->list)[ret].addr);}
}// 通訊錄的修改
void ModifyContact(Contact* p)
{char name[NAME_LONG];printf("請輸入要修改的聯系人姓名:\n");scanf("%s", name);int ret = findByname(p, name);if (ret == -1){printf("該姓名不存在!\n");return;}else{printf("請輸入修改姓名:\n");scanf("%s", (p->list)[ret].name);printf("請輸入修改年齡:\n");scanf("%d", &((p->list)[ret].age));printf("請輸入修改性別:\n");scanf("%s", (p->list)[ret].gender);printf("請輸入修改電話號碼:\n");scanf("%s", (p->list)[ret].tele);printf("請輸入修改地址:\n");scanf("%s", (p->list)[ret].addr);printf("通訊錄修改成功!\n");}
}size_t contact_cmp(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}// 通訊錄的排序
void SortContact(Contact* p)
{assert(p);qsort(p->list, p->count, sizeof(p->list[0]), contact_cmp);printf("排序成功!\n");
}
9.3 test.c
#define _CRT_SECURE_NO_WARNINGS
#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");
}int main()
{// 聲明通訊錄結構體變量Contact con;// 初始化通訊錄結構體變量InitContact(&con);int input = 0;do{menu();printf("請輸入一個選項:\n");scanf("%d", &input);switch (input){case 1:addContact(&con);break;case 2:deleContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:showContact(&con);break;case 6:SortContact(&con);break;case 0:printf("程序已退出!\n");break;default:printf("請正確輸入選項!\n");break;}} while (input);return 0;
}