首頁 > 軟體

C語言實現通訊錄功能的流程與程式碼

2022-06-18 14:00:19

用C語言製作一個擁有新增,刪除,查詢,修改,排序,清空,列印功能的通訊錄

用分模組的方法來實現這個通訊錄,函數的宣告,型別的宣告放在一個.h檔案中,函數的實現放在一個.c檔案中,在主檔案中來呼叫函數。

首先建立一個test.c檔案用來測試並且實現通訊錄的功能

通訊錄需要顯示一個選單來讓使用者具體選擇哪個功能,那麼在test.c檔案中就需要列印出來一個選單,如下程式碼:

#include <stdio.h>
void menu()
{
	printf("***********************************n");
	printf("******  1.add      2.del     ******n");
	printf("******  3.search   4.modify  ******n");
	printf("******  5.sort     6.empty   ******n");
	printf("******  7.print    0.exit    ******n");
	printf("***********************************n");
}
int main()
{
	//通訊錄:1.add 2.del 3.search 4,modify 5.sort 6.empty 7.print 0.exit
	do
	{
		menu();
	} while (0);
	return 0;
}

接著就要讓使用者選擇輸入某個陣列來使用通訊錄的功能,這時就可以用一個switch開關來實現了,如下程式碼:

	int input = 0;
	do
	{
		menu();
		printf("請選擇功能>:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 0:
			break;
		default:
			printf("請重新輸入n");
			break;
		}
	} while (input);

在while迴圈的條件判斷部分直接寫input,這樣選擇輸入0的時候就直接跳出迴圈了,輸入其他數位可以繼續使用通訊錄的功能。

case後面跟著的都是數位,有時候偵錯程式碼的時候比較容易忘記這個數位表示的是什麼意思,所以這個時候可以用建立一個列舉型別來定義對應的列舉常數。

建立一個contact.h檔案來放型別的定義,函數的宣告。

然後把列舉型別在裡面進行宣告

enum input
{
	Exit,
	add,
	sub,
	search,
	modify,
	sort,
	empty,
	print
};

之後要在主檔案中呼叫這個標頭檔案

#include "contact.h"

同時可以把#include <stdio.h>這些庫函數的參照都放到contact.h這個檔案當中,這樣要參照新的庫函數時只需要在contact.h這個檔案中新增就可以了。

這樣switch開關中的程式碼就可以改成這樣了:

		switch (input)
		{
		case add:
			break;
		case sub:
			break;
		case search:
			break;
		case modify:
			break;
		case sort:
			break;
		case empty:
			break;
		case print:
			break;
		case Exit:
			break;
		}

然後開始用函數去實現每一個函數的功能,首先是新增功能,在新增之前,還得需要一個空的通訊錄,來存放新增進去的通訊人的資料,而通訊人的資料有姓名,年齡,性別,電話號碼,地址這些資料,都是一些不同型別的值,這時可以宣告一個結構體型別來包含這些成員

好,切到contact.h檔案來宣告一個結構體型別:

typedef struct People
{
	char name[20];
	int age;
	char sex[5];
	char phone[20];
	char address[30];
} People;

同時還對這個型別重新命名了一下,方便後續使用這個結構體型別,這是需要考慮到通訊錄存放資料多少的問題,如果address裡面存放的內容放不下了,這是就需要對陣列的大小進行更改,那這時就要先找到這個結構體型別才能更改了,如果程式碼寫的比較多的話就會比較亂,所以可以用#define定義的識別符號常數來定義這些值,以後要改的話就只需要找到#define就可以了

如下程式碼:

#define NameMax 20
#define SexMax 5
#define PhoneMax 20
#define AddressMax 30
typedef struct People
{
	char name[NameMax];
	int age;
	char sex[SexMax];
	char phone[PhoneMax];
	char address[AddressMax];
} People;

因為這裡是不同型別的值的定義,所以用#define來定義而不用列舉型別來定義,因為列舉型別是用來列舉相同型別的值的,比如前面的通訊錄功能都是屬於通訊錄的功能一類的值

下一步,通訊錄不只存放一個人的資料,所以需要用這個結構體型別來建立一個陣列,假設這個通訊錄可以存放1000個人的資料,同時還能記錄其中已存放了多少個人

