C語言實現可增容動態通訊錄詳細過程

創建可自動擴容的通訊錄

這裡我們想實現通訊錄自動擴容,不夠瞭能擴大內存,變得稍微有點智能,就不得不用到開辟內存的函數malloc和realloc,這兩個函數又和free離不開關系

所以這裡我給大傢簡單的介紹一下這三個庫函數

malloc:這個函數向內存申請一塊連續可用的空間,並返回指向這塊空間的指針

void *malloc( size_t size );

如果開辟成功,則返回一個指向開辟好空間的指針。

如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。

返回值的類型是 void* ,所以malloc函數並不知道開辟空間的類型,具體在使用的時候使用者自己

來決定。

如果參數 size 為0,malloc的行為是標準是未定義的,取決於編譯器

這裡給大傢簡單的演示一下:

int main()
{
	int arr[5] = { 0 };
	int* ptr = NULL;
	ptr = (int*)malloc(5 * sizeof(int));//開辟5個大小為int整型的空間給ptr
	//判斷是否開辟成功
	if (ptr == NULL)
	{
		perror(malloc);//打印錯誤信息
		return;
	}
	free(ptr);//釋放內存
    ptr = NULL;//消除野指針問題
	return 0;
}

realloc:realloc函數的出現讓動態內存管理更加靈活。

有時會我們發現過去申請的空間太小瞭,有時我們又會覺得申請的空間過大瞭,那為瞭合理的時使用內存,我們一定會對內存的大小做靈活的調整。那 realloc 函數就可以做到對動態開辟內存大小的調整

void* realloc (void* ptr, size_t size);

ptr 是要調整的內存地址

size 調整之後新大小

返回值為調整之後的內存起始位置。

這個函數調整原內存空間大小的基礎上,還會將原來內存中的數據移動到新的空間

值得我們註意的是這個函數的開辟內存有兩種情況:

情況1

當原有空間之後有足夠大的空間的時候,要擴展內存就直接原有內存之後直接追加空間,原來空間的數據不發生變化。

情況2

當原有空間之後沒有足夠大的空間時候,原有空間之後沒有足夠多的空間時,擴展的方法是:在堆空間上另找一個合適大小

的連續空間來使用。這樣函數返回的是一個新的內存地址

free:用來釋放內存的,這個函數是搭配開辟內存的函數使用且非常關鍵,如果開辟瞭內存不及時釋放的話會造成內存釋放等嚴重後果,若重復釋放也會有不良影響,所以需要我們註意。

當我們瞭解瞭上面三個函數過後我們來試著建立一個可擴容的通訊錄

這裡我們先創建一個結構體用來存放用戶的信息

//在這裡進行初始化賦值,若以後有變隻需在這一個地方改變
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
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;//可以存放人的信息(可增長)
	int sz;//記錄通訊中已經保存的信息個數
	int capacity;//記錄通訊錄當前的最大容量
}Contact;

當數量大於3時我們就應該擴容並初始化,具體實現

//通訊錄初始狀態的容量大小
#define DEFAULT_SZ 3
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的內存並且強制類型轉換為PeoInfo*類型放在tmp地址處
		PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
		if (tmp != NULL)
		{
			pc->data = tmp;//將tmp地址給到pc->data達到連續存放的目的
		}
		else
		{
			perror("CheckCapacity::realloc");//開辟失敗打印錯誤信息
			return;
		}
		pc->capacity += 2;//開辟成功後及時更新最大容量
		printf("增容成功\n");
	}
}

添加用戶信息

實現:

void AddContact(Contact* pc)
{
	assert(pc);
    //動態的版本
	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");
}

刪除用戶信息

//找到瞭返回下標
//找不到返回-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");
}

查找聯系人

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 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 ModifyContact(Contact* pc)
{
	//首先先找到要修改的人
	int input = 0;
	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);
	printf("請選擇你要修改的信息:\n");
    //用switch語句可以實現隻改某一項的信息
	do
	{
		printf("0.修改完畢  1.姓名  2.年齡  3.性別  4.電話  5.地址\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("請輸入修改的名字:>");
			scanf("%s", pc->data[pos].name);
			break;
		case 2:
			printf("請輸入修改的年齡:>");
			scanf("%d", &(pc->data[pos].age));//註意取地址
			break;
		case 3:
			printf("請輸入修改的性別:>");
			scanf("%s", pc->data[pos].sex);
			break;
		case 4:
			printf("請輸入修改的電話:>");
			scanf("%s", pc->data[pos].tele);
			break;
		case 5:
			printf("請輸入修改的地址:>");
			scanf("%s", pc->data[pos].addr);
			break;
		}
	} while (input);
	printf("修改成功\n");
}

以名字將用戶排序

//以姓名排序(A~Z的順序)
void SortContact(Contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz-1; i++)
	{
		int ret = strcmp(pc->data[i].name, pc->data[i + 1].name);
		if (ret > 0)
		{
			PeoInfo tmp;
			tmp = pc->data[i];
			pc->data[i] = pc->data[i + 1];
			pc->data[i + 1] = tmp;
		}
	}
	printf("排序成功\n");
}

銷毀通訊錄

當結束時銷毀通訊錄,釋放內存,避免出現內存泄漏等問題

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("銷毀成功\n");
}

這裡隻展示瞭功能函數以及我認為一些需要註意的地方,若想看完整版可以去下面的鏈接看看哦

gitee

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

推薦閱讀: