溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于C語(yǔ)言怎么打造高效通訊錄

發(fā)布時(shí)間:2023-05-05 10:22:47 來(lái)源:億速云 閱讀:79 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“基于C語(yǔ)言怎么打造高效通訊錄”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“基于C語(yǔ)言怎么打造高效通訊錄”吧!

先來(lái)梳理下需求:

1.通訊錄能夠存儲(chǔ)的聯(lián)系人的信息有:姓名、年齡、性別、電話、住址。

2.這個(gè)通訊錄不能是“靜態(tài)的”,而應(yīng)該是“動(dòng)態(tài)的”,也就是說(shuō),需要用到動(dòng)態(tài)內(nèi)存管理的知識(shí)。這是因?yàn)椋o態(tài)的通訊錄的容量是固定的,空間太大可能浪費(fèi),太小了又不夠存。

3.由于當(dāng)程序開始運(yùn)行后,通訊錄的數(shù)據(jù)是存儲(chǔ)在內(nèi)存中的,一旦程序運(yùn)行結(jié)束,執(zhí)行完main函數(shù)的return 0;后,空間就被操作系統(tǒng)回收了,相當(dāng)于數(shù)據(jù)就丟了。為了能夠?qū)崿F(xiàn)“永久保存”的效果,我們要在程序退出前,把數(shù)據(jù)保存到文件中,這又涉及到文件操作的相關(guān)知識(shí)點(diǎn)。

4.類似順序表這種數(shù)據(jù)結(jié)構(gòu)的基本操作,通訊錄要能做到:增刪查改+排序+打印,即增加聯(lián)系人、刪除聯(lián)系人、查找聯(lián)系人、修改聯(lián)系人、排序聯(lián)系人、打印聯(lián)系人等等。

準(zhǔn)備工作

以下是菜單里的一些選項(xiàng),聲明成枚舉類型是比較合適的。

// 菜單里的不同選項(xiàng)
enum Option
{
    EXIT,   // 退出
    ADD,    // 增加聯(lián)系人
    DEL,    // 刪除聯(lián)系人
    SEARCH, // 查找聯(lián)系人
    MODIFY, // 修改聯(lián)系人
    SHOW,   // 顯示聯(lián)系人
    SORT    // 排序
};

由于聯(lián)系人的姓名、性別、電話和住址都是字符串,要存儲(chǔ)在字符數(shù)組中,最好先聲明它們的容量。

// 各信息的存儲(chǔ)容量
#define MAX_NAME 20 // 名字
#define MAX_SEX 5   // 性別
#define MAX_TELE 12 // 電話
#define MAX_ADDR 30 // 住址

我們后面在進(jìn)行動(dòng)態(tài)內(nèi)存管理時(shí),需要知道初始的容量和每次擴(kuò)容的容量,也聲明一下:

// 動(dòng)態(tài)內(nèi)存默認(rèn)存儲(chǔ)的數(shù)據(jù)
#define DEFAULT_SZ 3
// 若不夠存,每次擴(kuò)容的數(shù)量
#define INC_SZ 2

再聲明一個(gè)結(jié)構(gòu)體,表示一個(gè)人的信息,包括姓名、年齡、性別、電話、住址。

// 表示一個(gè)人的信息
typedef struct PeoInfo
{
    char name[MAX_NAME]; // 姓名
    int age;             // 年齡
    char sex[MAX_SEX];   // 性別
    char tele[MAX_TELE]; // 電話
    char addr[MAX_ADDR]; // 住址
}PeoInfo;

類似數(shù)據(jù)結(jié)構(gòu)中的“順序表”的結(jié)構(gòu),定義一個(gè)結(jié)構(gòu)體,用于存儲(chǔ)通訊錄中的信息,包括一個(gè)動(dòng)態(tài)開辟的數(shù)組,數(shù)組中有效數(shù)據(jù)的個(gè)數(shù),以及數(shù)組當(dāng)前動(dòng)態(tài)開辟的容量。

