C語言實(shí)現(xiàn)一個(gè)文件版動(dòng)態(tài)通訊錄流程詳解
通訊錄思維導(dǎo)圖
?
一、Contact.h
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 11
#define ADDR_MAX 30
#define INIT_CAPA 3
#define INC_CAPA 2
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele[TELE_MAX];
char addr[ADDR_MAX];
}PeoInfo;
//動(dòng)態(tài)版本
typedef struct Contact
{
PeoInfo* data;
int sz;//表示通訊錄有多少個(gè)聯(lián)系人
int capacity;//表示通訊錄的最大容量
}Contact;
//初始化通訊錄
void InitContact(Contact* pc);
//添加聯(lián)系人
void AddContact(Contact* pc);
//刪除聯(lián)系人
void DelContact(Contact* pc);
//顯示通訊錄
void ShowContact(const Contact* pc);
//查找聯(lián)系人
void SearchContact(Contact*pc);
//修改聯(lián)系人'
void ModifyContact(Contact*pc);
//通過名字排序聯(lián)系人
void ByNameSortContact(Contact* pc);
//銷毀聯(lián)系人
void DestroyContact(Contact* pc);
//保存聯(lián)系人到文本文件中
void SaveContact(Contact* pc);
//從文件中讀取聯(lián)系人的信息
void GetContact(Contact* pc);這些是頭文件的包含,函數(shù)的聲明,以及#define定義的常量,為了以后修改方便
二、Contact.c
1.初始化通訊錄
void InitContact(Contact* pc)//初始化通訊錄
{
assert(pc!=NULL);
pc-> sz = 0;
pc->capacity = INIT_CAPA;
PeoInfo * ptr = (PeoInfo*)calloc(INIT_CAPA, sizeof(PeoInfo));
if (ptr == NULL)
{
perror("InitContact");
return;
}
pc->data = ptr;
GetContact(pc);
}初始化通訊錄的容量開始為3,sz初始時(shí)為0,動(dòng)態(tài)開辟的ptr開辟成功在賦給data。
2.檢查容量是否滿
void check_capacity(Contact* pc)//檢查容量是否滿
{
assert(pc);
if (pc->capacity == pc->sz)
{
PeoInfo*ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("check_capacity");
return;
}
pc->data = ptr;
pc->capacity += INC_CAPA;
printf("增容成功\n");
}
}如果容量滿,則每次增容兩個(gè),如果想要增容更多,則修改define定義的常量就可以修改了。
realloc開辟的時(shí)候有可能是用pc->data來往后擴(kuò)大增容,也有可能是用新的空間來開辟,為了防止開辟失敗,使原有的數(shù)據(jù)丟失,則先使用新的指針變量來接收動(dòng)態(tài)開辟的空間,如果開辟成功,再將它賦給data。
3.添加聯(lián)系人
void AddContact(Contact* pc)//添加聯(lián)系人
{
assert(pc != NULL);
check_capacity(pc);
printf("請(qǐng)輸入姓名:\n");
scanf("%s", pc->data[pc->sz].name);
printf("請(qǐng)輸入年齡:\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("請(qǐng)輸入性別:\n");
scanf("%s", pc->data[pc->sz].sex);
printf("請(qǐng)輸入號(hào)碼:\n");
scanf("%s", pc->data[pc->sz].tele);
printf("請(qǐng)輸入地址:\n");
scanf("%s", pc->data[pc->sz].addr);
printf("添加聯(lián)系人成功\n");
pc->sz++;
}添加聯(lián)系人前,需要先判斷是否需要增容
4.顯示聯(lián)系人
void ShowContact(const Contact* pc)//顯示聯(lián)系人
{
assert(pc != NULL);
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n","姓名","年齡","性別","電話號(hào)碼","地址");
for (int i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-4s\t%-12s\t%-30s\n", pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tele,
pc->data[i].addr);
}
}5.查找聯(lián)系人
int ByNameFind(Contact* pc, char name[])//通過名字查找聯(lián)系人
{
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void SearchContact(Contact* pc)//查找聯(lián)系人
{
assert(pc);
char name[NAME_MAX];
printf("請(qǐng)輸入要查找的聯(lián)系人\n");
scanf("%s", name);
int ret = ByNameFind(pc, name);
if (ret == -1)
{
printf("查無此人\n");
return;
}
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n", "姓名", "年齡", "性別", "電話號(hào)碼", "地址");
printf("%-20s\t%-4d\t%-4s\t%-12s\t%-30s\n", pc->data[ret].name,
pc->data[ret].age,
pc->data[ret].sex,
pc->data[ret].tele,
pc->data[ret].addr);
}注意:名字屬于字符串,名字的比較需要用strcmp來比較,如果返回-1,則是沒有找到聯(lián)系人,如果找到了,則就打印這個(gè)聯(lián)系人的信息出來
6.修改聯(lián)系人
void ModifyContact(Contact* pc)//修改聯(lián)系人
{
assert(pc);
char name[NAME_MAX];
printf("請(qǐng)輸入要修改的聯(lián)系人姓名\n");
scanf("%s", name);
int pos = ByNameFind(pc, name);
if (pos == -1)
{
printf("找不到該聯(lián)系人\n");
return;
}
printf("請(qǐng)輸入姓名:\n");
scanf("%s", pc->data[pos].name);
printf("請(qǐng)輸入年齡:\n");
scanf("%d", &(pc->data[pos].age));
printf("請(qǐng)輸入性別:\n");
scanf("%s", pc->data[pos].sex);
printf("請(qǐng)輸入號(hào)碼:\n");
scanf("%s", pc->data[pos].tele);
printf("請(qǐng)輸入地址:\n");
scanf("%s", pc->data[pos].addr);
printf("修改聯(lián)系人成功\n");
}注意:想要修改這個(gè)聯(lián)系人,也需要通訊錄中有這個(gè)聯(lián)系人,所以要先查找到這個(gè)聯(lián)系人,所以調(diào)用封裝好的通過名字查找聯(lián)系人這個(gè)函數(shù)就可以了,如果返回-1,則就是沒有該聯(lián)系人,無法修改,如果找到了,則才能夠修改此聯(lián)系人的信息。
7.通過名字來排序聯(lián)系人
void ByNameSortContact(Contact* pc)//通過名字來排序
{
assert(pc);
if (pc->sz == 0)
{
printf("無聯(lián)系人,無法排序\n");
return;
}
PeoInfo temp;
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)
{
temp = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = temp;
}
}
}
printf("排序成功\n");
}注意:這里通過名字來排序聯(lián)系人,也是需要用到strcmp這個(gè)庫(kù)函數(shù)的,strcmp是一個(gè)字符來比較的,如果有一個(gè)字符大的話就要進(jìn)行交換,利用的是冒泡排序思想來排序聯(lián)系人的
8.保存聯(lián)系人到文本文件中
void SaveContact(Contact* pc)
{
assert(pc);
FILE* pf = fopen("Contact.txt", "wb");
if (pf == NULL)
{
perror("fopen");
}
else
{
for (int i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
printf("保存數(shù)據(jù)成功\n");
}
}
?
注意:FILE是C語言標(biāo)準(zhǔn)的指針,wb是用二進(jìn)制的方式寫入文本文件中,而fwrite的用法我們可以利用cplusplus來查找它的用法,里面介紹了它的每個(gè)參數(shù)的用法,第一個(gè)參數(shù)ptr其實(shí)就是傳我們的data的指針進(jìn)去,第二個(gè)參數(shù)本質(zhì)就是求大小的,求得是PeoInfo得大小,第三個(gè)參數(shù)就是每次添加幾個(gè)聯(lián)系人,每次添加1個(gè)。第四個(gè)參數(shù)是把文件流放入
9.從文件中讀取聯(lián)系人的信息
//從文件中初始化聯(lián)系人
void GetContact(Contact* pc)
{
assert(pc);
FILE* pf = fopen("Contact.txt", "rb");
if (pf == NULL)
{
perror("GetContact::fopen");
}
else
{
PeoInfo ptr = { 0 };
int i = 0;
while (fread(&ptr, sizeof(PeoInfo), 1, pf))
{
check_capacity(pc);
pc->data[i] = ptr;
i++;
pc->sz++;
}
fclose(pf);
pf = NULL;
}
}
?
注意:rb是利用二進(jìn)制來讀取聯(lián)系人的,fread的用法如上圖所示。
10.銷毀聯(lián)系人
//銷毀聯(lián)系人
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}注意:在我們退出通訊錄時(shí),要將它進(jìn)行銷毀
三、text.c
#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");
}
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
int main()
{
Contact con;
InitContact(&con);
int input = 0;
do
{
menu();
printf("請(qǐng)輸入數(shù)字:\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL :
DelContact(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
ByNameSortContact(&con);
break;
case EXIT:
SaveContact(&con);
DestroyContact(&con);
printf("退出程序\n");
break;
default:
printf("輸入錯(cuò)誤,請(qǐng)重新輸入\n");
break;
}
} while (input);
return 0;注意:首先要建立菜單,然后用枚舉來定義case后面,這樣為了可以讓我們看代碼更清晰,在運(yùn)行程序時(shí)要將聯(lián)系人從文件中讀取出來,在退出文件時(shí),要把聯(lián)系人保存到文本文件中去,在進(jìn)行銷毀。
好了,小編的分享到這里就結(jié)束了,如果有什么不足的地方請(qǐng)大佬多多指教!?。?/p>
到此這篇關(guān)于C語言實(shí)現(xiàn)一個(gè)文件版動(dòng)態(tài)通訊錄流程詳解的文章就介紹到這了,更多相關(guān)C語言動(dòng)態(tài)通訊錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于C語言中弱符號(hào)與弱引用的實(shí)際應(yīng)用問題
在編碼過程中,我們經(jīng)常遇到符號(hào)重定義的錯(cuò)誤問題,本文通過實(shí)例代碼展示給大家介紹了C語言弱符號(hào)與弱引用的實(shí)際應(yīng)用問題,一起看看吧2021-09-09
用32位int型變量表示單引號(hào)括起來的四個(gè)字符的深入探討
本篇文章是對(duì)用32位int型變量表示單引號(hào)括起來的四個(gè)字符進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C++基于boost asio實(shí)現(xiàn)sync tcp server通信流程詳解
這篇文章主要介紹了C++基于boost asio實(shí)現(xiàn)sync tcp server通信的流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量
這篇文章主要為大家詳細(xì)介紹了C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06

