C語言實現一個文件版動態通訊錄流程詳解

通訊錄思維導圖

一、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;
//動態版本
typedef struct Contact
{
	PeoInfo* data;
	int sz;//表示通訊錄有多少個聯系人
	int capacity;//表示通訊錄的最大容量
}Contact;
//初始化通訊錄
void InitContact(Contact* pc);
//添加聯系人
void AddContact(Contact* pc);
//刪除聯系人
void DelContact(Contact* pc);
//顯示通訊錄
void ShowContact(const Contact* pc);
//查找聯系人
void SearchContact(Contact*pc);
//修改聯系人'
void ModifyContact(Contact*pc);
//通過名字排序聯系人
void ByNameSortContact(Contact* pc);
//銷毀聯系人
void DestroyContact(Contact* pc);
//保存聯系人到文本文件中
void SaveContact(Contact* pc);
//從文件中讀取聯系人的信息
void GetContact(Contact* pc);

這些是頭文件的包含,函數的聲明,以及#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初始時為0,動態開辟的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");
	}
}

如果容量滿,則每次增容兩個,如果想要增容更多,則修改define定義的常量就可以修改瞭。

realloc開辟的時候有可能是用pc->data來往後擴大增容,也有可能是用新的空間來開辟,為瞭防止開辟失敗,使原有的數據丟失,則先使用新的指針變量來接收動態開辟的空間,如果開辟成功,再將它賦給data。

3.添加聯系人

void AddContact(Contact* pc)//添加聯系人
{
	assert(pc != NULL);
	check_capacity(pc);
	printf("請輸入姓名:\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("請輸入年齡:\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("請輸入性別:\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("請輸入號碼:\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("請輸入地址:\n");
	scanf("%s", pc->data[pc->sz].addr);
	printf("添加聯系人成功\n");
	pc->sz++;
}

添加聯系人前,需要先判斷是否需要增容

4.顯示聯系人

void ShowContact(const Contact* pc)//顯示聯系人
{
	assert(pc != NULL);
	printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n","姓名","年齡","性別","電話號碼","地址");
	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.查找聯系人

int ByNameFind(Contact* pc, char name[])//通過名字查找聯系人
{
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
void SearchContact(Contact* pc)//查找聯系人
{
	assert(pc);
	char name[NAME_MAX];
	printf("請輸入要查找的聯系人\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", "姓名", "年齡", "性別", "電話號碼", "地址");
	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,則是沒有找到聯系人,如果找到瞭,則就打印這個聯系人的信息出來

6.修改聯系人

void ModifyContact(Contact* pc)//修改聯系人
{
	assert(pc);
	char name[NAME_MAX];
	printf("請輸入要修改的聯系人姓名\n");
	scanf("%s", name);
	int pos = ByNameFind(pc, name);
	if (pos == -1)
	{
		printf("找不到該聯系人\n");
		return;
	}
	printf("請輸入姓名:\n");
	scanf("%s", pc->data[pos].name);
	printf("請輸入年齡:\n");
	scanf("%d", &(pc->data[pos].age));
	printf("請輸入性別:\n");
	scanf("%s", pc->data[pos].sex);
	printf("請輸入號碼:\n");
	scanf("%s", pc->data[pos].tele);
	printf("請輸入地址:\n");
	scanf("%s", pc->data[pos].addr);
	printf("修改聯系人成功\n");
}

註意:想要修改這個聯系人,也需要通訊錄中有這個聯系人,所以要先查找到這個聯系人,所以調用封裝好的通過名字查找聯系人這個函數就可以瞭,如果返回-1,則就是沒有該聯系人,無法修改,如果找到瞭,則才能夠修改此聯系人的信息。

7.通過名字來排序聯系人

void ByNameSortContact(Contact* pc)//通過名字來排序
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("無聯系人,無法排序\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");
}

註意:這裡通過名字來排序聯系人,也是需要用到strcmp這個庫函數的,strcmp是一個字符來比較的,如果有一個字符大的話就要進行交換,利用的是冒泡排序思想來排序聯系人的

8.保存聯系人到文本文件中

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("保存數據成功\n");
	}
}

註意:FILE是C語言標準的指針,wb是用二進制的方式寫入文本文件中,而fwrite的用法我們可以利用cplusplus來查找它的用法,裡面介紹瞭它的每個參數的用法,第一個參數ptr其實就是傳我們的data的指針進去,第二個參數本質就是求大小的,求得是PeoInfo得大小,第三個參數就是每次添加幾個聯系人,每次添加1個。第四個參數是把文件流放入

9.從文件中讀取聯系人的信息

//從文件中初始化聯系人
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是利用二進制來讀取聯系人的,fread的用法如上圖所示。

10.銷毀聯系人

//銷毀聯系人
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

註意:在我們退出通訊錄時,要將它進行銷毀

三、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("請輸入數字:\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("輸入錯誤,請重新輸入\n");
			break;
		}
	} while (input);
	return 0;

註意:首先要建立菜單,然後用枚舉來定義case後面,這樣為瞭可以讓我們看代碼更清晰,在運行程序時要將聯系人從文件中讀取出來,在退出文件時,要把聯系人保存到文本文件中去,在進行銷毀。

好瞭,小編的分享到這裡就結束瞭,如果有什麼不足的地方請大佬多多指教!!!

到此這篇關於C語言實現一個文件版動態通訊錄流程詳解的文章就介紹到這瞭,更多相關C語言動態通訊錄內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: