c語言實現(xiàn)通訊錄管理系統(tǒng)詳細實例
一、前言
本文將會用c語言實現(xiàn)一個通訊錄的系統(tǒng),并且存儲若干人的信息,每個人的信息包括:姓名,性別,年齡,電話號碼,住址。此通訊錄系統(tǒng)的功能包括: 1.增加聯(lián)系人 2.刪除對應的聯(lián)系人 3.查找聯(lián)系人 4.修改聯(lián)系人的信息 5.排序此通訊錄 6.打印出通訊錄每個人的信息
二、通訊錄的實現(xiàn)
1.關于通訊錄的前期準備
(1)菜單的實現(xiàn)
首先關于一個通訊錄,建立一個菜單是很重要的,菜單能夠?qū)崿F(xià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.排序通訊錄=============\n"); printf("============6.打印通訊錄=============\n"); printf("============0.退出通訊錄=============\n"); printf("=====================================\n"); }
效果差不都就是這樣子
(2)關于聯(lián)系人結(jié)構體的創(chuàng)建
這里我們需要利用結(jié)構體來實現(xiàn)實現(xiàn)前言中的通訊錄功能以及聯(lián)系人信息,我將利用兩個結(jié)構體來構建我們需要的東西。
typedef struct PeoInfo { char name[NAME_MAX]; char sex[SEX_MAX]; int age; char tele[TELE_MAX]; char addr[ADDR_MAX]; }Peo; typedef struct Contact { Peo con[PON_MAX]; int sz;//記錄數(shù)量 }contact;
關于第一個結(jié)構體Peo是關于個人信息的存儲,第二個結(jié)構體構建了 我們需要的通訊錄,con來作為以第一個結(jié)構體為類型的數(shù)組,sz來記錄這個結(jié)構體存儲個人信息的數(shù)量。
(3)實現(xiàn)菜單選項的功能
我們需要根據(jù)菜單里面的選項來選擇進行我們需要實現(xiàn)的功能,比如我們想假如一個用戶信息,我們就輸入1就會進行用戶假如的操作,我們想退出程序我們輸入0就可以退出。我選擇利用枚舉變量的形式來實現(xiàn),講操作變成數(shù)字,利用switch選擇語句來實現(xiàn)各自的功能。
enum Option//利用枚舉變量來定義 { exit,//0 add,//1 del,//2 search,//3 modify,//4 sort,//5 print//6 }; void test() { contact con;//建立結(jié)構體 InitCon(&con); int input = 0; do { menu(); scanf("%d", &input); switch (input) { case add: AddCon(&con); break; case del: DelCon(&con); break; case search: SearchCon(&con); break; case modify: ModifyCon(&con); break; case sort: SortCon(&con); break; case print: PrintCon(&con); break; case exit: printf("退出程序,歡迎使用!\n"); break; default: printf("沒有找到此數(shù)字匹配的操作!!\n"); } } while (input); }
(4)關于全局變量的定義
為了實現(xiàn)這些變量,并且方便后期的處理數(shù)組大小,所以我們可以利用宏來實現(xiàn)這個功能
#define NAME_MAX 20//姓名的長度 #define SEX_MAX 5//性別的長度 #define TELE_MAX 12//電話號碼的長度 #define ADDR_MAX 30//地址長度 #define PON_MAX 1000//通訊錄的大小
2、通訊錄的功能實現(xiàn)
(1)初始化通訊錄
剛剛開始我們創(chuàng)建了通訊錄的結(jié)構體,但是我們不難發(fā)現(xiàn),因為沒有定義的原因,他們里面存的都是隨機數(shù),因此我們需要對他們進行初始化防止后面的失誤。初始化很簡單就是把我們通訊錄結(jié)構體里面的用戶信息的結(jié)構體類型的數(shù)組進行初始化,這里我們可以淺淺用一個memset函數(shù)來實現(xiàn),當然別忘了引用string的頭文件,然后sz的初始化很簡單就是初始化為0。
void InitCon(contact* pc) { assert(pc); pc->sz = 0; memset(pc->con, 0, sizeof(pc->con)); }//初始化結(jié)構體
(2)增加聯(lián)系人
首先第一步我們完成第一步就可以創(chuàng)建關于加入聯(lián)系人的函數(shù),這個很簡單我們只需要訪問通訊錄結(jié)構體里面的數(shù)組中的每個元素然后輸入對應值就可以了
void AddCon(contact* pc) { assert(pc); if (pc->sz == PON_MAX) { printf("通訊錄滿了?。n"); } printf("請輸入姓名:>\n"); scanf("%s", pc->con[pc->sz].name); printf("請輸入性別:>\n"); scanf("%s", pc->con[pc->sz].sex); printf("請輸入年齡:>\n"); scanf("%d", &(pc->con[pc->sz].age));//注意年齡在這里是一個int類型 printf("請輸入電話號碼:>\n"); scanf("%s", pc->con[pc->sz].tele); printf("請輸入地址:>\n"); scanf("%s", pc->con[pc->sz].addr); pc->sz++; printf("此用戶添加成功!\n"); }
(3)打印通訊錄
打印通訊錄也很簡單,利用一個for循環(huán)根據(jù)sz的大小遍歷結(jié)構體中的數(shù)組每個元素并且打印即可
void PrintCon(const contact* pc) { assert(pc); printf("%-15s %-5s %-5s %-12s %-30s\n","姓名","性別","年齡","電話","地址"); for (int i = 0; i < pc->sz; i++) { printf("%-15s %-5s %-5d %-12s %-30s\n", pc->con[i].name, pc->con[i].sex, pc->con[i].age, pc->con[i].tele, pc->con[i].addr); } }
(4)查找聯(lián)系人
查找聯(lián)系人這邊我們需要構建一個函數(shù),這個函數(shù)需要去根據(jù)我們想要尋找的姓名去在通訊錄中尋找這個人所對應的位置,加入找到了就可以返回對應位置的下標,否則返回-1。找到之后就和打印通訊錄的操作差不多打印出來就好了。
int FindByName(const contact* pc, char* name) { assert(pc && name); for (int i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->con[i].name, name)) return i; } return -1; }//尋找或者刪除聯(lián)系人的下標 void SearchCon(const contact* pc) { assert(pc); char name[NAME_MAX]; printf("請輸入需要尋找用戶的名字:>\n"); scanf("%s", name); int pos = FindByName(pc, name);//pos為要尋找的人的下標 if (pos == -1) { printf("查無此人\n"); } else { printf("%-15s %-5s %-5s %-12s %-30s\n", "姓名", "性別", "年齡", "電話", "地址"); printf("%-15s %-5s %-5d %-12s %-30s\n", pc->con[pos].name, pc->con[pos].sex, pc->con[pos].age, pc->con[pos].tele, pc->con[pos].addr); } }
(5)修改聯(lián)系人
關于修改聯(lián)系人這個內(nèi)容,大多數(shù)的代碼都是直接替換所有的內(nèi)容,這樣也會讓一些本來就不用修改的信息又被修改了一遍,很麻煩,所有我的設計是,先讓用戶查找到需要修改的這個人然后選擇是修改什么信息,然后重新輸入嘞一部分的信息,這個其實就和菜單選項實現(xiàn)很相似,我們需要利用枚舉變量,并且利用do...while語句來讓他一直循環(huán)直到輸入0為止,利用switch來根據(jù)用戶的選項來跳到需要的操作。
enum Con { ERRO, NAME, SEX, AGE, TELE, ADDR }; void ModifyCon(contact* pc) { assert(pc); char name[NAME_MAX]; printf("請輸入需要修改信息用戶的名字:>\n"); scanf("%s", name); int pos = FindByName(pc, name);//pos為要尋找的人的下標 if (pos == -1) { printf("查無此人\n"); } else { int num = 0; do { printf("請輸入你想修改此用戶的信息\n"); printf(" 0.退出 1.姓名 2.性別 3.年齡 4.電話 5.地址:>\n"); scanf("%d", &num); switch (num) { case NAME: printf("請輸入你想修改的姓名:>\n"); scanf("%s", pc->con[pos].name); break; case SEX: printf("請輸入你想修改的性別:>\n"); scanf("%s", pc->con[pos].sex); break; case AGE: printf("請輸入你想修改的年齡:>\n"); scanf("%d", &(pc->con[pos].age)); break; case TELE: printf("請輸入你想修改的電話:>\n"); scanf("%s", pc->con[pos].tele); break; case ADDR: printf("請輸入你想修改的地址:>\n"); scanf("%s", pc->con[pos].addr); break; case 0: printf("不修改退回界面\n"); break; default:printf("無效操作數(shù)!\n"); } } while (num); } }
(6)刪除聯(lián)系人
這個操作也不算復雜,我的思路是,首先我們先利用剛剛查找的嘞個查找下標的函數(shù),查找到我們需要尋找刪除聯(lián)系人的坐標,然后對他進行刪除,刪除之后呢我們需要把后面的元素往前移動,這就要利用for循環(huán),但是對于for循環(huán)的次數(shù)要多加注意,因為稍不小心就會導致數(shù)組越界。
void DelCon(contact* pc) { assert(pc); char name[NAME_MAX]; printf("請輸入需要刪除用戶的名字:>\n"); scanf("%s", name); int pos = FindByName(pc, name);//pos為要尋找的人的下標 if (pos == -1) { printf("查無此人\n"); } else { for (int i = pos; i < pc->sz - 1; i++) { pc->con[i] = pc->con[i + 1]; } pc->sz--; printf("刪除成功!\n"); } }
(7)排序通訊錄
這一步我們需要按照人名首字母的大小對于通訊錄進行排序,就比如summer和banni,banni會在summer,這個排序其實和冒泡排序差不多,我們需要注意的是我們在交換兩個數(shù)的時候我們需要定義的的嘞個中間數(shù)為聯(lián)系人結(jié)構體類型,以免出錯
void SortCon(contact* pc) { if (pc->sz == 0) { printf("通訊錄中沒有聯(lián)系人\n"); } else { for (int i = 0; i < pc->sz - 1; i++) { for (int j = 0; j < pc->sz - 1 - i; j++) { if ((strcmp(pc->con[j].name, pc->con[j + 1].name)) > 0) { Peo temp = pc->con[j]; pc->con[j] = pc->con[j + 1]; pc->con[j + 1] = temp; } } } printf("排序成功!\n"); } }
這樣我們需要的一個通訊錄就這樣實現(xiàn)了!
三、關于通訊錄的優(yōu)化
這個通訊錄我們不難發(fā)現(xiàn)他有一個致命的缺點,就是我們初始化的通訊錄大小為1000,但是當我們存滿還想存元素的時候,編譯器就會給我們報錯,我們就需要繼續(xù)手動增加空間,所以為了避免這樣我們可以利用動態(tài)內(nèi)存分配來定義我們的通訊錄結(jié)構體。
1、通訊錄結(jié)構體的改進
這邊我們可以把之前的結(jié)構體里面的數(shù)組變成一個指針數(shù)組,并且為了考慮這個通訊錄來回刪除增加的緣故,一個sz來記錄數(shù)組元素個數(shù)是不行的,我們需要在設定一個值為數(shù)組最大的空間,當sz和他相等的時候我們就需要擴充這個數(shù)組。
typedef struct Contact { Peo* con; int sz;//記錄數(shù)量 int max;//記錄通訊錄當前的最大容量 }contact;
2、初始化結(jié)構體
這個初始化結(jié)構體,我們需要sz初始化為0,并且為con這個指針開辟一塊空間,并且賦予max一個初始值,這個初始值我們可以用宏來定義我們初始化通訊錄的大小
#define CON_MAX 3//通訊錄初始化大小 void InitCon(contact* pc) { assert(pc); pc->sz = 0; pc->max = CON_MAX; pc->con = (Peo*)malloc(sizeof(Peo) * pc->max); if (pc->con == NULL) { perror("InitContact::malloc"); return; } memset(pc->con, 0, pc->max * sizeof(Peo)); }
3.增容
當我們增加聯(lián)系人是sz == max的時候,我們可以利用realloc函數(shù)來實現(xiàn)擴容,每一次擴容兩個空間
void CheckCapacity(contact* pc) { //增容的代碼 if (pc->sz == pc->max) { Peo* tmp = (Peo*)realloc(pc->sz, (pc->max + 2) * sizeof(Peo)); if (tmp != NULL) { pc->sz = tmp; } else { perror("CheckCapacity::realloc"); return; } pc->max += 2; printf("增容成功\n"); } }
4.釋放內(nèi)存
這邊我們可以構建一個函數(shù)在這個程序結(jié)束之后釋放內(nèi)存
void DestroyContact(contact* pc) { free(pc->con); pc->con = NULL; pc->max = 0; pc->sz = 0; printf("銷毀成功\n"); }
四、總結(jié)
這個通訊錄主要考察的是對于結(jié)構體的訪問,還有對于結(jié)構體的創(chuàng)建,在編碼的時候得務必細心,最后放上完整的源代碼供大家參考
#pragma once #include <string.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> //類型的聲明 #define MAX 1000 #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 //通訊錄初始狀態(tài)的容量大小 #define DEFAULT_SZ 3 enum Option { EXIT,//0 ADD, DEL, SEARCH, MODIFY, SORT, PRINT }; enum Con { ERRO, NAME, SEX, AGE, TELE, ADDR }; typedef struct PeoInfo { char name[NAME_MAX]; char sex[SEX_MAX]; int age; char tele[TELE_MAX]; char addr[ADDR_MAX]; } PeoInfo; typedef struct Contact { PeoInfo* data;//可以存放1000個人的信息 int sz;//記錄通訊中已經(jīng)保存的信息個數(shù) int capacity;//記錄通訊錄當前的最大容量 }Contact; //函數(shù)的聲明 //初始化通訊錄 void InitContact(Contact* pc); //銷毀通訊錄 void DestroyContact(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); //保存通訊錄的信息到文件 void SaveContact(const Contact* pc); //通訊錄排序 void SortCon(Contact* pc); void ModifyCon(Contact* pc); #define _CRT_SECURE_NO_WARNINGS 1 //動態(tài)的版本 //void InitContact(Contact* pc) //{ // assert(pc); // pc->sz = 0; // pc->capacity = DEFAULT_SZ; // pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo)); // // if (pc->data == NULL) // { // perror("InitContact::malloc"); // return; // } // memset(pc->data, 0, pc->capacity * sizeof(PeoInfo)); //} void CheckCapacity(Contact* pc) { //增容的代碼 if (pc->sz == pc->capacity) { PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo)); if (tmp != NULL) { pc->data = tmp; } else { perror("CheckCapacity::realloc"); return; } pc->capacity += 2; printf("增容成功\n"); } } void LoadContact(Contact* pc) { //打開文件 FILE* pf = fopen("contact.dat", "rb"); if (pf == NULL) { perror("LoadContact::fopen"); return; } //讀文件 PeoInfo tmp = { 0 }; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { CheckCapacity(pc); pc->data[pc->sz] = tmp; pc->sz++; } //關閉文件 fclose(pf); pf = NULL; } //初始化通訊錄 - 文件版本 void InitContact(Contact* pc) { assert(pc); pc->sz = 0; pc->capacity = DEFAULT_SZ; pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo)); if (pc->data == NULL) { perror("InitContact::malloc"); return; } memset(pc->data, 0, pc->capacity * sizeof(PeoInfo)); //加載文件信息到通訊錄中 LoadContact(pc); } void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; printf("銷毀成功\n"); } void AddContact(Contact* pc) { assert(pc); //靜態(tài)版本 //if (pc->sz == MAX) //{ // printf("通訊錄已滿,無法添加\n"); // return; //} //動態(tài)的版本 CheckCapacity(pc); //錄入信息 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("添加成功\n"); } void PrintContact(const Contact* pc) { assert(pc); int i = 0; printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址"); for (i = 0; i < pc->sz; i++) { printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } //找到了返回下標 //找不到返回-1 int FindByName(const Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i; } } return -1; } void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通訊錄已空,無法刪除\n"); return; } //刪除 //1. 找到 char name[NAME_MAX] = { 0 }; printf("請輸入要刪除人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要刪除的人不存在\n"); return; } //2. 刪除 int j = 0; for (j = pos; j < pc->sz - 1; j++) { pc->data[j] = pc->data[j + 1]; } pc->sz--; printf("刪除成功\n"); } void SearchContact(const Contact* pc) { char name[NAME_MAX] = { 0 }; printf("請輸入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址"); printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } void SaveContact(const Contact* pc) { FILE* pf = fopen("contact.dat", "wb"); //回來本地建立一個contact.dat的記事本 if (pf == NULL) { perror("SaveContact::fopen"); return; } //寫文件 int i = 0; for (i = 0; i < pc->sz; i++) { fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); } //關閉文件 fclose(pf); pf = NULL; } void SortCon(Contact* pc) { if (pc->sz == 0) { printf("通訊錄中沒有聯(lián)系人\n"); } else { for (int i = 0; i < pc->sz - 1; i++) { for (int j = 0; j < pc->sz - 1 - i; j++) { if ((strcmp(pc->data[j].name, pc->data[j + 1].name)) > 0) { PeoInfo temp = pc->data[j]; pc->data[j] = pc->data[j + 1]; pc->data[j + 1] = temp; } } } printf("排序成功!\n"); } } void ModifyCon(Contact* pc) { assert(pc); char name[NAME_MAX]; printf("請輸入需要修改信息用戶的名字:>\n"); scanf("%s", name); int pos = FindByName(pc, name);//pos為要尋找的人的下標 if (pos == -1) { printf("查無此人\n"); } else { int num = 0; do { printf("請輸入你想修改此用戶的信息\n"); printf(" 0.退出 1.姓名 2.性別 3.年齡 4.電話 5.地址:>\n"); scanf("%d", &num); switch (num) { case NAME: printf("請輸入你想修改的姓名:>\n"); scanf("%s", pc->data[pos].name); break; case SEX: printf("請輸入你想修改的性別:>\n"); scanf("%s", pc->data[pos].sex); break; case AGE: printf("請輸入你想修改的年齡:>\n"); scanf("%d", &(pc->data[pos].age)); break; case TELE: printf("請輸入你想修改的電話:>\n"); scanf("%s", pc->data[pos].tele); break; case ADDR: printf("請輸入你想修改的地址:>\n"); scanf("%s", pc->data[pos].addr); break; case 0: printf("不修改退回界面\n"); break; default:printf("無效操作數(shù)!\n"); } } while (num); } } void menu() { printf("*****************************************\n"); printf("**** 1.增加聯(lián)系人 2.刪除聯(lián)系人 ****\n"); printf("**** 3.查找聯(lián)系人 4.修改聯(lián)系人 ****\n"); printf("**** 5.通訊錄排序 6.打印通訊錄 ****\n"); printf("**** 0.退出 ****\n"); printf("******************************************\n"); } void test() { int input = 0; Contact con; InitContact(&con); do { menu(); printf("請輸入你的選擇:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL: DelContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: ModifyCon(&con); break; case SORT: SortCon(&con); break; case PRINT: PrintContact(&con); break; case EXIT: SaveContact(&con); DestroyContact(&con); printf("感謝使用\n"); break; default: printf("非法輸入\n"); break; } } while (input); } int main() { test(); return 0; }
感謝閱讀!?。?!
到此這篇關于c語言實現(xiàn)通訊錄管理系統(tǒng)的文章就介紹到這了,更多相關c語言通訊錄管理系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!