// 通訊錄
typedef struct Contact
{
    PeoInfo* data; // data指向了存放數(shù)據(jù)的空間
    int sz;        // 記錄通訊錄中的有效信息個(gè)數(shù)
    int capacity;  // 通訊錄當(dāng)前的容量
}Contact;

下面我們開始實(shí)現(xiàn)程序的主體邏輯。先從主函數(shù)寫起,把主要的功能都封裝成函數(shù):

// 打印菜單
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()
{
	int input = 0; // 存儲(chǔ)用戶輸入的數(shù)據(jù)
	Contact con; // 通訊錄
	// 初始化通訊錄
	// 加載文件的信息到通訊錄中
	InitContact(&con);
	do
	{
		menu(); // 菜單
		printf("請(qǐng)選擇:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD: // 添加聯(lián)系人
			AddContact(&con);
			break;
		case DEL: // 刪除聯(lián)系人
			DelContact(&con);
			break;
		case SEARCH: // 查找指定聯(lián)系人
			SearchContact(&con);
			break;
		case MODIFY: // 修改指定聯(lián)系人的信息
			ModifyContact(&con);
			break;
		case SHOW: // 展示聯(lián)系人信息
			ShowContact(&con);
			break;
		case SORT: // 排序
			SortContact(&con);
			break;
		case EXIT: // 退出通訊錄
			// 保存通訊錄到文件中
			SaveContact(&con);
			// 銷毀通訊錄
			DestroyConact(&con);
			printf("退出通訊錄\n");
			break;
		default:
			printf("選擇錯(cuò)誤\n");
			break;
		}
	} while (input);
	return 0;
}

初始化通訊錄

先定義一個(gè)函數(shù)InitContact,它的作用是初始化通訊錄。函數(shù)的參數(shù)是一個(gè)指向Contact結(jié)構(gòu)體的指針。函數(shù)的具體實(shí)現(xiàn)如下:

  • 函數(shù)的第一行使用assert宏檢查指針是否有效,如果無(wú)效則程序會(huì)中止運(yùn)行。

  • 接下來(lái),函數(shù)使用malloc函數(shù)開辟了一塊內(nèi)存空間,用于存儲(chǔ)PeoInfo結(jié)構(gòu)體數(shù)組。這個(gè)數(shù)組的大小是DEFAULT_SZ,即默認(rèn)容量。如果開辟空間失敗,則會(huì)輸出錯(cuò)誤信息并返回。

  • 如果開辟空間成功,則將通訊錄的大小sz和容量capacity都設(shè)置為DEFAULT_SZ,并調(diào)用LoadContact函數(shù)將文件中的信息加載到通訊錄中。

void InitContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 先開辟默認(rèn)的容量
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	// 檢查開辟空間是否成功
	if (pc->data == NULL)
	{
		// 開辟空間失敗
		printf("通訊錄初始化失敗:%s\n", strerror(errno));
		return;
	}
	// 開辟空間成功
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	//加載文件的信息到通訊錄
	LoadContact(pc);
}

從文件中加載信息

再定義一個(gè)函數(shù)LoadContact,用于從文件中讀取聯(lián)系人信息并存儲(chǔ)到內(nèi)存中。函數(shù)的參數(shù)是一個(gè)指向Contact結(jié)構(gòu)體的指針,表示要將讀取到的聯(lián)系人信息存儲(chǔ)到哪個(gè)數(shù)據(jù)結(jié)構(gòu)中。函數(shù)的具體實(shí)現(xiàn)如下:

  • 首先使用assert函數(shù)檢查傳入的指針是否有效,如果無(wú)效則直接返回。

  • 然后使用fopen函數(shù)打開名為"contact.dat"的二進(jìn)制文件,如果打開失敗則說(shuō)明可能是第一次運(yùn)行通訊錄,沒有數(shù)據(jù)文件,直接返回。

  • 接著使用一個(gè)while循環(huán),每次讀取一個(gè)PeoInfo結(jié)構(gòu)體大小的數(shù)據(jù),即一個(gè)聯(lián)系人的信息,存儲(chǔ)到臨時(shí)變量tmp中。

  • 調(diào)用CheckCapacity函數(shù)檢查當(dāng)前動(dòng)態(tài)數(shù)組的容量是否足夠存儲(chǔ)讀取到的聯(lián)系人信息,如果不夠則進(jìn)行擴(kuò)容。

  • 將讀取到的聯(lián)系人信息存儲(chǔ)到動(dòng)態(tài)數(shù)組中,即將tmp變量中的數(shù)據(jù)存儲(chǔ)到data數(shù)組的末尾,并將sz變量加一。

  • 循環(huán)結(jié)束后,關(guān)閉文件并將文件指針置為 NULL。

void LoadContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 打開文件
	FILE* pf = fopen("contact.dat", "rb");
	// 檢查打開文件是否成功
	if (pf == NULL)
	{
		// 打開文件失敗,可能是第一次運(yùn)行通訊錄,并沒有數(shù)據(jù)文件
		//perror("LoadContact::fopen");
		return;
	}
	// 讀文件
	PeoInfo tmp = { 0 }; // 存儲(chǔ)讀取到的數(shù)據(jù)
	// 每次讀一個(gè)數(shù)據(jù)
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		// 檢查容量,不夠的話要擴(kuò)容
		CheckCapacity(pc);
		// 存儲(chǔ)從文件讀取到的數(shù)據(jù)
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	// 關(guān)閉文件
	fclose(pf);
	pf = NULL;
}

檢查容量

再定義一個(gè)函數(shù)CheckCapacity,用于檢查并擴(kuò)容動(dòng)態(tài)數(shù)組。函數(shù)的參數(shù)是一個(gè)指向Contact結(jié)構(gòu)體的指針。函數(shù)的具體實(shí)現(xiàn)如下:

  • 函數(shù)首先使用assert宏檢查傳入的指針是否有效。然后,它檢查當(dāng)前數(shù)組是否需要擴(kuò)容。如果數(shù)組的大小已經(jīng)等于容量,就需要擴(kuò)容。

  • 在需要擴(kuò)容的情況下,函數(shù)使用realloc函數(shù)重新分配內(nèi)存。realloc函數(shù)會(huì)嘗試將原來(lái)分配的內(nèi)存塊擴(kuò)大到指定的大小。如果擴(kuò)容成功,realloc函數(shù)會(huì)返回一個(gè)指向新內(nèi)存塊的指針,否則返回NULL。

  • 如果realloc函數(shù)返回NULL,說(shuō)明擴(kuò)容失敗,函數(shù)會(huì)輸出錯(cuò)誤信息并返回0。如果realloc函數(shù)返回非空指針,說(shuō)明擴(kuò)容成功,函數(shù)會(huì)更新數(shù)組的起始位置和容量,并輸出擴(kuò)容成功的信息。最后,函數(shù)返回1,表示擴(kuò)容成功或者不需要擴(kuò)容。

// 擴(kuò)容失敗,返回0
// 擴(kuò)容成功,不需要擴(kuò)容,返回1
static int CheckCapacity(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 檢查是否需要擴(kuò)容
	if (pc->sz == pc->capacity)
	{
		// 需要擴(kuò)容
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		// 檢查是否擴(kuò)容成功
		if (ptr == NULL)
		{
			// 擴(kuò)容失敗
			printf("CheckCapacity:%s\n", strerror(errno));
			return 0;
		}
		else
		{
			// 擴(kuò)容成功
			// 更新數(shù)組的起始位置
			pc->data = ptr;
			// 更新容量
			pc->capacity += INC_SZ;
			printf("增容成功,當(dāng)前容量:%d\n", pc->capacity);
		}
	}
	return 1;
}

銷毀通訊錄

再定義一個(gè)函數(shù)DestroyContact,用來(lái)銷毀通訊錄。函數(shù)的參數(shù)是一個(gè)指向Contact結(jié)構(gòu)體的指針。函數(shù)的具體實(shí)現(xiàn)如下:

  • 先使用assert宏檢查指針的有效性。

  • 釋放動(dòng)態(tài)數(shù)組占用的內(nèi)存空間。

  • 把結(jié)構(gòu)體的變量置空。