那麼可以在主函數中這麼寫:

int main()
{
	//通訊錄:1.add 2.del 3.search 4,modify 5.sort 6.empty 7.print 0.exit
	People contact[1000];
	int num;

對於這個通訊錄和這個通訊人的數量,這兩個變數可以兩者之間是由聯絡的,那麼此時就可以再宣告一個結構體型別來包含這兩個成員。

切到contact.h檔案:

typedef struct Contact
{
	People people[1000];
	int num;
} Contact;

宣告好這個通訊錄型別之後,需要在主檔案中用這個型別建立一個變數,同時對變數的內容進行初始化

int main()
{
	//通訊錄:1.add 2.del 3.search 4,modify 5.sort 6.empty 7.print 0.exit
	Contact contact;
	InitialContact(&contact);

切到contact.h檔案宣告函數:

//函數的宣告
 
//通訊錄初始化
void InitialContact(Contact* pc);

此時建立一個contact.c檔案來實現函數的內容:

切到contact.c檔案:

#include "contact.h"
void InitialContact(Contact* pc)
{
	memset(pc, 0, sizeof(*pc));
}

要記得引這個contact.h標頭檔案

在對通訊錄的內容進行完初始化之後,可以開始往裡面新增通訊人的資訊了,再宣告一個函數:

test.c:

		case add:
			printf("新增通訊人n");
			AddPeople(&contact);
			break;

contact.h:

//新增通訊人
void AddPeople(Contact* pc);

contact.c:

void AddPeople(Contact* pc)
{
	if (pc->num == 1000)
	{
		printf("通訊錄已滿n");
		return;
	}
	printf("請輸入姓名>:");
	scanf("%s", pc->people[pc->num].name);
	printf("請輸入年齡>:");
	scanf("%d", &pc->people[pc->num].age);
	printf("請輸入性別>:");
	scanf("%s", pc->people[pc->num].sex);
	printf("請輸入電話>:");
	scanf("%s", pc->people[pc->num].phone);
	printf("請輸入地址>:");
	scanf("%s", pc->people[pc->num].address);
	pc->num++;
}

輸入完成之後,要記得讓通訊人數量+1

接下來可以嘗試顯示一下通訊錄中的通訊人資訊了

contact.h:

//顯示通訊人資訊
void PrintContact(const Contact* pc);

contact.c:

void PrintContact(const Contact* pc)
{
	printf("%-20s %-20s %-20s %-20s %-20sn", "姓名", "年齡", "性別", "電話", "地址");
	int i = 0;
	for (i = 0; i < pc->num; i++)
	{
		printf("%-20s %-20d %-20s %-20s %-20sn", pc->people[i].name, pc->people[i].age, pc->people[i].sex, pc->people[i].phone, pc->people[i].address);
	}
}

在前面列印個通訊人列表修飾一下

test.c:

		case print:
			printf("顯示通訊人資訊n");
			PrintContact(&contact);
			break;

接下來,開始實現通訊錄的刪除功能:

可以通過讓使用者輸入某個人的名字來刪除這個人在通訊錄中的資訊,刪除功能的實現分為兩步,第一步,是需要找到這個人,第二步,刪除這個人在通訊錄中的資訊

contact.h:

//刪除通訊人資訊
void SubPeople(Contact* pc);

contact.c:

int FindByName(Contact* pc, const char* name)
{
	//遍歷每一個contact結構體中people陣列成員中的已存放資料的每一個結構體
	int i = 0;
	for (i = 0; i < sizeof(pc->num); i++)
	{
		if (strcmp(pc->people[i].name, name) == 0)
		{
			return i;//找到了返回對應結構體的下標
		}
	}
	return -1;//找不到就返回-1
}
void SubPeople(Contact* pc)
{
	if (pc->num == 0)//先判斷通訊錄中有無儲存資訊
	{
		printf("通訊錄已清空n");
		return;
	}
	//1.找到
	printf("請輸入要刪除的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要刪除的人n");
		return;//讓函數直接返回
	}
	//2.刪除
	//從找到的那個下標位置開始,後面的陣列元素(通訊人結構體)依次往前賦值
	int j = 0;
	for (j = ret; j < pc->num - 1; j++)
	{
		pc->people[j] = pc->people[j + 1];
	}
	printf("刪除成功n");
	pc->num--;//通訊人數量-1
}

test.c:

		case sub:
			SubPeople(&contact);
			break;

每完成一個功能,都要去嘗試執行一下,看有沒有bug,否則最後才去找bug可能會比較麻煩。

在刪除功能中,用到了一個自己寫的FindByName函數,然後在接下來的通訊錄查詢功能實現中,同樣也要依賴這個函數,不僅如此,在通訊錄修改功能中,也要用到這個函數,而這個函數的實現是為了刪除、查詢和修改功能而宣告的,所以可以不用寫在contact.h標頭檔案中進行宣告。

下面,來開始實現查詢功能:

contact.h:

//查詢通訊人
void SearchPeople(const Contact* pc);

contact.c:

void SearchPeople(const Contact* pc)
{
	//查詢
	printf("請輸入要查詢的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要查詢的人n");
		return;//讓函數直接返回
	}
	//顯示
	printf("%-20s %-20s %-20s %-20s %-20sn", "姓名", "年齡", "性別", "電話", "地址");
	printf("%-20s %-20d %-20s %-20s %-20sn", pc->people[ret].name, pc->people[ret].age, pc->people[ret].sex, pc->people[ret].phone, pc->people[ret].address);
}

