如何用1個C語言函數寫出帶文件存儲的動態內存通訊錄!!

C語言通訊錄的實現

將自己在學習完C語言之際所寫的一個通訊錄實現程序分享給大家,這其中包括了對於動態內存管理的知識,和文件操作的知識,或許不是最牛最精簡的,但卻是最好學習最容易上手的一個動態內存通訊錄。

對於每一行代碼我都將給出最全面的註釋,讓你的學習沒有絲毫難度

1. 頭文件

#define _CRT_SECURE_NO_WARNINGS//windows的弊端,所以需要加上這個,其他系統另當別論
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//字符串函數的使用
#include <windows.h>//用來進行清屏函數的使用
#include <assert.h>//判空函數的使用

//定義通訊錄數組的最大值爲200 [0-200) 前閉後開
#define MAX_SIZE 200
(對於不想實現動態內存的話,可以將通訊錄中人數的指針變爲數組即可,而數組的大小就是在這裏所定義的200,所以在這個動態內存之中沒有使用到靜態,因此`MAX_SIZE`沒有用武之地,大家也可以將其省略)


//
#define CAPACITY 20

//定義個人聯繫信息的結構體變量
typedef struct PersonInof {
	char name[1024];//存儲姓名
	char phone[1024];//存儲電話
}PersonInof;//定義結構體聲明

//定義通訊錄結構
typedef struct AddressBook {
	PersonInof *persons;//總共可存儲的通訊錄人數
	int size;//統計放入的個數
	//定義空間 [0- size) 爲已使用的空間
	// (size-200) 爲未使用的空間
	int capacity;
	//通訊錄的容量
}AddressBook;

2. 調用函數

2.1 文件存儲函數

//文件的讀取和存儲操作函數
void SaveFile(AddressBook* address) {
	//文件存儲
	//1. 先行打開我們需要寫入數據的文件
	FILE* fp = fopen("h:/address.txt", "w");//我自己的文件根目錄,大家需要改變
	if (fp == NULL) {
		perror("文件打開操作失敗!\n");
		return;
	}

	//2. 使用for循環遍歷的方式,將通訊錄之中的數據寫入到文件之中
	for (int i = 0; i < address->size; i++) {
		fwrite(&address->persons[i], sizeof(PersonInof), 1, fp);
	}
	fclose(fp);
	printf("保存成功!\n");
}


void LoadFile(AddressBook* address) {
	//文件讀取
	//1. 打開文件
	FILE* fp = fopen("h:/address.txt", "r");
	if (fp == NULL) {
		perror("文件打開操作失敗!\n");
		return;
	}

	//2. 循環讀取文件之中的內容,並把數據加載到通訊錄結構體之中
	PersonInof tmp = { 0 };
	while (1) {
		int n = fread(&tmp, sizeof(PersonInof), 1, fp);
		if (n < 1) {
			break;
		}
		CheckCapacity(address);
		//判斷容量是否超標,進行擴容操作
		address->persons[address->size] = tmp;
		address->size++;
	}
	fclose(fp);

}

2.2 初始化函數

//初始化函數,將通訊錄中的信息進行初始化
void Init(AddressBook* address) {
	address->size = 0;//先行使size爲0 ,則表示通訊錄爲空
	address->persons = (PersonInof*)malloc(sizeof(PersonInof) * CAPACITY);
	if (address->persons == NULL)
	{
		perror("use malloc");//報錯
		exit(EXIT_FAILURE);//退出
	}
	memset(address->persons, 0, sizeof(PersonInof) * CAPACITY);
	address->capacity = CAPACITY;
}

2.3 檢查容量擴容函數

void CheckCapacity(AddressBook* address) {
	//檢查是否容量超標,進行擴容
	if (address->size == address->capacity) {
		PersonInof* ptr = (PersonInof*)realloc(address->persons,
			address->capacity * sizeof(PersonInof));
		//進行續接,每次擴大的容量都是一個標準容量capacity
		if (address->persons == NULL)
		{
			//判空
			perror("realloc");
			exit(EXIT_FAILURE);
		}
		else {
			address->persons = ptr;
		}
		printf("擴容成功!\n");
	}
}

