文章目錄
- 前言與生成結果
- 1.具體代碼實作(生成通訊錄,添加資訊并查重,列印通訊錄人的資訊)
- 第一階段測驗
- 2.具體代碼實作(通訊錄資訊查找,通訊錄人資訊的修改,動態通訊錄記憶體Free)
- 第二階段除錯
- 3.具體代碼實作(排序通訊錄人的資訊)
- 第三階段除錯
- 4.整體代碼框架的構建
- 5.具體代碼實作(保存通訊錄資訊,加載通訊錄,洗掉通訊錄的人或整體的資訊)
- 最后階段除錯!!!
- 6.全部代碼付下
- 7.小結
前言與生成結果


加載通訊錄表示將二進制檔案的資料匯入結構體中,
初始化通訊錄成功表示:成功的開辟了一塊動態的空間,
可以實作增刪查找,全部清空通訊錄,查重,保存功能,

在保存后會自動在桌面生成一個通訊錄文本,
1.具體代碼實作(生成通訊錄,添加資訊并查重,列印通訊錄人的資訊)
先考慮頭檔案
首先我們要宣告一個人的結構體
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDRESS 20
#define MAX_CAP 3
typedef struct people
{
char name[MAX_NAME];//姓名
int age;//年齡
char sex[MAX_SEX];//性別
char tele[MAX_TELE];//電話
char address[MAX_ADDRESS];//地址
}people;
之后我們還要定義一個通訊錄結構體
typedef struct contect
{
int sz;//當前通訊錄人數
people* data;//動態開辟的空間地址
int capacity;//最大容量
}contect;
注意:
如果有一個通訊錄結構體指標p,
p->有3種情況.
1.int sz;
2.int capacity;
3.一塊連續空間的地址,地址中放的都是people結構體的資料
所以我們可以知道
p->data[p->sz]與p->*(data+sz)相同找到了下標為sz的people結構體
具體陣列與指標的關系見
陣列與指標的關系
所以p->data[p->sz] . 就可以找到sz位置上的結構體上的不同資訊
在之后我們要列印一個選單,讓人可以選擇
void menu();
類似這樣

通過選擇不同的數字,執行不同的函式,
之后還要實作初始化 增刪,列印通訊錄的功能
void initcontect(contect* p);
void Addcontect(contect* p);
void Showcontect(contect* p);