void DestroyConact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 釋放內(nèi)存空間
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("釋放內(nèi)存.....\n");
}

添加聯(lián)系人

接著定義一個(gè)函數(shù)AddContact,參數(shù)仍然是一個(gè)指向Contact結(jié)構(gòu)體的指針,實(shí)現(xiàn)向通訊錄中添加聯(lián)系人的功能。具體實(shí)現(xiàn)如下:

  • 首先檢查傳入的指針是否有效,如果無(wú)效則使用assert宏觸發(fā)斷言,程序終止。

  • 調(diào)用CheckCapacity函數(shù)檢查通訊錄是否需要擴(kuò)容,如果需要?jiǎng)t進(jìn)行擴(kuò)容操作。如果擴(kuò)容失敗,則輸出提示信息并返回。

  • 如果擴(kuò)容成功,則提示用戶輸入聯(lián)系人信息,包括名字、年齡、性別、電話和地址。這些信息將被存儲(chǔ)在通訊錄的data數(shù)組中,下標(biāo)為 sz。

  • 最后更新有效數(shù)據(jù)個(gè)數(shù)sz,并輸出添加成功的提示信息。

void AddContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 擴(kuò)容,同時(shí)檢查是否成功
	if (0 == CheckCapacity(pc))
	{
		// 擴(kuò)容失敗
		printf("空間不夠,擴(kuò)容失敗\n");
		return;
	}
	else
	{
		// 輸入聯(lián)系人信息
		printf("請(qǐng)輸入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("請(qǐng)輸入年齡:>");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("請(qǐng)輸入性別:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("請(qǐng)輸入電話:>");
		scanf("%s", pc->data[pc->sz].tele);
		printf("請(qǐng)輸入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		// 更新有效數(shù)據(jù)個(gè)數(shù)
		pc->sz++;
		printf("添加成功\n");
	}
}

打印數(shù)據(jù)

接下來(lái)定義一個(gè)函數(shù) ShowContact,用于打印聯(lián)系人信息。函數(shù)接受一個(gè)指向Contact結(jié)構(gòu)體的指針pc。具體實(shí)現(xiàn)如下:

  • 函數(shù)首先使用assert宏檢查指針pc是否有效,如果無(wú)效則程序會(huì)崩潰并輸出錯(cuò)誤信息。

  • 接下來(lái),函數(shù)使用printf函數(shù)打印聯(lián)系人信息。首先打印表頭,包括姓名、年齡、性別、電話和地址。然后使用循環(huán)遍歷pc中的每個(gè)聯(lián)系人,打印其姓名、年齡、性別、電話和地址。

  • 在打印時(shí)使用格式化字符串,其中 %s 表示字符串,%-10s 表示左對(duì)齊并占用 10 個(gè)字符的字符串,%-4d 表示左對(duì)齊并占用 4 個(gè)字符的整數(shù),%-5s 表示左對(duì)齊并占用 5 個(gè)字符的字符串,%-12s 表示左對(duì)齊并占用 12 個(gè)字符的字符串,%-30s 表示左對(duì)齊并占用 30 個(gè)字符的字符串。

void ShowContact(const Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 打印效果
	// 姓名      年齡      性別     電話      地址
	// zhangsan 20        男      123456    北京
	//
	// 打印標(biāo)題
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址");
	// 打印數(shù)據(jù)
	for (int i = 0; i < pc->sz; ++i)
	{
		printf("%-10s %-4d %-5s %-12s %-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

刪除聯(lián)系人

接下來(lái)實(shí)現(xiàn)通訊錄的刪除聯(lián)系人功能。具體實(shí)現(xiàn)如下:

FindByName函數(shù):根據(jù)指定名字,在通訊錄中查找聯(lián)系人信息。函數(shù)參數(shù)為指向Contact結(jié)構(gòu)體的指針和要查找的名字。函數(shù)返回值為查找到的聯(lián)系人在通訊錄中的下標(biāo),如果沒找到則返回-1。

DelContact函數(shù):刪除通訊錄中指定聯(lián)系人。函數(shù)參數(shù)為指向Contact結(jié)構(gòu)體的指針。函數(shù)實(shí)現(xiàn)如下:

  • 檢查指針有效性,如果為空則直接返回。

  • 檢查通訊錄中是否還有數(shù)據(jù),如果沒有則輸出提示信息并返回。

  • 獲取用戶輸入的要?jiǎng)h除的聯(lián)系人名字。

  • 調(diào)用FindByName函數(shù)查找要?jiǎng)h除的聯(lián)系人在通訊錄中的下標(biāo)。

  • 如果沒找到,則輸出提示信息并返回。

  • 如果找到了,則使用memmove函數(shù)將該聯(lián)系人后面的所有聯(lián)系人向前移動(dòng)一個(gè)位置,覆蓋掉要?jiǎng)h除的聯(lián)系人。

  • 更新通訊錄中的有效數(shù)據(jù)個(gè)數(shù)。

  • 輸出刪除成功的提示信息。

// 根據(jù)指定名字,查找聯(lián)系人信息
static int FindByName(const Contact* pc, char name[])
{
	// 檢查指針有效性
	assert(pc);
	assert(name);
	// 遍歷數(shù)組
	for (int i = 0; i < pc->sz; ++i)
	{
		// 檢查名字是否匹配
		if (0 == strcmp(pc->data[i].name, name))
		{
			// 找到了
			return i;
		}
	}
	// 沒找到
	return -1;
}
void DelContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 檢查是否還有數(shù)據(jù)
	if (pc->sz == 0)
	{
		// 通訊錄已空
		printf("通訊錄為空,無(wú)法刪除\n");
		return;
	}
	char name[MAX_NAME] = { 0 }; // 存儲(chǔ)用戶輸入的數(shù)據(jù)
	// 用戶輸入信息
	printf("輸入要?jiǎng)h除人的名字:>");
	scanf("%s", name);
	// 找到要?jiǎng)h除的人的下標(biāo)
	int pos = FindByName(pc, name);
	// 檢查是否找到
	if (pos == -1)
	{
		// 沒找到
		printf("要?jiǎng)h除的人不存在\n");
		return;
	}
	// 刪除pos位置上的數(shù)據(jù)
	// 挪動(dòng)pos后面的數(shù)據(jù),覆蓋pos
	memmove(pc->data + pos, pc->data + pos + 1, sizeof(PeoInfo) * (pc->sz - pos - 1));
	// 更新有效數(shù)據(jù)個(gè)數(shù)
	pc->sz--;
	printf("刪除成功\n");
}

