C語言實(shí)現(xiàn)靜態(tài)版通訊錄的示例代碼
前言
大家好~今天要實(shí)現(xiàn)一個(gè)非常有意思的東西–通訊錄。
通訊錄需求分析
為了實(shí)現(xiàn)通訊錄管理系統(tǒng),為此,要保證實(shí)現(xiàn)以下的功能:
能夠存放1000個(gè)聯(lián)系人的信息、每個(gè)人的信息包含:名字、年齡、性別、電話、地址、除此之外,還是實(shí)現(xiàn):增加人的信息、刪除人的信息、修改指定人的信息、查找指定人的信息、清空聯(lián)系人的信息、顯示聯(lián)系人的信息、排序通訊錄的信息.
功能介紹
1.增加聯(lián)系人信息
2.刪除聯(lián)系人信息
3.查找聯(lián)系人信息
4.修改聯(lián)系人信息
5.顯示聯(lián)系人信息
6.排序聯(lián)系人信息
7.清空聯(lián)系人信息
實(shí)現(xiàn)思路
靜態(tài)版本的通訊錄首先聲明一個(gè)結(jié)構(gòu)體類型(struct PeoInfo)用來描述一個(gè)人的聯(lián)系人的各種信息;
然后再聲明一個(gè)結(jié)構(gòu)體類型(struct Contact)用來描述通訊錄,成員使用數(shù)組開辟1000個(gè)聯(lián)系人的內(nèi)存空間實(shí)現(xiàn)通訊錄,數(shù)組的類型為struct PeoInfo
最后就是對存放聯(lián)系人信息數(shù)組的一系列訪問操作,封裝各個(gè)函數(shù)實(shí)現(xiàn)各部分功能!
代碼實(shí)現(xiàn)
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" void menu() { printf("*******************************\n"); printf("***** 1.add 2.del *****\n"); printf("***** 3.search 4.modify *****\n"); printf("***** 5.sort 6.print *****\n"); printf("***** 7.clear 0.exit *****\n"); printf("*******************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, PRINT, CLEAR }; int main() { int input = 0; //創(chuàng)建通訊錄,結(jié)構(gòu)體類型在頭文件中定義的,所以要引頭文件,MAX的定義在頭文件或者該源文件內(nèi)定義都是可以的,因?yàn)榘祟^文件 //但是如果把數(shù)組和數(shù)組元素個(gè)數(shù)sz定義成一個(gè)結(jié)構(gòu)體,就要去頭文件中定義,那邊就需要MAX,如果MAX在test.c中定義的話,contact.h中就會報(bào)錯(cuò) //既然這樣,就直接把MAX定義在contact.h中去,即可。 //PeoInfo data[MAX] = { 0 };//不完全初始化 //通訊錄中當(dāng)前有幾個(gè)元素: //int sz = 0; //創(chuàng)建通訊錄 Contact con; //con就是通訊錄,也可以直接進(jìn)行初始化,但是為了更好的體現(xiàn)模塊化,就對初始化通訊錄封裝一個(gè)函數(shù)。 //如果想把其中的一部分初始化為0,就必須使用函數(shù)來做了。 //初始化通訊錄 InitContact(&con); //初始化通訊錄的時(shí)候要對通訊錄中的內(nèi)容進(jìn)行修改,如果傳值調(diào)用的話,不會修改實(shí)參中的內(nèi)容,而且效率低,所以要傳址調(diào)用。 do { menu(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case ADD: //增加聯(lián)系人信息 AddContact(&con); //要把數(shù)組和數(shù)組元素個(gè)數(shù)都進(jìn)行傳參,會比較麻煩,把兩者定義成一個(gè)新的結(jié)構(gòu)體 break; case DEL: //刪除聯(lián)系人信息 DelContact(&con); break; case SEARCH: //查找聯(lián)系人信息 SearchContact(&con); break; case MODIFY: //修改聯(lián)系人信息 ModifyContact(&con); break; case SORT: //排序聯(lián)系人信息 SortContact(&con); break; case PRINT: //雖然只是打印信息,不會改變實(shí)參的信息,但是考慮的效率的話,還是使用傳址調(diào)用比較好,結(jié)構(gòu)體傳參最好傳地址。 PrintContact(&con); break; case CLEAR: //清空所有聯(lián)系人信息 ClearContact(&con); break; case EXIT: printf("退出通訊錄\n"); break; default: printf("選擇錯(cuò)誤,請重新選擇:>"); break; } } while (input); //如果有同名的,一律操作第一個(gè)出現(xiàn)該名字的那個(gè)成員,因?yàn)楸闅v是從前往后遍歷的,在這里不考慮同名的情況。 return 0; }
contact.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" //初始化通訊錄 void InitContact(Contact* pc) { assert(pc); //內(nèi)存設(shè)置函數(shù) — memset() - 內(nèi)存設(shè)置 (pc->sz) = 0; memset(pc->data, 0, sizeof(pc->data)); //pc->data 就相當(dāng)于找到了整個(gè)數(shù)組,而整個(gè)數(shù)組可以使用數(shù)組名來表示,所以可以使用data來表示整個(gè)數(shù)組 //即:pc->data === data ,,,數(shù)組名在第一個(gè)參數(shù)中沒有&和sizeof,代表的是數(shù)組首元素的地址,第二個(gè)參數(shù)是把 //每一個(gè)字節(jié)都設(shè)置成0,十進(jìn)制的0,轉(zhuǎn)為十六進(jìn)制表示形式就是0x 00,,pc->data === data,數(shù)組名單獨(dú)放在 //sizeof中,代表的是整個(gè)數(shù)組,計(jì)算的是整個(gè)數(shù)組的大小,單位是字節(jié)也可以寫成:MAX * sizeof(Contact) } //增加聯(lián)系人 void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { printf("通訊錄已滿、無法添加新的聯(lián)系人\n"); return; //返回類型是void,也可以寫return,但是不能帶出去返回值。 } //通訊錄未滿,可以添加新成員,增加一個(gè)人的信息 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); pc->sz++; printf("增加聯(lián)系人成功\n"); //在這里,[ ]的優(yōu)先級等于->,,但是,data和[ ]是不可以先進(jìn)行結(jié)合的,因?yàn)?,這是在一個(gè)調(diào)用函數(shù)中,形參那部分接受到的只有指針變量pc //也就是說,如果后兩者進(jìn)行結(jié)合的話,系統(tǒng)根本就不知道data是什么東西,所以它結(jié)合出來是錯(cuò)誤的,即,即使[ ]的優(yōu)先級等于->,但是后兩者不能 //進(jìn)行結(jié)合會出錯(cuò),又因結(jié)合性從左到右所以,還是先讓data和->進(jìn)行結(jié)合,即先進(jìn)行pc->data的操作,所以在結(jié)構(gòu)體成員變量中找到了整個(gè)數(shù)組data //而整個(gè)數(shù)組可以使用數(shù)組名進(jìn)行表示,知道了數(shù)組名就可以再通過下標(biāo)對數(shù)組元素進(jìn)行訪問了。 } //顯示聯(lián)系人信息 void PrintContact(const Contact* pc) { assert(pc); //打印出所有人的信息,即sz個(gè)人的信息。 int i = 0; //打印標(biāo)題 printf("%-10s\t%-5s\t%-5s\t%-12s\t%-50s\n", "名字", "年齡", "性別", "電話", "地址");// \t === tab //打印數(shù)據(jù) for (i = 0; i < (pc->sz); i++) { printf("%-10s\t%-5d\t%-5s\t%-12s\t%-50s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } //通過pc->data[i]找到數(shù)組data中下標(biāo)為i的元素,即找到了一個(gè)變量,再通過點(diǎn)來訪問該人的姓名等,,由于姓名是一個(gè)數(shù)組,找到的就是整個(gè)數(shù)組,整個(gè) //數(shù)組又可以使用數(shù)組名來表示,即:pc->data[i].name === name ,沒有sizeof和&,代表數(shù)組首元素的地址,再通過%s進(jìn)行打印字符串,除了年齡是一個(gè)變量,其他的都是數(shù)組,和name同理。 } //因?yàn)樵摵瘮?shù)只是為了滿足刪除,查找,修改功能的需要,而這三個(gè)功能對應(yīng)的函數(shù)的實(shí)現(xiàn)都會在該 .c 文件內(nèi)進(jìn)行實(shí)現(xiàn),所以,對于這個(gè)函數(shù) //只需要在該 .c 文件內(nèi)執(zhí)行即可,不許要暴露給別人,,所以,在前面加上static,就固定了該函數(shù)只在目前所在的 .c 文件內(nèi)進(jìn)行工作即可。 //static 修飾函數(shù),本質(zhì)上是改變了函數(shù)的鏈接屬性。 static int Find_By_Name(const Contact* pc, char name[])//數(shù)組形式接收,數(shù)組形式接受的話就不考慮const的使用了。 { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0)//相等 //第一個(gè)參數(shù)先找到整個(gè)數(shù)組,可以使用數(shù)組名來表示,不是特例,即代表數(shù)組首元素的地址,第二個(gè)參數(shù)也不是特例,也是數(shù)組首元素的地址。 { return i; } } return -1; } //刪除聯(lián)系人信息 void DelContact(Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; if (pc->sz == 0) { printf("通訊錄為空、不可以再進(jìn)行刪除操作\n"); return; } //刪除某個(gè)人的信息 printf("請輸入要?jiǎng)h除人員的姓名:>"); scanf("%s", name); //1、查找要?jiǎng)h除的人 //不管是刪除還是查找還是修改,都需要使用到查找這個(gè)功能,所以就單獨(dú)把該功能拿出來封裝一個(gè)函數(shù); int pos = Find_By_Name(pc, name);//一級指針傳參和數(shù)組名傳參 //不存在該人 if (pos == -1) { printf("要?jiǎng)h除的人員不存在\n"); return; } //2、存在該人員,要進(jìn)行刪除,把數(shù)組該位置上的人員刪除之后,數(shù)組后面的人員依次往前移動一個(gè)位置。 int i = 0; for (i = pos; i < (pc->sz - 1); i++) { pc->data[i] = pc->data[i + 1]; } //pc->sz -= 1; pc->sz--; //如果想刪除最后一個(gè),是刪除不掉的,因?yàn)?,如?0個(gè)元素,最后一個(gè)下標(biāo)為9,判斷條件是<9,,所以不進(jìn)入循環(huán),但是 //循環(huán)后面還有pc->sz--,,成員個(gè)數(shù)少了1,再顯示人員信息的時(shí)候,訪問不到最后一個(gè)人員了,,即使沒刪掉,也訪問不掉, //最后的結(jié)果和刪掉最后一個(gè)人員的效果是一樣的。 //假設(shè)MAX=3,把最后一個(gè)元素刪除,本質(zhì)上并沒有從數(shù)組中刪除掉,而是因?yàn)閟z減1,打印的時(shí)候不訪問最后一個(gè)元素,看起來和刪除的效果是一樣的,現(xiàn)在由于 //看起來刪了,本質(zhì)上沒刪去,如果再添加新元素會怎么樣呢? //因?yàn)閯h除完之后,元素個(gè)數(shù)就會減去1,由原來的3變成了2,,再添加新元素的時(shí)候,就會直接把新元素的內(nèi)容放在下標(biāo)為2的位置上,這樣的話,即使之前的最后一個(gè)元素 //沒刪去,也會被新的元素覆蓋掉,添加完之后元素個(gè)數(shù)加1,再打印出來就是添加成員后的信息,是對的。 printf("刪除聯(lián)系人員成功\n"); } //查找聯(lián)系人信息 void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; //查找某個(gè)人的信息 printf("請輸入要查找人員的姓名:>"); scanf("%s", name); int pos = Find_By_Name(pc, name); //要查找的人員不存在 if (pos == -1) { printf("要查找的人員不存在\n"); return; } //2、存在該人員,找出之后并打印出該成員的信息 //打印標(biāo)題 printf("%-10s\t%-5s\t%-5s\t%-12s\t%-50s\n", "名字", "年齡", "性別", "電話", "地址");// \t === tab //打印數(shù)據(jù) printf("%-10s\t%-5d\t%-5s\t%-12s\t%-50s\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) { assert(pc); char name[MAX_NAME] = { 0 }; //修改某個(gè)人的信息 printf("請輸入要修改人員的姓名:>"); scanf("%s", name); int pos = Find_By_Name(pc, name); //要修改的人員不存在 if (pos == -1) { printf("要修改的人員不存在\n"); return; } else { 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].addr); printf("請輸入修改后人員的電話:>"); scanf("%s", pc->data[pos].tele); printf("修改聯(lián)系人員信息成功\n"); } } int cmp_Per_by_name(const void* e1, const void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } void SortContact(Contact* pc) { assert(pc); qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_Per_by_name); PrintContact(pc); } void ClearContact(Contact* pc) { assert(pc); InitContact(pc); printf("清空成功\n"); }
contact.h
#pragma once //類型的定義、通訊錄中要放1000個(gè)人的信息, //每個(gè)人的信息要包括名字、年齡、性別、電話、地址等, //所以要定義成一個(gè)結(jié)構(gòu)體,而該結(jié)構(gòu)體要在兩個(gè)源文件中使用, //所以最好定義在頭文件中,這樣只需要包含一下頭文件就可以頻繁的使用了 //頭文件的包含 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> //定義結(jié)構(gòu)體類型 #define MAX_NAME 20 #define MAX_SEX 10 #define MAX_TELE 12 #define MAX_ADDR 30 #define MAX 1000 typedef struct PeoInfo { //char name[20]; //直接寫成固定值就寫死了,不方便后期的修改, //所以使用#define 來定義一個(gè)常量,后期直接改變#define中的內(nèi)容即可。 char name[MAX_NAME]; char sex[MAX_SEX]; int age; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo;//使用typedef對結(jié)構(gòu)體類型重命名為:PeoInfo //結(jié)構(gòu)體嵌套 //通訊錄 typedef struct Contact//重命名 { PeoInfo data[MAX];//存放添加進(jìn)去的聯(lián)系人的信息 int sz;//記錄當(dāng)前通訊錄中有效信息的個(gè)數(shù) }Contact; //初始化通訊錄 void InitContact(Contact* pc); //增加聯(lián)系人 void AddContact(Contact* pc); //打印信息 void PrintContact(const Contact* pc); //刪除聯(lián)系人信息 void DelContact(Contact* pc); //查找聯(lián)系人信息 void SearchContact(const Contact* pc); //修改指定聯(lián)系人的信息 void ModifyContact(Contact* pc); //排序聯(lián)系人的信息 void SortContact(Contact* pc); //清空所有聯(lián)系人的信息 void ClearContact(Contact* pc);
效果圖
以上就是C語言實(shí)現(xiàn)靜態(tài)版通訊錄的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于C語言靜態(tài)通訊錄的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c語言中exit和return的區(qū)別點(diǎn)總結(jié)
小編今天給大家整理了關(guān)于c語言中exit和return的不同點(diǎn)及相關(guān)基礎(chǔ)知識點(diǎn),有興趣的朋友們可以跟著學(xué)習(xí)下。2021-10-10C語言實(shí)現(xiàn)魔方比賽管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)魔方比賽管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C語言中send()函數(shù)和sendto()函數(shù)的使用方法
這篇文章主要介紹了C語言中send()函數(shù)和sendto()函數(shù)的使用方法,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09C語言實(shí)現(xiàn)字符串操作函數(shù)的實(shí)例
這篇文章主要介紹了C語言實(shí)現(xiàn)字符串操作函數(shù)的實(shí)例的相關(guān)資料,開發(fā)程序的時(shí)候經(jīng)常使用到一些字符串函數(shù),例如求字符串長度,拷貝字符串……,需要的朋友可以參考下2017-08-08C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程
這篇文章主要介紹了C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程,以struct語句定義的結(jié)構(gòu)體是C語言編程中的重要基礎(chǔ),需要的朋友可以參考下2015-12-12使用c語言輕松實(shí)現(xiàn)動態(tài)內(nèi)存管
這篇文章主要介紹了使用c語言輕松實(shí)現(xiàn)動態(tài)內(nèi)存管,本文章內(nèi)容詳細(xì),具有很好的參考價(jià)值,希望對大家有所幫助,需要的朋友可以參考下2023-01-01windows系統(tǒng)下C++調(diào)用matlab程序的方法詳解
這篇文章主要給大家介紹了關(guān)于在windows系統(tǒng)下C++調(diào)用matlab程序的方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08