通訊錄的最新版本來啦,請注意查收~~~
創(chuàng)新互聯(lián)服務(wù)項目包括樊城網(wǎng)站建設(shè)、樊城網(wǎng)站制作、樊城網(wǎng)頁制作以及樊城網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,樊城網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到樊城省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!在手機中的通訊錄,與我們之前的兩個通訊錄版本相比,大的區(qū)別是每次關(guān)掉程序或者關(guān)機重啟,聯(lián)系人的信息不會像在內(nèi)存中的程序一樣丟失,而是保存在了本地的硬盤里,這一次,我們就使用C語言中的文件功能對通訊錄進(jìn)行改進(jìn)。
總結(jié)一下,需要完成的功能為:在退出時保存信息到文件;打開時加載文件中的信息到程序。
目錄
一、代碼優(yōu)化
1.退出時保存信息
(1)創(chuàng)建函數(shù)
(2)保存信息
(3)關(guān)閉文件
2.打開程序時加載文件中的信息
(1)創(chuàng)建讀取函數(shù)
(2)讀取信息
(3)關(guān)閉文件
三、文件代碼?
1.contact.h
2.contact.c
3.test.c
四、注意事項
?????我們創(chuàng)建SaveContact函數(shù)用來將信息保存至文件中,將這個函數(shù)放在switch語句中的case選項下,先存放到文件中,再銷毀程序中的通訊錄。
// test.c
...
case EXIT:
SaveContact(&contact);
DestoryContact(&contact);
break;
...
(1)創(chuàng)建函數(shù)???? 首先需要先打開文件,采用寫入的方式,我們定義FILE類型指針,指向使用fopen打開的文件,并判斷文件指針是否為空,即是否打開文件失敗,失敗就提示錯誤信息并退出函數(shù)。
(2)保存信息????? 當(dāng)打開文件成功后,就可以進(jìn)行寫入了,我們使用for循環(huán)進(jìn)行逐個寫入,使用fwrite寫入文件,信息源為聯(lián)系人列表,每次寫入一個聯(lián)系人信息所占的字節(jié)數(shù),每次寫入一個聯(lián)系人信息,寫入文件指針類型所指向的文件中。
(3)關(guān)閉文件???? 最后就是關(guān)閉文件了,使用fclose關(guān)閉文件,并將指針置空。
???? 每次使用文件指針后切記要關(guān)閉文件,并將指針置空,防止內(nèi)存訪問異常!
???? 函數(shù)代碼如下:
// contact.c
void SaveContact(Contact* pc)
{
// 打開文件
FILE* pf = fopen("contact.dat", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
// 寫文件
int i = 0;
for (i = 0; i< pc->sz; i++)
{
// 要寫入的信息來源為聯(lián)系人列表;每次寫入一個聯(lián)系人的信息大??;
// 每次寫入一個聯(lián)系人信息;寫入pf所指向的文件中
fwrite(pc->data+i, sizeof(PeoInfo), 1,pf);
}
// 關(guān)閉文件
fclose(pf);
pf = NULL;
}
2.打開程序時加載文件中的信息加載文件就是指讀取文件中的內(nèi)容到程序中,我們創(chuàng)建LoadContact函數(shù)用來讀取文件中的信息。
需要注意的是,我們應(yīng)該在程序初始化時讀取文件的內(nèi)容,而不是到用戶選擇功能時再進(jìn)行讀取。將讀取文件的函數(shù)放在初始化函數(shù)中。
// contact.c
void InitContact(Contact* pc)
{
...
LoadContact(pc);
}
(1)創(chuàng)建讀取函數(shù)???? a.讀取文件
???????????? 使用FILE類型指針指向使用fopen打開存放信息的文件"contact.dat",需要注意的是,這里應(yīng)當(dāng)使用"r"對文件進(jìn)行讀取。要記得進(jìn)行判斷是否打開成功~
(2)讀取信息??????????? 使用fread對信息進(jìn)行讀取,創(chuàng)建一個臨時的聯(lián)系人列表temp用來存放讀取得到的信息,并對temp進(jìn)行判斷:
????? 若讀取為0表示文件中沒有信息;
?????若讀取成功就將讀取的信息存放到程序中創(chuàng)建的通訊錄中,這時候文件中的聯(lián)系人數(shù)量可能會大于我們設(shè)置的默認(rèn)數(shù)量,需要判斷是否需要對容量進(jìn)行增加,我們使用CheckCapicaty函數(shù)進(jìn)行判斷。
// contact.c
void LoadContact(Contact* pc)
{
...
CheckCapacity(pc);
...
}
???? 具體的CheckCapacity函數(shù)在動態(tài)版本中已有寫明,可移步查看。
???? 我們將臨時列表中的信息存放到程序中的通訊錄中,使用while函數(shù)進(jìn)行判斷,當(dāng)讀取的信息不為空時,將聯(lián)系人信息逐條轉(zhuǎn)存到聯(lián)系人列表中,為空時就退出程序。
(3)關(guān)閉文件??????? 在讀取完成后,文件中的聯(lián)系人信息已被存至程序中的通訊錄中,直到退出通訊錄時才需要再次打開文件進(jìn)行寫入,故在完成讀取后需要關(guān)閉文件。
???? 函數(shù)代碼如下:
// contact.c
void LoadContact(Contact* pc)
{
FILE* pf = fopen("contact.dat", "r");
if (pf == NULL)
{
perror("LoadContact");
return;
}
// 讀文件
PeoInfo temp = { 0 };
while (fread(&temp, sizeof(PeoInfo), 1, pf))
{
// 是否需要增容
CheckCapacity(pc);
pc->data[pc->sz] = temp;
pc->sz++;
}
// 關(guān)閉文件
fclose(pf);
pf = NULL;
}
三、文件代碼?
??????? 1.contact.h#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
// 相關(guān)函數(shù)的聲明
// 一些類型的定義
#include#include#include#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TEL 15
#define MAX_ADDR 30
#define MAX 1000
#define DEFAULT_SZ 3
#define INC_SZ 2
// 聯(lián)系人的存放
// 使用typedef 定義結(jié)構(gòu)體類型,方便調(diào)用
typedef struct PeoInfo
{
char name[MAX_NAME]; // 姓名
char sex[MAX_SEX]; // 性別
int age; // 年齡
char tel[MAX_TEL]; // 電話
char addr[MAX_ADDR]; // 地址
}PeoInfo;
// 通訊錄
typedef struct Contact
{
PeoInfo* data; // 指向動態(tài)申請的空間,用來存放聯(lián)系人的信息
int sz; // 通訊錄中具體的聯(lián)系人數(shù)量
int capacity; // 記錄當(dāng)前通訊錄的大容量
}Contact;
// 初始化通訊錄
void InitContact(Contact* pc);
// 增加聯(lián)系人
void AddContact(Contact* pc);
// 打印聯(lián)系人
void PrintContact(const Contact* pc);
// 刪除聯(lián)系人
void DelContact(Contact* pc);
// 查找聯(lián)系人
void SearchContact(Contact* pc);
// 修改聯(lián)系人
void ModifyContact(Contact* pc);
// 排序聯(lián)系人
void SortContact(Contact* pc);
// 銷毀通訊錄
void DestorContact(Contact* pc);
// 保存通訊錄信息
void SaveContact(Contact* pc);
2.contact.c#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
// 具體的功能函數(shù)的實現(xiàn)
#include"contact.h"
// 保存信息到文件中
void SaveContact(Contact* pc)
{
// 打開文件
FILE* pf = fopen("contact.dat", "w");
if (pf == NULL)
{
perror("SaveContact");
return;
}
// 寫文件
int i = 0;
for (i = 0; i< pc->sz; i++)
{
// 要寫入的信息來源為聯(lián)系人列表;每次寫入一個聯(lián)系人的信息大??;
// 每次寫入一個聯(lián)系人信息;寫入pf所指向的文件中
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
// 關(guān)閉文件
fclose(pf);
pf = NULL;
}
// 判斷是否需要增容
void CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
if (ptr != NULL)
{
pc->data = ptr;
pc->capacity += INC_SZ;
printf("增容成功\n");
}
else
{
perror("AddContact");
printf("增加聯(lián)系人失敗\n");
return;
}
}
}
void LoadContact(Contact* pc)
{
FILE* pf = fopen("contact.dat", "r");
if (pf == NULL)
{
// 提示錯誤并返回
perror("LoadContact");
return;
}
// 讀取文件
PeoInfo temp = { 0 };
while (fread(&temp, sizeof(PeoInfo), 1, pf))
{
// 是否需要增容
CheckCapacity(pc);
pc->data[pc->sz] = temp;
pc->sz++;
}
// 關(guān)閉文件
fclose(pf);
pf = NULL;
}
// 文件版本-初始化通訊錄
void InitContact(Contact* pc)
{
pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
// 加載文件
LoadContact(pc);
}
// 動態(tài)版本——增加聯(lián)系人
void AddContact(Contact* pc)
{
// 判斷空間是否足夠
CheckCapacity(pc);
// 增加聯(lián)系人信息
printf("請輸入姓名:>");
scanf("%s", pc->data[pc->sz].name);
printf("請輸入性別:>");
scanf("%s", pc->data[pc->sz].sex);
printf("請輸入年齡:>");
// 變量需要使用&
scanf("%d", &pc->data[pc->sz].age);
printf("請輸入電話:>");
scanf("%s", pc->data[pc->sz].tel);
printf("請輸入地址:>");
scanf("%s", pc->data[pc->sz].addr);
// 使聯(lián)系人數(shù)量+1
pc->sz++;
printf("增加成功\n");
}
// 動態(tài)版本——銷毀通訊錄
void DestorContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->sz = 0;
pc->capacity = 0;
}
// 打印聯(lián)系人——加上const確保在函數(shù)內(nèi)部聯(lián)系人信息不會被改變
void PrintContact(const Contact* pc)
{
if (pc->sz == 0)
{
printf("通訊錄中無聯(lián)系人信息,無需打印\n");
return;
}
// 打印表頭
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n", "姓名", "性別", "年齡", "電話", "地址");
// 打印聯(lián)系人信息
int i = 0;
for (i = 0; i< pc->sz; i++)
{
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-10s\n",
pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tel,
pc->data[i].addr
);
}
printf("打印完成\n");
}
// 通過姓名查找聯(lián)系人
// 創(chuàng)建查找函數(shù),方便被刪除修改和查找時調(diào)用
// 使用static 使得此函數(shù)只能在本函數(shù)內(nèi)部被調(diào)用和查看
static int FindName(const Contact* pc, const char input_name[])
{
int i = 0;
for (i = 0; i< pc->sz; i++)
{
// strcmp的結(jié)果為0時是找到了對應(yīng)的姓名
if (strcmp(pc->data[i].name, input_name) == 0)
{
// 則返回對應(yīng)的聯(lián)系人信息下標(biāo)
return i;
}
}
// 找不到
return -1;
}
// 刪除聯(lián)系人
void DelContact(Contact* pc)
{
// 判斷通訊錄是否為空
if (pc->sz == 0)
{
printf("通訊錄為空,無需刪除\n");
return;
}
// 查找要刪除的人
char input_name[MAX_NAME];
printf("請輸入要刪除人的姓名:>");
scanf("%s", input_name);
// 設(shè)定ret判斷返回結(jié)果
int ret = FindName(pc, input_name);
// 當(dāng)查找失敗時
if (ret == -1)
{
printf("要刪除的人不存在\n");
return;
}
// 刪除后,將刪除聯(lián)系人之后的聯(lián)系人信息的下標(biāo)-1
int i = 0;
for (i = ret; i< pc->sz; i++)
{
pc->data[i] = pc->data[i + 1];
}
// 刪除成功后使聯(lián)系人數(shù)量減1
pc->sz--;
printf("刪除成功\n");
}
// 查找聯(lián)系人
void SearchContact(Contact* pc)
{
char find_name[MAX_NAME] = { 0 };
printf("請輸入查找的聯(lián)系人姓名:>");
scanf("%s", find_name);
int ret = FindName(pc, find_name);
if (ret == -1)
{
printf("查無此人\n");
return;
}
else
{
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n", "姓名", "性別", "年齡", "電話", "地址");
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-10s\n",
pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tel,
pc->data[ret].addr
);
printf("查找完畢\n");
}
}
// 修改聯(lián)系人
void ModifyContact(Contact* pc)
{
char input_name[MAX_NAME] = { 0 };
printf("請輸入要修改的聯(lián)系人的姓名:>");
scanf("%s", input_name);
int ret = FindName(pc, input_name);
if (ret == -1)
{
printf("查無此人,無法修改\n");
return;
}
printf("請輸入姓名:>");
scanf("%s", pc->data[ret].name);
printf("請輸入性別:>");
scanf("%s", pc->data[ret].sex);
printf("請輸入年齡:>");
// 變量需要使用&
scanf("%d", &pc->data[ret].age);
printf("請輸入電話:>");
scanf("%s", pc->data[ret].tel);
printf("請輸入地址:>");
scanf("%s", pc->data[ret].addr);
printf("修改完畢\n");
}
// 創(chuàng)建比較函數(shù)
int cmp_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
// 排序聯(lián)系人
void SortContact(Contact* pc)
{
// 判斷通訊錄是否為空
if (pc->sz == 0)
{
printf("通訊錄為空,無需排序\n");
return;
}
// 以姓名為排序依據(jù)進(jìn)行排序
// 使用qsort函數(shù)進(jìn)行排序——調(diào)用了創(chuàng)建的cmp_name()
// 待排序列地址、待排關(guān)鍵字個數(shù)、關(guān)鍵字大小、比較函數(shù)地址
qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_name);
printf("排序成功\n");
}
3.test.c#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
// 測試文件
// 文件版本
// 當(dāng)退出通訊錄時,將聯(lián)系人信息保存到文件中
// 當(dāng)打開通訊錄時,加載文件中的聯(lián)系人信息到程序中
//
#include"contact.h"
void menu()
{
printf("*******************\n");
printf("**** 1.add ****\n"); // 增加聯(lián)系人信息
printf("**** 2.del ****\n"); // 刪除聯(lián)系人信息
printf("**** 3.serach ****\n"); // 查找聯(lián)系人信息
printf("**** 4.modify ****\n"); // 修改聯(lián)系人信息
printf("**** 5.sort ****\n"); // 排序聯(lián)系人信息
printf("**** 6.print ****\n"); // 打印聯(lián)系人信息
printf("**** 0.exit ****\n"); // 退出通訊錄
printf("*******************\n");
}
// 使用枚舉,使得switch選擇時,更加明了
enum Menu
{
EXIT, // 默認(rèn)為 0
ADD, // 1
DEL,
SEARCH,
MODIFY,
SORT,
PRINT
};
int main() // 在靜態(tài)模式下會因為數(shù)據(jù)過多報警告
{
int input = 0;
// 創(chuàng)建通訊錄
Contact contact;
// 初始化通訊錄
InitContact(&contact);
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&contact);
break;
case DEL:
DelContact(&contact);
break;
case SEARCH:
SearchContact(&contact);
break;
case MODIFY:
ModifyContact(&contact);
break;
case SORT:
SortContact(&contact);
break;
case PRINT:
PrintContact(&contact);
break;
case EXIT:
// 保存信息到文件
SaveContact(&contact);
DestorContact(&contact);
printf("程序結(jié)束\n");
break;
default:
printf("選擇錯誤,請重新選擇:\n");
}
} while (input);
return 0;
}
四、注意事項1.在之前兩個版本中,有少許代碼無用,不影響功能的執(zhí)行,在當(dāng)前版本進(jìn)行了適當(dāng)優(yōu)化。
2.目前為止的三個版本分別對應(yīng)不同的C語言內(nèi)容,可根據(jù)自身學(xué)習(xí)進(jìn)度進(jìn)行實現(xiàn),做到先理解,再獨立完成。不要沒有學(xué)習(xí)對應(yīng)的內(nèi)容就進(jìn)行編寫,一口吃不成胖子,學(xué)習(xí)急不得。
3.通訊錄的編寫告一段落,日后若有新的想法或者更新,將會編寫相關(guān)的文章用來講述。
4.gitee鏈接
shiwuqing-Contact-3
?????
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