查找聯(lián)系人

接著實(shí)現(xiàn)在通訊錄中根據(jù)姓名查找聯(lián)系人的功能。具體實(shí)現(xiàn)如下:

  • 函數(shù)名為SearchContact,接受一個(gè)指向Contact結(jié)構(gòu)體的指針pc作為參數(shù)。

  • 第一行代碼使用assert宏檢查指針pc是否有效,如果pc為 NULL,則程序會(huì)崩潰并輸出錯(cuò)誤信息。

  • 定義一個(gè)char類型的數(shù)組name,長(zhǎng)度為MAX_NAME,用于存儲(chǔ)用戶輸入的要查找的人的名字。

  • 使用printf函數(shù)輸出提示信息,讓用戶輸入要查找的人的名字。

  • 使用scanf函數(shù)讀取用戶輸入的名字,存儲(chǔ)到name數(shù)組中。

  • 調(diào)用FindByName函數(shù),在通訊錄中查找名字為name的聯(lián)系人,返回值為該聯(lián)系人在通訊錄中的位置,如果沒找到則返回-1。

  • 判斷FindByName函數(shù)的返回值,如果為-1,則說(shuō)明沒有找到要查找的聯(lián)系人,使用printf函數(shù)輸出提示信息,并直接返回。

  • 如果FindByName函數(shù)的返回值不為-1,則說(shuō)明找到了要查找的聯(lián)系人,使用printf函數(shù)輸出通訊錄的標(biāo)題行,包括姓名、年齡、性別、電話、地址等信息。

  • 使用printf函數(shù)輸出找到的聯(lián)系人的具體信息,包括姓名、年齡、性別、電話、地址等信息,這些信息都存儲(chǔ)在Contact結(jié)構(gòu)體中的data數(shù)組中,通過pc指針訪問。pos變量表示要查找的聯(lián)系人在data數(shù)組中的位置。注意,這里使用了%-10s、%-4d等格式控制符,表示輸出字符串時(shí)左對(duì)齊,并且占用固定的寬度,方便對(duì)齊。