2. 4 目錄的打印

//打印通訊錄的菜單選項
int Menu() {
	printf("============================\n");
	printf("==========通 訊 錄==========\n");
	printf("======1.新 增 聯 系 人======\n");
	printf("======2.刪 除 聯 系 人======\n");
	printf("======3.修 改 聯 系 人======\n");
	printf("======4.查 找 聯 系 人======\n");
	printf("======5.排 序 通 訊 錄======\n");
	printf("======6.打 印 通 訊 錄======\n");
	printf("======7.清 空 通 訊 錄======\n");
	printf("======0.   退  出     ======\n");
	printf("============================\n");
	printf("請輸入您的選擇:");
	int choice;
	scanf("%d", &choice);//輸入我們的選擇
	return choice;///返回用戶所輸入的信息
}

2. 5 功能函數

  1. 增加聯繫人函數
//增加聯繫人函數
void AddpersonInof(AddressBook* address) {
	assert(address->persons != NULL);
	CheckCapacity(address);
	PersonInof* info = &address->persons[address->size];
	//這樣做是爲了方便使用,避免在下面的輸入中不斷地輸入很長地一串
	printf("請輸入姓名:");
	scanf("%s", info->name);
	printf("請輸入電話:");
	scanf("%s", info->phone);
	printf("成功增加新的聯繫人!\n");
	address->size ++;
}
  1. 刪除聯繫人函數
//刪除聯繫人函數
void DelpersonInof(AddressBook* address) {
	//確定執行刪除操作
	printf("執行刪除\n");
	if (address->size <= 0) {
		//先行判定通訊錄是否爲空
		printf("通訊錄爲空,無需進行刪除!\n");
		return;
	}

	printf("請輸入您要刪除的聯繫人序號:");
	int id = 0;
	//創建需要刪除的聯繫人序號變量
	scanf("%d", &id);
	//麻煩之處就是需要先行進行查詢全部的聯繫人

	if (id < 0 || id >= address->size) {
		//檢查客戶輸入的程序是否合法
		printf("輸入的id非法!無法進行刪除\n");
		return;
	}

	PersonInof* last_info = &address->persons[address->size - 1];
	//找到最後一個成員的信息
	PersonInof* to_delete = &address->persons[id];
	//需要刪除的成員信息

	*to_delete = *last_info;
	//二者進行互換則可
	address->size--;
	//最後更改size值,保證刪除後數量減11
	printf("刪除成功!\n");
}
  1. 修改聯繫人函數
void ModifypersonInof(AddressBook* address) {
	if (address->size <= 0) {
		//同樣判斷通訊錄是否爲空
		printf("通訊錄爲空,無法進行修改\n");
			return;
	}
	int id = 0;
	printf("請輸入要修改的聯繫人序號:");
	//創建聯繫人序號中間變量
	scanf("%d", &id);
	if (id < 0 || id >= address->size) {
		//檢查輸入序號是否合法
		printf("輸入序號無法查詢,修改失敗\n");
		return;
	}

	PersonInof* info = &address->persons[id];
	//定義結構體變量類型
	printf("請輸入修改後的名字(* 表示不修改):");
	char name[1024] = { 0 };
	scanf("%s", name);
	//若相等則代表不修改
	if (strcmp(name, "*") != 0) {
		strcpy(info->name, name);
	}
	printf("請輸入修改後的電話(* 表示不修改):");
	char phone[1024] = { 0 };
	scanf("%s", phone);
	//同理
	if (strcmp(phone, "*") != 0) {
		strcpy(info->phone, phone);
	}
	printf("修改完成!\n");
}

  1. 查找聯繫人函數
void FindpersonInof(AddressBook* address) {
	printf("查找指定聯繫人\n");
	printf("請輸入要查找的聯繫人姓名:");
	int N = 0;
	char name[1024] = { 0 };
	//設定輸入名字的變量
	scanf("%s", name);
	for (int i = 0; i < address->size; i++) {
		//逐個進行比對,將相等的輸出
		PersonInof* info = &address->persons[i];
		if (strcmp(name, info->name) == 0) {
			printf("[%d] %s:%s\n", i, info->name, info->phone);
			N++;
		}
	}
	if (N == 0) {
		printf("未找到您需要查找的聯繫人信息!\n");
	}
	else {
		printf("查找聯繫人完畢\n");
	}

}
  1. 排序聯繫人函數
void SortpersonInof(AddressBook* address) {
	int i = 0;
	int j = 0;
	int k = 0;
	for (i = 0; i < address->size - 1; i++)
	{
		for (j = 0; j < address->size - i - 1; j++)
		{
			if (strcmp(address->persons[i].name, address->persons[i + 1].name) > 0)
			{
				struct PersonInof tmp;
				tmp = address->persons[j];
				address->persons[j] = address->persons[j + 1];
				address->persons[j + 1] = tmp;
			}
		}
	}
}

  1. 打印聯繫人函數
void PrintpersonInof(AddressBook* address) {
	printf("打印通訊錄\n");
	printf("%5s\t%10s\t%15s\t\n","num","name", "phone");
	for (int i = 0; i < address->size; i++) {
		PersonInof* info = &address->persons[i];
		printf("[%d] %s:%s\n",i,info->name,info->phone);
	}
	//逐個打印所存在的通訊錄數據
	printf("當前共打印%d條記錄\n", address->size);
}
  1. 清空聯繫人函數
void ClearpersonInof(AddressBook* address) {
	printf("是否要刪除全部通訊錄?\n");
	printf("Y(y)/N(n)\n");
	//提供確認選項供客戶選擇
	char choice[1024] = { 0 };
	//回答是則進行最後的刪除
	scanf("%c", choice);
	if ((strcmp(choice, "y") == 0) || (strcmp(choice, "Y") == 0)) {
		address->size = 0;
		printf("刪除完畢!\n");
		return;
	}
	//否則進行取消操作
	else{
		printf("刪除取消!\n");
		return;
	}
}

3. 主函數

int main() {
	AddressBook address;//創建初始變量
	Init(&address);//初始化函數
	LoadFile(&address);
	typedef void(*Func)(AddressBook*);
	//定義函數指針

	//採用轉移表地方式來進行菜單地選擇
	Func func_table[] = {
		NULL,//爲和菜單項地序號匹配,將0地位置置爲空
		AddpersonInof,
		DelpersonInof,
		ModifypersonInof,
		FindpersonInof,
		SortpersonInof,
		PrintpersonInof,
		ClearpersonInof,
	};
	while (1) {
		int choice = Menu();
		if (choice < 0 || choice >= sizeof(func_table) / sizeof(func_table[0])) {
			printf("您的輸入有誤!\n");
			continue;
		}
		if (choice == 0) {
			SaveFile(&address);
			system("cls");
			printf("goodbye!\n");
			break;
		}
		func_table[choice](&address);
	}

	system("pause");
	return 0;
}

4. 實現圖

因爲我在通訊錄之中放置了一些我自己朋友的信息,所有就不一一給大家展示了。
實現圖
到這裏關於動態內存通訊錄的所有程序也就完全執行完畢了,如果哪裏還有這不懂得朋友,也是可以直接留言,或者有什麼更好主意的朋友也是可以進行相互之間的討論,以此來相互提高。
完整的代碼鏈接,在我GitHub上,鏈接如下:通訊錄鏈接
除此之外還有其他的這麼多的練手小程序,都是以前編寫出來的,需要的朋友也是可以自取!
GitHub圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章