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 功能函數
- 增加聯繫人函數
//增加聯繫人函數
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 ++;
}
- 刪除聯繫人函數
//刪除聯繫人函數
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");
}
- 修改聯繫人函數
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");
}
- 查找聯繫人函數
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");
}
}
- 排序聯繫人函數
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;
}
}
}
}
- 打印聯繫人函數
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);
}
- 清空聯繫人函數
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上,鏈接如下:通訊錄鏈接
除此之外還有其他的這麼多的練手小程序,都是以前編寫出來的,需要的朋友也是可以自取!