void SearchContact(const Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	char name[MAX_NAME] = { 0 }; // 存儲(chǔ)用戶輸入的信息
	// 用戶輸入數(shù)據(jù)
	printf("請(qǐng)輸入要查找人的名字:>");
	scanf("%s", name);
	// 查找
	int pos = FindByName(pc, name);
	// 檢查是否找到
	if (pos == -1)
	{
		// 沒找到
		printf("要查找的人不存在\n");
		return;
	}
	// 打印標(biāo)題行
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址");
	// 打印數(shù)據(jù)
	printf("%-10s %-4d %-5s %-12s %-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}

修改聯(lián)系人

再下來(lái)實(shí)現(xiàn)一個(gè)函數(shù),函數(shù)的參數(shù)仍然是一個(gè)指向通訊錄結(jié)構(gòu)體類型Contact的指針,用于修改通訊錄中的聯(lián)系人信息。具體實(shí)現(xiàn)如下:

  • 使用assert宏函數(shù)檢查指針有效性,如果指針為空,則程序會(huì)終止。

  • 定義一個(gè)char類型數(shù)組name,用于存儲(chǔ)用戶輸入的聯(lián)系人名字。

  • 使用printf函數(shù)提示用戶輸入要修改的聯(lián)系人名字,并使用scanf函數(shù)讀取用戶輸入的名字。

  • 調(diào)用FindByName函數(shù)查找通訊錄中是否存在該聯(lián)系人,如果不存在則輸出提示信息并返回。

  • 如果存在該聯(lián)系人,則使用scanf函數(shù)分別讀取用戶輸入的聯(lián)系人信息,包括名字、年齡、性別、電話和地址,并將這些信息存儲(chǔ)到通訊錄結(jié)構(gòu)體中對(duì)應(yīng)的位置。

  • 最后使用printf函數(shù)輸出修改成功的提示信息。

void ModifyContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	char name[MAX_NAME] = { 0 }; // 存儲(chǔ)用戶輸入的信息
	// 用戶輸入數(shù)據(jù)
	printf("請(qǐng)輸入要修改人的名字:>");
	scanf("%s", name);
	// 查找
	int pos = FindByName(pc, name);
	// 檢查是否找到
	if (pos == -1)
	{
		// 沒找到
		printf("要修改的人不存在\n");
		return;
	}
	// 修改
	// 用戶輸入信息
	printf("請(qǐng)輸入名字:>");
	scanf("%s", pc->data[pos].name);
	printf("請(qǐng)輸入年齡:>");
	scanf("%d", &(pc->data[pos].age));
	printf("請(qǐng)輸入性別:>");
	scanf("%s", pc->data[pos].sex);
	printf("請(qǐng)輸入電話:>");
	scanf("%s", pc->data[pos].tele);
	printf("請(qǐng)輸入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
}

排序通訊錄

接下來(lái)實(shí)現(xiàn)排序功能。具體實(shí)現(xiàn)如下:

  • 定義一個(gè)比較函數(shù)CmpByName,用于按照名字來(lái)排序聯(lián)系人信息。該函數(shù)的參數(shù)為兩個(gè)指向聯(lián)系人信息結(jié)構(gòu)體的指針p1和p2,返回值為兩個(gè)名字字符串的比較結(jié)果。

  • 在CmpByName函數(shù)中,首先使用assert宏檢查指針p1和p2的有效性,確保程序不會(huì)因?yàn)闊o(wú)效指針而崩潰。然后使用strcmp函數(shù)比較兩個(gè)聯(lián)系人信息結(jié)構(gòu)體中的名字字符串大小,返回比較結(jié)果。

  • 定義一個(gè)排序函數(shù)SortContact,用于對(duì)聯(lián)系人信息進(jìn)行排序。該函數(shù)的參數(shù)為一個(gè)指向聯(lián)系人管理系統(tǒng)結(jié)構(gòu)體的指針pc。

  • 在SortContact函數(shù)中,首先使用assert宏檢查指針pc的有效性,確保程序不會(huì)因?yàn)闊o(wú)效指針而崩潰。然后調(diào)用qsort函數(shù)對(duì)聯(lián)系人信息進(jìn)行排序,其中pc->data表示聯(lián)系人信息數(shù)組的首地址,pc->sz表示聯(lián)系人信息數(shù)組的大小,sizeof(PeoInfo)表示每個(gè)聯(lián)系人信息結(jié)構(gòu)體的大小,CmpByName表示排序函數(shù)。

  • 最后輸出排序成功的提示信息。