test.c:

		case search:
			SearchPeople(&contact);
			break;

查詢功能已經實現了,接下來就要實現修改功能了,先通過通訊人的姓名找到需要修改的結構體對應的下標,然後重新對這個結構體進行賦值就可以了

contact.h:

//修改通訊人資訊
void ModifyPeople(Contact* pc);

contact.c:

void ModifyPeople(Contact* pc)
{
	//查詢
	printf("請輸入要修改的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要修改的人n");
		return;//讓函數直接返回
	}
	//修改
	printf("請輸入要修改的姓名>:");
	scanf("%s", pc->people[ret].name);
	printf("請輸入要修改的年齡>:");
	scanf("%d", &pc->people[ret].age);
	printf("請輸入要修改的性別>:");
	scanf("%s", pc->people[ret].sex);
	printf("請輸入要修改的電話>:");
	scanf("%s", pc->people[ret].phone);
	printf("請輸入要修改的地址>:");
	scanf("%s", pc->people[ret].address);
}

test.c:

		case modify:
			ModifyPeople(&contact);
			break;

接下來可以開始實習通訊錄的排序功能了,這裡就按照年齡來進行一個排序,用到qsort這個函數,其中cmp函數需要自己去寫

contact.h:

//排序
void SortByAge(Contact* pc);

contact.c:

int cmp(const void* e1, const void* e2)
{
	Contact* p1 = (Contact*)e1;
	Contact* p2 = (Contact*)e2;
	if (p1->people[0].age > p2->people[1].age)
	{
		return 1;
	}
	else if (p1->people[0].age < p2->people[1].age)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
void SortByAge(Contact* pc)
{
	if (pc->num == 0)
	{
		printf("通訊錄已清空n");
		return;
	}
	int num = pc->num;
	int width = sizeof(pc->people[0]);
	qsort(pc->people, num, width, cmp);
}

test.c:

		case sort:
			printf("按照年齡排序n");
			SortByAge(&contact);
			PrintContact(&contact);
			break;

到這裡通訊錄的功能就只剩下清空了,可以用到一開始的初始化函數InitialContact

test.c:

		case empty:
			printf("清空通訊錄n");
			InitialContact(&contact);
			break;

現在通訊錄的功能已經全部實現了

可是這個通訊錄的功能還是有點不太好,就是通訊錄預設的大小就是存放1000個人的資料,那麼能不能建立一個可以隨著新增人數的增加而變大的通訊錄呢?鑑於最近學習了動態記憶體管理,所以對通訊錄的功能做出了一點改進

對結構體型別的修改:

contact.h

typedef struct Contact
{
	People* people;
	int num;
	int capacity;//通訊錄的容量
} Contact;

contact.c:

對InitialContact函數的修改:

void InitialContact(Contact* pc)
{
	pc->people = (People*)calloc(3, sizeof(People));
	if (pc->people == NULL)
	{
		perror("calloc");
		return;
	}
	pc->num = 0;
	pc->capacity = 3;
}

對AddPeople函數的修改:

void AddPeople(Contact* pc)
{
	if (pc->num == pc->capacity)
	{
		pc->people = realloc(pc->people, (pc->capacity + 2) * sizeof(People));
		if (pc->people == NULL)
		{
			perror("realloc");
			return;
		}
		pc->capacity += 2;
	}
	printf("請輸入姓名>:");
	scanf("%s", pc->people[pc->num].name);
	printf("請輸入年齡>:");
	scanf("%d", &pc->people[pc->num].age);
	printf("請輸入性別>:");
	scanf("%s", pc->people[pc->num].sex);
	printf("請輸入電話>:");
	scanf("%s", pc->people[pc->num].phone);
	printf("請輸入地址>:");
	scanf("%s", pc->people[pc->num].address);
	pc->num++;
}

對排序函數中cmp函數的修改:

int cmp(const void* e1, const void* e2)
{
	People* p1 = (People*)e1;
	People* p2 = (People*)e2;
	if (p1->age > p2->age)
	{
		return 1;
	}
	else if (p1->age < p2->age)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

test.c:

部分修改:

		case empty:
			printf("清空通訊錄n");
			FreeContact(&contact);
			break;
		case Exit:
			FreeContact(&contact);
			break;

如下是完整的程式碼:

contact.h:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
//型別的宣告
#define NameMax 20
#define SexMax 5
#define PhoneMax 20
#define AddressMax 30
enum input
{
	Exit,
	add,
	sub,
	search,
	modify,
	sort,
	empty,
	print
};
typedef struct People
{
	char name[NameMax];
	int age;
	char sex[SexMax];
	char phone[PhoneMax];
	char address[AddressMax];
} People;
typedef struct Contact
{
	People* people;
	int num;
	int capacity;//通訊錄的容量
} Contact;
//函數的宣告
//通訊錄初始化
void InitialContact(Contact* pc);
//新增通訊人
void AddPeople(Contact* pc);
//顯示通訊人資訊
void PrintContact(const Contact* pc);
//刪除通訊人資訊
void SubPeople(Contact* pc);
//查詢通訊人
void SearchPeople(const Contact* pc);
//修改通訊人資訊
void ModifyPeople(Contact* pc);
//排序
void SortByAge(Contact* pc);
//銷燬通訊錄
void FreeContact(Contact* pc);

contact.c:

#include "contact.h"
void InitialContact(Contact* pc)
{
	pc->people = (People*)calloc(3, sizeof(People));
	if (pc->people == NULL)
	{
		perror("calloc");
		return;
	}
	pc->num = 0;
	pc->capacity = 3;
}
void AddPeople(Contact* pc)
{
	if (pc->num == pc->capacity)
	{
		pc->people = realloc(pc->people, (pc->capacity + 2) * sizeof(People));
		if (pc->people == NULL)
		{
			perror("realloc");
			return;
		}
		pc->capacity += 2;
	}
	printf("請輸入姓名>:");
	scanf("%s", pc->people[pc->num].name);
	printf("請輸入年齡>:");
	scanf("%d", &pc->people[pc->num].age);
	printf("請輸入性別>:");
	scanf("%s", pc->people[pc->num].sex);
	printf("請輸入電話>:");
	scanf("%s", pc->people[pc->num].phone);
	printf("請輸入地址>:");
	scanf("%s", pc->people[pc->num].address);
	pc->num++;
}
void PrintContact(const Contact* pc)
{
	printf("%-20s %-20s %-20s %-20s %-20sn", "姓名", "年齡", "性別", "電話", "地址");
	int i = 0;
	for (i = 0; i < pc->num; i++)
	{
		printf("%-20s %-20d %-20s %-20s %-20sn", pc->people[i].name, pc->people[i].age, pc->people[i].sex, pc->people[i].phone, pc->people[i].address);
	}
}
int FindByName(Contact* pc, const char* name)
{
	//遍歷每一個contact結構體中people陣列成員中的已存放資料的每一個結構體
	int i = 0;
	for (i = 0; i < sizeof(pc->num); i++)
	{
		if (strcmp(pc->people[i].name, name) == 0)
		{
			return i;//找到了返回對應結構體的下標
		}
	}
	return -1;//找不到就返回-1
}
void SubPeople(Contact* pc)
{
	if (pc->num == 0)//先判斷通訊錄中有無儲存資訊
	{
		printf("通訊錄已清空n");
		return;
	}
	//1.找到
	printf("請輸入要刪除的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要刪除的人n");
		return;//讓函數直接返回
	}
	//2.刪除
	//從找到的那個下標位置開始,後面的陣列元素(通訊人結構體)依次往前賦值
	int j = 0;
	for (j = ret; j < pc->num - 1; j++)
	{
		pc->people[j] = pc->people[j + 1];
	}
	printf("刪除成功n");
	pc->num--;//通訊人數量-1
}
void SearchPeople(const Contact* pc)
{
	//查詢
	printf("請輸入要查詢的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要查詢的人n");
		return;//讓函數直接返回
	}
	//顯示
	printf("%-20s %-20s %-20s %-20s %-20sn", "姓名", "年齡", "性別", "電話", "地址");
	printf("%-20s %-20d %-20s %-20s %-20sn", pc->people[ret].name, pc->people[ret].age, pc->people[ret].sex, pc->people[ret].phone, pc->people[ret].address);
}
void ModifyPeople(Contact* pc)
{
	//查詢
	printf("請輸入要修改的人的姓名;>");
	char name[NameMax];
	scanf("%s", name);
	int ret = FindByName(pc, name);//用以接收放回的陣列下標
	if (ret == -1)
	{
		printf("找不到要修改的人n");
		return;//讓函數直接返回
	}
	//修改
	printf("請輸入要修改的姓名>:");
	scanf("%s", pc->people[ret].name);
	printf("請輸入要修改的年齡>:");
	scanf("%d", &pc->people[ret].age);
	printf("請輸入要修改的性別>:");
	scanf("%s", pc->people[ret].sex);
	printf("請輸入要修改的電話>:");
	scanf("%s", pc->people[ret].phone);
	printf("請輸入要修改的地址>:");
	scanf("%s", pc->people[ret].address);
}
int cmp(const void* e1, const void* e2)
{
	People* p1 = (People*)e1;
	People* p2 = (People*)e2;
	if (p1->age > p2->age)
	{
		return 1;
	}
	else if (p1->age < p2->age)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
void SortByAge(Contact* pc)
{
	if (pc->num == 0)
	{
		printf("通訊錄已清空n");
		return;
	}
	int num = pc->num;
	int width = sizeof(People);
	qsort(pc->people, num, width, cmp);
}
void FreeContact(Contact* pc)
{
	free(pc->people);
	pc->people = NULL;
	pc->num = 0;
	pc->capacity = 0;
}

test.c:

#include "contact.h"
void menu()
{
	printf("***********************************n");
	printf("******  1.add      2.del     ******n");
	printf("******  3.search   4.modify  ******n");
	printf("******  5.sort     6.empty   ******n");
	printf("******  7.print    0.exit    ******n");
	printf("***********************************n");
}
int main()
{
	//通訊錄:1.add 2.del 3.search 4,modify 5.sort 6.empty 7.print 0.exit
	//建立通訊錄
	Contact contact;
	//初始化通訊錄
	InitialContact(&contact);
	int input = 0;
	do
	{
		menu();
		printf("請選擇功能>:");
		scanf("%d", &input);
		switch (input)
		{
		case add:
			printf("新增通訊人n");
			AddPeople(&contact);
			break;
		case sub:
			SubPeople(&contact);
			break;
		case search:
			SearchPeople(&contact);
			break;
		case modify:
			ModifyPeople(&contact);
			break;
		case sort:
			printf("按照年齡排序n");
			SortByAge(&contact);
			PrintContact(&contact);
			break;
		case empty:
			printf("清空通訊錄n");
			FreeContact(&contact);
			break;
		case print:
			printf("顯示通訊人資訊n");
			PrintContact(&contact);
			break;
		case Exit:
			FreeContact(&contact);
			break;
		default:
			printf("請重新輸入n");
			break;
		}
	} while (input);
	return 0;
}

到此這篇關於C語言實現通訊錄功能的流程與程式碼的文章就介紹到這了,更多相關C語言通訊錄內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com