我們不急去想接下來的功能,先把這些介面寫好,在.c檔案中寫下函式的實作
選單的列印沒什么好說的
void menu()
{
printf("|-----------------------|\n");
printf("| contact |\n");
printf("| 1.Add 2.Delete |\n");
printf("| 3.Search 4.Modify |\n");
printf("| 5.Show 6.Sort |\n");
printf("| 0.Exit |\n");
printf("|-----------------------|\n");
}
初始化通訊錄結構體
void initcontect(contect* p)
{
p->sz = 0;//起始資料為0
p->capacity = MAX_CAP;//之前宏定義過容量
p->data = (people*)malloc(3*sizeof(people));
//動態開辟一塊大小為3個people結構體大小的空間
if (p->data == NULL)
{
printf("通訊錄初始化失敗,請退出程式重試\n");
exit(1);
}
}
添加一個人的資訊
注意:
在添加人之后還要查重,萬一這個人我們之前就已經記錄過,就沒有必要在儲存她的資訊了,
所以我們要一個查重函式,和一個洗掉函式,檢查已有人的名字,當有相同的名字時,再自動把這個人刪掉,而姓名是字串strcmp()在遇到相同的字符時回傳非零值,所以可以用strcmp來實作
void Addcontect(contect* p)
{
int pos = -1;
if (p->sz == p->capacity)
//當現在的通訊錄人=最大容量時再次呼叫增加函式時增容
{
people* ptr =
(people*)realloc(p->data, (p->capacity + 2) * sizeof(people));
//每次增容2個people,也可以增加不同值,
if (ptr==NULL)
{
printf("記憶體不足,增容失敗\n");
}
else
{
p->data = ptr;
//realloc增容通訊錄結構體地址可能改變,
//詳情見realloc函式所以要重新獲得地址
p->capacity += 2;//增容后總大小增大,
printf("提示:通訊錄增容成功\n");
}
}//儲存人的資訊
printf("請輸入姓名:>\n");
scanf("%s",p->data[p->sz].name);
printf("請輸入年齡:>\n");
scanf("%d",&p->data[p->sz].age);
printf("請輸入性別:>\n");
scanf("%s",p->data[p->sz].sex);
printf("請輸入電話:>\n");
scanf("%s",p->data[p->sz].tele);
printf("請輸入地址:>\n");
scanf("%s",p->data[p->sz].address);
p->sz++;//儲存成功后現有大小加1
system("cls");
pos = search_name2(p->data[p->sz-1].name, p);
//當search_name2函式回傳-1,表示沒有重名
//當search_name2 回傳其他值表示重名
if (pos == -1)
{
printf("添加成功\n");
}
else
{
//發現重名,提示一下再自動把剛添加的人的資訊刪掉
printf("通訊錄中已經有此人\n");
dele_name2(p->sz,p);//洗掉函式
p->sz--;//大小-1
}
}
int search_name2(char name[], contect* ps)
{
for (int i = 0; i < ps->sz-1; i++)
{
if (strcmp(name, ps->data[i].name) == 0)
{
return i;//有重名回傳非0值
}
}
return -1;
}
void dele_name2(int p,contect* ps)
{
ps->data[p - 1] = ps->data[p];
//直接將要洗掉的位置后一位隨機值資料放在這一位,
//其實也可以不寫,直接將記錄當前通訊錄人數的size減少1就行,
}
void Showcontect(contect* p)
{
if (p->sz == 0)
{
system("cls");
printf("通訊錄為空\n");//當通訊錄為空時直接不列印
}
else
{
system("cls");
printf("%-15s\t %-5s\t %-5s\t %-12s\t %-20s\t\n",
//控制通訊錄的列印形式
"姓名","年齡","性別","電話","地址");
for (int i = 0; i < p->sz; i++)
{
printf("%-15s\t %-5d\t %-5s\t %-12s\t %-20s\t\n",
p->data[i].name,
p->data[i].age,p->data[i].sex,
p->data[i].tele,p->data[i].address);
}
}
}
第一階段測驗
寫到這里我們先開始測驗我們的代碼
把我們剛寫的函式再添加到頭檔案中
#pragma once//防止重復包含頭檔案
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDRESS 20
#define MAX_CAP 3
typedef struct people
{
char name[MAX_NAME];//姓名
int age;//年齡
char sex[MAX_SEX];//性別
char tele[MAX_TELE];//電話
char address[MAX_ADDRESS];//地址
}people;
typedef struct contect
{
int sz;//當前通訊錄人數
people* data;//動態開辟的空間地址
int capacity;//最大容量
}contect;
void menu();
void initcontect(contect* p);
void Addcontect(contect* p);
void Showcontect(contect* p);
void dele_name2(int p, contect* ps);
int search_name2(char name[], contect* ps);
在main函式中寫下測驗介面
#include"標頭.h"//包含自己寫的頭檔案
int main()
{
contect con;//生成通訊錄
initcontect(&con);//初始化通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Showcontect(&con);//列印通訊錄
return 0;
}

初始化通訊錄介面:

初始化成功

添加資訊介面:


再輸入相同的人的名字檢查,查重介面:

再添加3個不同人的資訊來檢查增容介面:

之后進入列印函式介面


清屏列印,沒有問題
之后我們就可以考慮接下來的功能了
2.具體代碼實作(通訊錄資訊查找,通訊錄人資訊的修改,動態通訊錄記憶體Free)
光有這些功能還不能稱為通訊錄
我們還要實作查找通訊錄人的功能,還要實作修改人資訊的功能,
修改人的資訊首先要查找到這個人的資訊所以我們先寫查找函式,
查找函式其實我們已經在之前寫過了,原理為之前的查重函式,只不過對找到的資訊處理不同而已,之前寫查重函式,找到相同的名字進行洗掉,查找函式找到相同函式進行列印,
其次查找函式還可以選擇通過名字查找,也可以選擇通過電話查找,我們再給它寫一個選單,
要新加兩個函式,一個是選單函式,一個是電話查找函式
void Searchcontect(contect*ps)
{
char name[20] = { 0 };
char tele[20] = { 0 };
int input = 0;
int pos = 0;
system("cls");
do
{
menu_search();
scanf("%d",&input);
switch (input)
{
case 1:
system("cls");
printf("請輸入你要查找人的名字\n");
scanf("%s",name);
pos = search_name2(name, ps);
if (pos == -1)
{
printf("你要找的名字不存在\n");
}
else
{
printf("%-15s\t%-4s\t%-5s\t%-12s\t%-20s\n",
"姓名", "年齡", "性別", "電話", "住址");
printf("%-15s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].address);
}
printf("\n");
printf("\n");
break;
case 2:
system("cls");
printf("請輸入你要查找人的電話號碼\n");
scanf("%s",tele);
pos = search_tele(tele, ps);
if (pos == -1)
{
printf("你要查找的電話號碼不存在\n");
}
else
{
printf("%-15s\t%-4s\t%-5s\t%-12s\t%-20s\n",
"姓名", "年齡", "性別", "電話", "住址");
printf("%-15s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].address);
}
printf("\n");
printf("\n");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
選單函式:
void menu_search()
{
printf("****1.通過名字查找****\n");
printf("****2.通過電話查找****\n");
printf("*****0.回傳上一步*****\n");
//回傳主函式的一個回圈相當于回傳
}
這里電話查找本質是字串,所以原理與名字查找相同:
找到相同的字串回傳非零,找不到字串回傳-1.
int search_tele(char tele[], contect* ps)
{
for (int i = 0; i < ps->sz; i++)
{
if (strcmp(tele, ps->data[i].tele) == 0)
{
return i;
}
}
return -1;
}
再把我們新寫的函式加到頭檔案中

之后我們再實作修改人資訊函式:
修改的時候我們先要查找人的資訊,如果找不到這個人就提示一下,找到了我們要選擇要修改的資訊
之后同樣,我們要給一個選單,選擇你要修改什么資訊
類似于



這里回傳上一步回傳到了輸入修改人的名字這一步,
查找函式選單;
void menu_modify()
{
printf("****1.通過名字查找****\n");
printf("****2.通過電話查找****\n");
printf("*****0.回傳上一步*****\n");
}
修改選單函式:
void menu_modify_option()
{
printf("****1.修改姓名****\n");
printf("****2.修改年齡****\n");
printf("****3.修改性別****\n");
printf("****4.修改電話****\n");
printf("****5.修改地址****\n");
printf("***0.回傳上一步***\n");
}
具體實作將用到兩個switch嵌套,
void Modifycontect(contect* ps)
{
char name[MAX_NAME] = { 0 };
char tele[MAX_TELE] = { 0 };
int pos = 0;
int input = 0;
do
{
menu_modify();//查找選單
scanf("%d",&input);
switch (input)
{
case 1://通過名字查找人
system("cls");
printf("請輸入你要修改人的名字\n");
scanf("%s", name);
pos = search_name2(name, ps);//第一階段寫過的查找名字函式
if (pos == -1)
{
printf("要修改的人不存在,請確定通訊錄資訊\n");
int i = 0;
printf("\n");
printf("是否需要回傳選單確認資訊 1.回傳 2.重新尋找\n");
scanf("%d",&i);
if(i == 1)
{
return;//回到主函式的switch中
}
}
else
{
int input2 = 0;
do
{
menu_modify_option();
scanf("%d",&input2);
switch (input2)
{
case 1:
printf("你要將原來的名字修改為\n");
scanf("%s",ps->data[pos].name);
system("cls");
break;
case 2:
printf("你要將原來的年齡改為\n");
scanf("%d",&ps->data[pos].age);
system("cls");
break;
case 3:
printf("你要將原來的性別改為\n");
scanf("%s",ps->data[pos].sex);
system("cls");
break;
case 4:
printf("你要將原來的電話改為\n");
scanf("%s",ps->data[pos].tele);
system("cls");
break;
case 5:
printf("你要將原來的地址改為\n");
scanf("%s",ps->data[pos].address);
system("cls");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input2);
}
break;
case 2://通過電話查找人
system("cls");
printf("請輸入你要修改人的電話號碼\n");
scanf("%s", tele);
pos = search_tele(tele, ps);//前面實作過此函式
if (pos == -1)
{
printf("要修改的人不存在,請確定通訊錄資訊\n");
int i = 0;
printf("\n");
printf("是否需要回傳選單確認資訊 1.回傳 2.重新尋找\n");
scanf("%d", &i);
if (i == 1)
{
return;
}
}
else
{
int input2 = 0;
do
{
menu_modify_option();
scanf("%d", &input2);
switch (input2)
{
case 1:
printf("你要將原來的名字修改為\n");
scanf("%s", ps->data[pos].name);
system("cls");
break;
case 2:
printf("你要將原來的年齡改為\n");
scanf("%d", &ps->data[pos].age);
system("cls");
break;
case 3:
printf("你要將原來的性別改為\n");
scanf("%s", ps->data[pos].sex);
system("cls");
break;
case 4:
printf("你要將原來的電話改為\n");
scanf("%s", ps->data[pos].tele);
system("cls");
break;
case 5:
printf("你要將原來的地址改為\n");
scanf("%s", ps->data[pos].address);
system("cls");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input2);
}
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
因為我們動態通訊錄空間是malloc的就自然而然想到Free防止記憶體泄漏
void Deletinformation(contect* p)
{
free(p->data);//釋放空間
p->data= NULL;//指標指空
p->sz = 0;//通訊錄現有大小為0;
}
寫完后我們將函式放在頭檔案宣告一下我們寫過的函式:

第二階段除錯
在main函式中添加
#include"標頭.h"//包含你寫的頭檔案名字!!!
int main()
{
contect con;//生成通訊錄;
initcontect(&con);//初始化通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Searchcontect(&con);//查找已經存在的人;
Searchcontect(&con);//查找不存在的人;
Modifycontect(&con);//修改不存在的人;
Modifycontect(&con);//修改存在人的姓名;
Showcontect(&con);//列印修改后的通訊錄;
Modifycontect(&con);//修改存在人的地址;
Showcontect(&con);
//類似測驗修改的其他功能是否正常
Deletinformation(&con);
return 0;
}




查找介面沒有問題,


修改不存在人正常



修改之后的資訊,修改介面正常


銷毀通訊錄介面正常
至此我們通訊錄都可以正常作業,
3.具體代碼實作(排序通訊錄人的資訊)
我們在實作了通訊錄的增加,修改,查找,查重功能后,我們還想要排序一下通訊錄人的資訊,這里選擇用qsort排序
void Sortcontect(contect* ps)
{
qsort(ps->data,ps->sz,sizeof(people), CmpByName);
//要排序data空間,排序大小,每一個資料的大小是結構體people大小,函式指標
system("cls");
printf("排序成功\n");
}
這里要寫一個函式指標,也是非常簡單
int CmpByName(const void* e1, const void* e2)
{
return strcmp((const char*)e1, (const char*)e2);
}
qsort函式的用法
在頭檔案包含一下寫的排序函式

第三階段除錯
在main函式中
#include"標頭.h"//包含自己的頭檔案!!!!
int main()
{
contect con;//生成通訊錄;
initcontect(&con);//初始化通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Addcontect(&con);//添加通訊錄;
Showcontect(&con);//列印添加前的通訊錄
Sortcontect(&con);//排序
Showcontect(&con);//列印排序后的通訊錄
Deletinformation(&con);//釋放記憶體
return 0;
}
排序前:


排序后:

排序介面完成
4.整體代碼框架的構建
通訊錄的功能大體實作了,這里我們大體構建一下通訊錄資訊的基本框架
并且選擇不同數字對應不同的介面
為了方便我們書寫代碼,這里在頭檔案中定義列舉型別,
enum option
{
Exit,//數值為0對應選單中的0退出
Add,//1
Delete,//2
Search,//3
Modify,//4
Show,//5
Sort,//6
Save,//7
};
在main函式中
int main()
{
int input = 0;
int input2 = 0;
contect con;//創建通訊錄
initcontect(&con);//初始化通訊錄
do//回圈執行介面,直到輸入0時退出
{
menu();//列印基本選單
scanf("%d",&input);
//因為主函式是一個switch句
//所以之前設計的函式回傳上一步選項都會回到主函式這里,不在贅述
switch (input)
{
case Add://Add數值大小為1
Addcontect(&con);//加法介面
break;
case Delete:
Deletecontect(&con);//洗掉介面,我們目前沒有寫
break;
case Search:
Searchcontect(&con);//查找介面
break;
case Modify:
Modifycontect(&con);//修改介面
break;
case Show:
Showcontect(&con);//列印介面
break;
case Sort:
Sortcontect(&con);//排序介面
break;
case Save:
Savecontect(&con);//保存介面,我們目前沒有寫
system("cls");
printf("保存成功\n");
break;
case Exit://退出
system("cls");
printf("退出通訊錄后,如不保存資料會丟失,請先保存再退出\n");//提示用戶保存
printf("1.退出 0.取消退出\n");
scanf("%d",&input2);
if (input2 == 0)
{
system("cls");
input = 1;//如果取消退出了把input改成非零就行
printf("取消退出成功\n");
}
else
{
Deletinformation(&con);//繼續退出的話銷毀申請的空間
system("cls");
printf("退出通訊錄成功\n");
}
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
return 0;
}
5.具體代碼實作(保存通訊錄資訊,加載通訊錄,洗掉通訊錄的人或整體的資訊)
我們首先來實作保存通訊錄功能,
void Savecontect(contect*ps)
{
FILE* pf = fopen("contect.data", "wb");
//以二進制的寫的形式打開contect.data檔案,
//如果沒有此檔案,會自己自動創建
if (pf == NULL)
{
printf("記憶體不足,保存失敗\n");
return;
}
//用回圈的方式以二進制形式寫入pf檔案指標指向的檔案
for (int i = 0; i < ps->sz; i++)
{
//這四個引數分別為
//要寫資料的地址,每一個資料的大小,每次寫幾個資料,寫到檔案
fwrite(&(ps->data[i]),sizeof(people),1,pf);
}
fclose(pf);//關閉檔案
pf = NULL;//檔案指標置空
printf("保存成功\n");
}
那么我們保存到檔案中的資訊在下次打開通訊錄的時候要加載,所以我們要對初始化通訊錄函式做調整
先寫出加載函式
加載時要判斷是否要擴容
void LodeContact(contect* p)
{
FILE* pf = fopen("contect.data", "rb");
//以二進制讀的方式打開檔案contect.data
//如果沒有此檔案會回傳空指標
if (pf == NULL)
{
printf("加載通訊錄失敗\n");
//說明沒有這個檔案,沒有資料可以加載
return;
}
//創建一個臨時的people結構體變數
//將檔案的一個資料先放到臨時的變數中
people tmp = {0};
//fread函式會回傳讀取的讀取資料的個數
//所以用while回圈每次讀取一個people結構體
//當讀取不到資料的時候回傳0,停止回圈,
//fread函式的引數為
//讀到的資料放到哪里,每一個資料的大小,一次讀幾個資料,從哪里讀
while (fread(&tmp, sizeof(people), 1, pf))
{
CheckCapacity(p);//每一次都要檢查是否要擴容
p->data[p->sz] = tmp;
//把臨時的通訊錄資料放到,我們在main函式創建的通訊錄
p->sz++;//通訊錄的大小增加1,
}
fclose(pf);//關閉檔案
pf = NULL;//檔案指標置空
}
我們發現我們還要設計一個檢查是否要增容的函式
發現這個函式實作思想與我們寫的Addcontect(&con)函式相類似
void CheckCapacity(contect* p)
{
if (p->sz == p->capacity)
//如果現有的容量=最大大小下一次呼叫會擴容
{
people* ptr =
(people*)realloc(p->data, (p->capacity + 2) * sizeof(people));
if (ptr == NULL)
{
printf("記憶體不足,增容失敗\n");
}
else
{
p->data = ptr;
p->capacity += 2;
printf("提示:通訊錄增容成功\n");
}
}
}
之前我們也使用過這種檢查是否要擴容的片段可以寫成函式來減少代碼長度,
同時要修改初始化函式
void initcontect(contect* p)
{
p->sz = 0;
p->capacity = MAX_CAP;
p->data = (people*)malloc(3*sizeof(people));
if (p->data == NULL)
{
printf("通訊錄初始化失敗,請退出程式重試\n");
exit(1);
}
LodeContact(p);//初始化成功后呼叫加載資訊函式
printf("初始化通訊錄成功!\n");
}
最后我們來實作洗掉人資料的函式
洗掉要有兩種洗掉
1.洗掉一個人的資訊,
查找人的資訊,后再洗掉,同樣我們要給一個選單,
洗掉的原理是資料覆寫,并將表示通訊錄現有人數的size-1就行,
2.洗掉通訊錄整體所有人的資訊
洗掉所有人的資訊利用了 fopen函式
fopen函式以二進制寫的方式再一次打開時會洗掉之前檔案已經寫好的資訊,我們只要再free掉之前申請的空間,并且將記錄通訊錄大小的size改成0就ok了
代碼與之前的相同,不在贅述,
void Deletecontect(contect* p)
{
int input = 0;
int input2 = 0;
int pos = 0;
char name[10] = { 0 };
char tele[20] = { 0 };
system("cls");
do
{
menu_deleat();//列印洗掉的選單
scanf("%d",&input);
switch (input)
{
case 1:
printf("請輸入你要洗掉的人名字\n");
scanf("%s",name);
pos= search_name2(name,p);
if (pos == -1)
{
printf("要洗掉的名字不存在\n");
printf("\n");
}
else
{
printf("洗掉成功\n");
int j = 0;
for (j = pos; j < p->sz - 1; j++)
{
p->data[pos] = p->data[pos + 1];
}
p->sz--;
}
break;
case 2:
printf("請輸入你要洗掉的人的電話號碼\n");
scanf("%s", tele);
pos = search_tele(tele, p);
if (pos == -1)
{
printf("要洗掉的電話號碼不存在\n");
printf("\n");
}
else
{
printf("洗掉成功\n");
int j = 0;
for(j = pos; j < p->sz - 1; j++)
{
p->data[pos] = p->data[pos + 1];
//把后一個的值賦給前一個
}
p->sz--;
}
break;
case 3:
printf("你確定要全部洗掉通訊錄嗎? 1.確定 2.回到上一步\n");
scanf("%d",&input2);
if (input2 == 2);
else
{
FILE* pf = fopen("contect.data", "wb");
//再打開一次檔案但是不寫,相當于清空了檔案的內容
Deletinformation(p);//釋放空間
system("cls");
return;
}
break;
case 0:
system("cls");
printf("回傳成功\n");
return;
break;
default:
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
列印洗掉選單
void menu_deleat()
{
printf("****1.通過名字洗掉****\n");
printf("****2.通過電話洗掉****\n");
printf("***** 3.全部洗掉*****\n");
printf("*****0.回傳上一步*****\n");
}
最后不要忘了在頭檔案宣告一下我們寫的函式,以及我們所宣告的列舉型別

最后階段除錯!!!
因為之前的介面已經除錯過,只用檢查,保存,洗掉,加載介面即可

開始因為沒有contect.data檔案所以顯示加載通訊錄失敗

添加一個人的資訊并列印,
點擊保存生成一個contect檔案

再關閉檔案后點開記事本已經存入資料


再點開生成的可執行程式,因為已經有了contect.data且有資料所以顯示初始化成功
直接列印通訊錄·的內容發現內容加載成功

全部洗掉后,

記事本變空

至此,我們的通訊錄就寫完了,
6.全部代碼付下
save_contect.h
#define _CRT_SECURE_NO_WARNINGS 1//vs2019防止報錯
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDRESS 20
//#define MAX 1000 //鎖定通訊錄大小為1000個
#define MAX_CAP 3
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<string.h>
enum option
{
Exit,
Add,
Delete,
Search,
Modify,
Show,
Sort,
Save,
};
typedef struct people
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char address[MAX_ADDRESS];
}people;
typedef struct contect
{
int sz;
people* data;
int capacity;
}contect;
void menu();
void initcontect(contect* p);
void Addcontect(contect* p);
void Showcontect(contect* p);
void Deletecontect(contect* p);
void menu_search();
int search_name(char name[], contect* ps);
int search_tele(char tele[], contect* ps);
int search_name2(char name[], contect* ps);
void dele_name2(int p,contect* ps);
void Searchcontect(contect* ps);
void Modifycontect(contect* ps);
void menu_modify();
void menu_modify_option();
void Sortcontect(contect* ps);
int CmpByName(const void* e1, const void* e2);
void Deletinformation(contect*ps);
void Savecontect(contect*ps);
void CheckCapacity(contect* ps);
void LodeContact(contect* ps);
save_test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"save_contect.h"
int main()
{
int input = 0;
int input2 = 0;
contect con;
initcontect(&con);
do
{
menu();
scanf("%d",&input);
switch (input)
{
case Add:
Addcontect(&con);
break;
case Delete:
Deletecontect(&con);
break;
case Search:
Searchcontect(&con);
break;
case Modify:
Modifycontect(&con);
break;
case Show:
Showcontect(&con);
break;
case Sort:
Sortcontect(&con);
break;
case Save:
Savecontect(&con);
system("cls");
printf("保存成功\n");
break;
case Exit:
system("cls");
printf("退出通訊錄后,如不保存資料會丟失,請先保存再退出\n");
printf("1.退出 0.取消退出\n");
scanf("%d",&input2);
if (input2 == 0)
{
system("cls");
input = 1;
printf("取消退出成功\n");
}
else
{
Deletinformation(&con);
system("cls");
printf("退出通訊錄成功\n");
}
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
return 0;
}
save_contect.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"save_contect.h"
void menu()
{
printf("|-----------------------|\n");
printf("| contact |\n");
printf("| 1.Add 2.Delete |\n");
printf("| 3.Search 4.Modify |\n");
printf("| 5.Show 6.Sort |\n");
printf("| 0.Exit 7.Save |\n");
printf("|-----------------------|\n");
}
void menu_deleat()
{
printf("****1.通過名字洗掉****\n");
printf("****2.通過電話洗掉****\n");
printf("***** 3.全部洗掉*****\n");
printf("*****0.回傳上一步*****\n");
}
void menu_search()
{
printf("****1.通過名字查找****\n");
printf("****2.通過電話查找****\n");
printf("*****0.回傳上一步*****\n");
}
void menu_modify()
{
printf("****1.通過名字查找****\n");
printf("****2.通過電話查找****\n");
printf("*****0.回傳上一步*****\n");
}
void menu_modify_option()
{
printf("****1.修改姓名****\n");
printf("****2.修改年齡****\n");
printf("****3.修改性別****\n");
printf("****4.修改電話****\n");
printf("****5.修改地址****\n");
printf("***0.回傳上一步***\n");
}
void initcontect(contect* p)
{
p->sz = 0;
p->capacity = MAX_CAP;
p->data = (people*)malloc(3*sizeof(people));
if (p->data == NULL)
{
printf("通訊錄初始化失敗,請退出程式重試\n");
exit(1);
}
LodeContact(p);
printf("初始化通訊錄成功!\n");
}
void CheckCapacity(contect* p)
{
if (p->sz == p->capacity)
{
people* ptr = (people*)realloc(p->data, (p->capacity + 2) * sizeof(people));
if (ptr == NULL)
{
printf("記憶體不足,增容失敗\n");
}
else
{
p->data = ptr;
p->capacity += 2;
printf("提示:通訊錄增容成功\n");
}
}
}
void Addcontect(contect* p)
{
int pos = -1;
CheckCapacity(p);
printf("請輸入姓名:>\n");
scanf("%s",p->data[p->sz].name);
printf("請輸入年齡:>\n");
scanf("%d",&p->data[p->sz].age);
printf("請輸入性別:>\n");
scanf("%s",p->data[p->sz].sex);
printf("請輸入電話:>\n");
scanf("%s",p->data[p->sz].tele);
printf("請輸入地址:>\n");
scanf("%s",p->data[p->sz].address);
p->sz++;
system("cls");
pos = search_name2(p->data[p->sz-1].name, p);
if (pos == -1)
{
printf("添加成功\n");
}
else
{
printf("通訊錄中已經有此人\n");
dele_name2(p->sz,p);
p->sz--;
}
}
void Showcontect(contect* p)
{
if (p->sz == 0)
{
system("cls");
printf("通訊錄為空\n");
}
else
{
system("cls");
printf("%-15s\t %-5s\t %-5s\t %-12s\t %-20s\t\n", "姓名","年齡","性別","電話","地址");
for (int i = 0; i < p->sz; i++)
{
printf("%-15s\t %-5d\t %-5s\t %-12s\t %-20s\t\n",p->data[i].name,
p->data[i].age,p->data[i].sex,p->data[i].tele,p->data[i].address);
}
}
}
int search_name2(char name[], contect* ps)
{
for (int i = 0; i < ps->sz-1; i++)
{
if (strcmp(name, ps->data[i].name) == 0)
{
return i;
}
}
return -1;
}
int search_name(char name[], contect* ps)
{
for (int i = 0; i < ps->sz; i++)
{
if (strcmp(name, ps->data[i].name) == 0)
{
return i;
}
}
return -1;
}
int search_tele(char tele[], contect* ps)
{
for (int i = 0; i < ps->sz; i++)
{
if (strcmp(tele, ps->data[i].tele) == 0)
{
return i;
}
}
return -1;
}
void dele_name2(int p,contect* ps)
{
ps->data[p - 1] = ps->data[p];
}
void Deletecontect(contect* p)
{
int input = 0;
int input2 = 0;
int pos = 0;
char name[10] = { 0 };
char tele[20] = { 0 };
system("cls");
do
{
menu_deleat();
scanf("%d",&input);
switch (input)
{
case 1:
printf("請輸入你要洗掉的人名字\n");
scanf("%s",name);
pos= search_name2(name,p);
if (pos == -1)
{
printf("要洗掉的名字不存在\n");
printf("\n");
}
else
{
printf("洗掉成功\n");
int j = 0;
for (j = pos; j < p->sz - 1; j++)
{
p->data[pos] = p->data[pos + 1];
}
p->sz--;
}
break;
case 2:
printf("請輸入你要洗掉的人的電話號碼\n");
scanf("%s", tele);
pos = search_tele(tele, p);
if (pos == -1)
{
printf("要洗掉的電話號碼不存在\n");
printf("\n");
}
else
{
printf("洗掉成功\n");
int j = 0;
for(j = pos; j < p->sz - 1; j++)
{
p->data[pos] = p->data[pos + 1];
}
p->sz--;
}
break;
case 3:
printf("你確定要全部洗掉通訊錄嗎? 1.確定 2.回到上一步\n");
scanf("%d",&input2);
if (input2 == 2);
else
{
FILE* pf = fopen("contect.data", "wb");
Deletinformation(p);
system("cls");
return;
}
break;
case 0:
system("cls");
printf("回傳成功\n");
return;
break;
default:
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
void Searchcontect(contect*ps)
{
char name[20] = { 0 };
char tele[20] = { 0 };
int input = 0;
int pos = 0;
system("cls");
do
{
menu_search();
scanf("%d",&input);
switch (input)
{
case 1:
system("cls");
printf("請輸入你要查找人的名字\n");
scanf("%s",name);
pos = search_name(name, ps);
if (pos == -1)
{
printf("你要找的名字不存在\n");
}
else
{
printf("%-15s\t%-4s\t%-5s\t%-12s\t%-20s\n", "姓名", "年齡", "性別", "電話", "住址");
printf("%-15s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].address);
}
printf("\n");
printf("\n");
break;
case 2:
system("cls");
printf("請輸入你要查找人的電話號碼\n");
scanf("%s",tele);
pos = search_tele(tele, ps);
if (pos == -1)
{
printf("你要查找的電話號碼不存在\n");
}
else
{
printf("%-15s\t%-4s\t%-5s\t%-12s\t%-20s\n", "姓名", "年齡", "性別", "電話", "住址");
printf("%-15s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].address);
}
printf("\n");
printf("\n");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
void Modifycontect(contect* ps)
{
char name[MAX_NAME] = { 0 };
char tele[MAX_TELE] = { 0 };
int pos = 0;
int input = 0;
do
{
menu_modify();
scanf("%d",&input);
switch (input)
{
case 1:
system("cls");
printf("請輸入你要修改人的名字\n");
scanf("%s", name);
pos = search_name(name, ps);
if (pos == -1)
{
printf("要修改的人不存在,請確定通訊錄資訊\n");
int i = 0;
printf("\n");
printf("是否需要回傳選單確認資訊 1.回傳 2.重新尋找\n");
scanf("%d",&i);
if(i == 1)
{
return;
}
}
else
{
int input2 = 0;
do
{
menu_modify_option();
scanf("%d",&input2);
switch (input2)
{
case 1:
printf("你要將原來的名字修改為\n");
scanf("%s",ps->data[pos].name);
system("cls");
break;
case 2:
printf("你要將原來的年齡改為\n");
scanf("%d",&ps->data[pos].age);
system("cls");
break;
case 3:
printf("你要將原來的性別改為\n");
scanf("%s",ps->data[pos].sex);
system("cls");
break;
case 4:
printf("你要將原來的電話改為\n");
scanf("%s",ps->data[pos].tele);
system("cls");
break;
case 5:
printf("你要將原來的地址改為\n");
scanf("%s",ps->data[pos].address);
system("cls");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input2);
}
break;
case 2:
system("cls");
printf("請輸入你要修改人的電話號碼\n");
scanf("%s", tele);
pos = search_tele(tele, ps);
if (pos == -1)
{
printf("要修改的人不存在,請確定通訊錄資訊\n");
int i = 0;
printf("\n");
printf("是否需要回傳選單確認資訊 1.回傳 2.重新尋找\n");
scanf("%d", &i);
if (i == 1)
{
return;
}
}
else
{
int input2 = 0;
do
{
menu_modify_option();
scanf("%d", &input2);
switch (input2)
{
case 1:
printf("你要將原來的名字修改為\n");
scanf("%s", ps->data[pos].name);
system("cls");
break;
case 2:
printf("你要將原來的年齡改為\n");
scanf("%d", &ps->data[pos].age);
system("cls");
break;
case 3:
printf("你要將原來的性別改為\n");
scanf("%s", ps->data[pos].sex);
system("cls");
break;
case 4:
printf("你要將原來的電話改為\n");
scanf("%s", ps->data[pos].tele);
system("cls");
break;
case 5:
printf("你要將原來的地址改為\n");
scanf("%s", ps->data[pos].address);
system("cls");
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input2);
}
break;
case 0:
system("cls");
printf("回傳成功\n");
break;
default:
system("cls");
printf("選擇錯誤,請重新選擇\n");
break;
}
} while (input);
}
int CmpByName(const void* e1, const void* e2)
{
return strcmp((const char*)e1, (const char*)e2);
}
void Sortcontect(contect* ps)
{
qsort(ps->data,ps->sz,sizeof(people), CmpByName);
system("cls");
printf("排序成功\n");
}
void Deletinformation(contect* p)
{
free(p->data);
p->data= NULL;
p->sz = 0;
}
void Savecontect(contect*ps)
{
FILE* pf = fopen("contect.data", "wb");
if (pf == NULL)
{
printf("記憶體不足,保存失敗\n");
return;
}
for (int i = 0; i < ps->sz; i++)
{
fwrite(&(ps->data[i]),sizeof(people),1,pf);
}
fclose(pf);
pf = NULL;
printf("保存成功\n");
}
void LodeContact(contect* p)
{
FILE* pf = fopen("contect.data", "rb");
if (pf == NULL)
{
printf("加載通訊錄失敗\n");
return;
}
people tmp = {0};
while (fread(&tmp, sizeof(people), 1, pf))
{
CheckCapacity(p);
p->data[p->sz] = tmp;
p->sz++;
}
fclose(pf);
pf = NULL;
}
7.小結
學校的c語言,圖書管理系統,學生成績系統,等等八九不離十,
我寫這篇文章的目的是梳理我寫這些題的程序與思路,所以代碼可能有些冗余,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271611.html
標籤:其他
上一篇:Python 編程1000例(15):查找演算法——折半查找演算法
下一篇:教你速成指標進階