// 按照名字來(lái)排序
int CmpByName(const void* p1, const void* p2)
{
	// 檢查指針有效性
	assert(p1 && p2);
	// 比較名字字符串大小
	return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void SortContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 根據(jù)名字來(lái)排序
	qsort(pc->data, pc->sz, sizeof(PeoInfo), CmpByName);
	printf("排序成功\n");
}

保存通訊錄

最后實(shí)現(xiàn)將聯(lián)系人信息保存到文件中的功能。具體實(shí)現(xiàn)如下:

  • 函數(shù)定義:函數(shù)名為SaveContact,參數(shù)為一個(gè)指向Contact結(jié)構(gòu)體的指針pc。

  • 檢查指針有效性:使用assert宏函數(shù)檢查指針pc是否為NULL,如果是NULL則程序會(huì)直接終止。

  • 打開文件:使用fopen函數(shù)打開名為"contact.dat"的文件,以二進(jìn)制寫入模式(“wb”)打開。返回值為一個(gè)指向FILE結(jié)構(gòu)體的指針pf。

  • 檢查是否打開成功:使用if語(yǔ)句判斷指針pf是否為NULL,如果是NULL則說(shuō)明打開文件失敗,使用perror函數(shù)輸出錯(cuò)誤信息并返回。

  • 寫數(shù)據(jù):使用for循環(huán)遍歷pc指向的Contact結(jié)構(gòu)體中的所有聯(lián)系人信息,使用fwrite函數(shù)將每個(gè)聯(lián)系人信息寫入文件中。其中,第一個(gè)參數(shù)為指向聯(lián)系人信息的指針,第二個(gè)參數(shù)為每個(gè)聯(lián)系人信息的大小,第三個(gè)參數(shù)為寫入的數(shù)量,第四個(gè)參數(shù)為指向文件的指針pf。

  • 關(guān)閉文件:使用fclose函數(shù)關(guān)閉文件,釋放文件指針pf所占用的資源。將pf賦值為NULL,防止出現(xiàn)野指針。

  • 輸出保存成功信息:使用printf函數(shù)輸出保存成功的信息。

void SaveContact(Contact* pc)
{
	// 檢查指針有效性
	assert(pc);
	// 打開文件
	FILE* pf = fopen("contact.dat", "wb");
	// 檢查是否打開成功
	if (pf == NULL)
	{
		// 打開文件失敗
		perror("SaveContact::fopen");
		return;
	}
	// 寫數(shù)據(jù),一次寫一個(gè)
	for (int i = 0; i < pc->sz; ++i)
	{
		fwrite(pc->data + i, sizeof(struct PeoInfo), 1, pf);
	}
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
	printf("保存成功...\n");
}

到此,相信大家對(duì)“基于C語(yǔ)言怎么打造高效通訊錄”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI