婚戀網(wǎng)站的渠道網(wǎng)絡建設2024年新冠第三波癥狀分析
首先感謝上一篇博客的大佬們的點贊,非常感謝!!!
目錄
前言
一、需要添加的功能
1.增加保存數(shù)據(jù)函數(shù)——可以保存數(shù)據(jù)到文件中
主要邏輯:
注意事項:?
代碼實現(xiàn):?
2.修改初始化函數(shù)——新增載入數(shù)據(jù)模塊
主要邏輯:
注意事項:?
?代碼實現(xiàn):
二、完整的代碼實現(xiàn)
三、運行效果展示
前言
上一篇c語言實踐博文我們將靜態(tài)版的通訊錄改成動態(tài)版,彌補了空間固定的尷尬。但是這個版本的通訊錄還是不完整的。為什么呢?想想看,當我們運行程序,輸入信息,退出程序,再進入程序,之前的數(shù)據(jù)還在不在了?不在了。因為那些數(shù)據(jù)是臨時存儲在內(nèi)存中的,下次打開時已經(jīng)被清理了。所以,我們需要在退出通訊錄時,把數(shù)據(jù)存起來。在進入通訊錄時,把數(shù)據(jù)加載進內(nèi)存。
復習通訊錄前兩個版本請?zhí)鴤?#x1f447;:
C語言實踐——通訊錄(2)(動態(tài)版)
c語言實踐——通訊錄(1)(靜態(tài)版)
一、需要添加的功能
在程序已經(jīng)開始執(zhí)行的時候,通訊錄的增刪查改與之前邏輯一樣,不用修改。但是在對通訊錄進行操作之前,需要加載保存的數(shù)據(jù)的內(nèi)容;在退出通訊錄時,需要保存當前數(shù)據(jù)到文件中。
1.增加保存數(shù)據(jù)函數(shù)——可以保存數(shù)據(jù)到文件中
之前我們的代碼執(zhí)行邏輯為,當用戶選擇0時,先銷毀通訊錄釋放內(nèi)存,再退出。所以我們要在銷毀通訊錄之前加一個函數(shù)SaveContact,用來實現(xiàn)數(shù)據(jù)的保存。
主要邏輯:
- 打開文件。用fopen函數(shù)打開(或新建)一個文件,用文件指針接收。
- 寫入數(shù)據(jù)。使用fwrite函數(shù)將Data中的數(shù)據(jù)保存到文件中。
- 關閉文件。用fclose函數(shù)關閉文件。
注意事項:?
- 打開文件記得檢驗文件打開是否成功,若不成功,直接返回并打印錯誤信息。
- 寫入數(shù)據(jù)時可以直接用Data數(shù)組名加整數(shù)的方式來表示要寫入數(shù)據(jù)的指針。
- 關閉文件時最好將文件指針置為NULL。
代碼實現(xiàn):?
//保存通訊錄
void SaveContact(Contact* pc)
{//打開文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact::fopen");return;}//數(shù)據(jù)寫入int i = 0;for (i = 0; i < pc->size; i++){fwrite(pc->Data + i, sizeof(PeoInfo), 1, pf);}//關閉文件fclose(pf);pf = NULL;printf("保存成功\n");
}
2.修改初始化函數(shù)——新增載入數(shù)據(jù)模塊
按照之前的代碼邏輯,初始化時,要把大小,容量初始化為零,并為Data開辟一個空間。而現(xiàn)在,我們還需要將文件中的數(shù)據(jù)存載入Data指向的空間中。
主要邏輯:
- 初始化內(nèi)容。和前面的版本一樣,初始化變量,開辟內(nèi)存。
- 打開文件。用fopen函數(shù)打開保存的文件,用文件指針接收。
- 讀取數(shù)據(jù)。使用fread函數(shù)將文件中的數(shù)據(jù)讀取存放到Data指向的空間。
- 關閉文件。用fclose函數(shù)關閉文件。
注意事項:?
- 打開文件記得檢驗文件打開是否成功,若不成功,直接返回并打印錯誤信息。
- 讀取數(shù)據(jù)時可以先用臨時變量接收讀取內(nèi)容,接著檢查空間容量,如果足夠直接賦值,如果不夠要開辟空間后再賦值。
- 每次讀取數(shù)據(jù)不要忘記讓數(shù)據(jù)大小size自增。
- 關閉文件時最好將文件指針置為NULL。
- 如果檢查內(nèi)存函數(shù)的定義放在后面,不要忘記事先聲明。
?代碼實現(xiàn):
//文件版本初始化
static void CheckCapacity(Contact* pc);
void LoadContact(Contact* pc)
{//打開文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact::fopen");return;}//讀文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){CheckCapacity(pc);pc->Data[pc->size] = tmp;pc->size++;}//關閉文件fclose(pf);pf = NULL;printf("加載成功\n");
}
void InitContact(Contact* pc)
{pc->Data = (PeoInfo*)malloc(INIT_SIZE * sizeof(PeoInfo));if (pc->Data == NULL){printf("初始化通訊錄失敗:%s\n", strerror(errno));return;}pc->size = 0;pc->capacity = INIT_SIZE;//將文件中的數(shù)據(jù)加載到通訊錄中LoadContact(pc);
}
二、完整的代碼實現(xiàn)
通訊錄最終的文件版本的代碼在下面啦,有需自取。
contact.h
#include<stdlib.h>
#include<errno.h>#define MAX_NAME 15
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 5
#define ADD_SIZE 2
#define INIT_SIZE 4typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;typedef struct Contact
{PeoInfo* Data;int size;int capacity;
}Contact;void InitContact(Contact* pc);void ContactAdd(Contact* pc);void ShowContact(const Contact* pc);void ContactDel(Contact* pc);void ContactSearch(const Contact* pc);void ContactModify(Contact* pc);void ContactSort(Contact* pc);void DestroyContact(Contact* pc);void SaveContact(Contact* pc);void LoadContact(Contact* pc);
contact.c
#include "contact.h"static void CheckCapacity(Contact* pc);
void LoadContact(Contact* pc)
{//打開文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact::fopen");return;}//讀文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){CheckCapacity(pc);pc->Data[pc->size] = tmp;pc->size++;}//關閉文件fclose(pf);pf = NULL;printf("加載成功\n");
}
void InitContact(Contact* pc)
{pc->Data = (PeoInfo*)malloc(INIT_SIZE * sizeof(PeoInfo));if (pc->Data == NULL){printf("初始化通訊錄失敗:%s\n", strerror(errno));return;}pc->size = 0;pc->capacity = INIT_SIZE;//將文件中的數(shù)據(jù)加載到通訊錄中LoadContact(pc);
}void DestroyContact(Contact* pc)
{free(pc->Data);pc->Data = NULL;pc->size = 0;pc->capacity = 0;printf("釋放內(nèi)存\n");
}static void CheckCapacity(Contact* pc)
{if (pc->size == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->Data, (pc->capacity + 2) * sizeof(PeoInfo));if (ptr == NULL){printf("CheckCapacity:%s\n", strerror(errno));return;}pc->Data = ptr;pc->capacity += ADD_SIZE;printf("增容成功,當前容量:%d\n", pc->capacity);}
}void ContactAdd(Contact* pc)
{CheckCapacity(pc);printf("請輸入名字>:");scanf("%s", pc->Data[pc->size].name);printf("請輸入年齡>:");scanf("%d", &pc->Data[pc->size].age);printf("請輸入性別>:");scanf("%s", pc->Data[pc->size].sex);printf("請輸入電話>:");scanf("%s", pc->Data[pc->size].tele);printf("請輸入地址>:");scanf("%s", pc->Data[pc->size].addr);pc->size++;printf("添加成功\n");
}static int FindByName(const Contact* pc, char name[MAX_NAME])
{int i = 0;for (i = 0; i < pc->size; i++){ //如果能找到if (0 == strcmp(pc->Data[i].name, name)){return i;}}//找不到return -1;
}void ShowContact(const Contact* pc)
{int i = 0;printf("%-15s %-5s %-5s %-11s %-5s", "姓名", "年齡", "性別", "電話", "地址\n");for (i = 0; i < pc->size; i++){printf("%-15s %-5d %-5s %-11s %-5s\n", pc->Data[i].name,pc->Data[i].age,pc->Data[i].sex,pc->Data[i].tele,pc->Data[i].addr);}}void ContactDel(Contact* pc)
{//1.找到要刪除的數(shù)據(jù)下標char name[MAX_NAME];printf("請輸入要刪除的名字:>");scanf("%s", name);//如果找不到,提示后直接返回int pos = FindByName(pc,name);//按名字查找,找到了返回下標,找不到返回-1if (pos == -1){printf("找不到指定聯(lián)系人\n");return;}//2.找到了就刪除memmove(pc->Data + pos, pc->Data + pos + 1, (pc->size - 1 - pos)*sizeof(pc->Data[0]));pc->size--;printf("刪除成功\n");
}void ContactSearch(const Contact * pc)
{char name[MAX_NAME];printf("請輸入要查找的人的名字>:");scanf("%s", name);int pos = FindByName(pc, name);//按名字查找,找到了返回下標,找不到返回-1if (pos == -1){printf("找不到要查找的人\n");return;}printf("%-15s %-3s %-5s %-11s %-5s", "姓名", "年齡", "性別", "電話", "地址\n");printf("%-15s %-3d %-5s %-11s %-5s\n", pc->Data[pos].name,pc->Data[pos].age,pc->Data[pos].sex,pc->Data[pos].tele,pc->Data[pos].addr);
}void ContactModify(Contact* pc)
{//1.查找char name[MAX_NAME];printf("請輸入要修改的人的名字>:");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("找不到要修改的聯(lián)系人\n");return;}//修改printf("請輸入名字>:");scanf("%s", pc->Data[pos].name);printf("請輸入年齡>:");scanf("%d", &pc->Data[pos].age);printf("請輸入性別>:");scanf("%s", pc->Data[pos].sex);printf("請輸入電話>:");scanf("%s", pc->Data[pos].tele);printf("請輸入地址>:");scanf("%s", pc->Data[pos].addr);printf("修改成功\n");
}int cmp_by_name(void* e1, void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void ContactSort(Contact* pc)
{qsort(pc->Data, pc->size, sizeof(PeoInfo), cmp_by_name);printf("排序成功\n");
}//保存通訊錄
void SaveContact(Contact* pc)
{//打開文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact::fopen");return;}//數(shù)據(jù)寫入int i = 0;for (i = 0; i < pc->size; i++){fwrite(pc->Data + i, sizeof(PeoInfo), 1, pf);}//關閉文件fclose(pf);pf = NULL;printf("保存成功\n");
}
test.c
#include "contact.h"
void menu()
{printf("***************************\n");printf("***** 1.add *****\n");printf("***** 2.del *****\n");printf("***** 3.search *****\n");printf("***** 4.modify *****\n");printf("***** 5.show *****\n");printf("***** 6.sort *****\n");printf("***** 0.exit *****\n");printf("***************************\n");}
//使用枚舉類型,提高可讀性,比define更方便,
//define把字母替換成相應的數(shù)字,
//但是enum直接字母和數(shù)字完全相同
enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};int main()
{int input = 0;Contact con;//定義通訊錄//初始化通訊錄InitContact(&con);do{menu();printf("請選擇>:");scanf("%d", &input);switch (input){case ADD:ContactAdd(&con);break;case DEL:ContactDel(&con);break;case SEARCH:ContactSearch(&con);break;case MODIFY:ContactModify(&con);break;case SHOW:ShowContact(&con);break;case SORT:ContactSort(&con);break;case EXIT:SaveContact(&con);DestroyContact(&con);printf("退出通訊錄\n");break;default:printf("選擇非法,請重新選擇\n");break;}} while (input);return 0;
}
三、運行效果展示
首先創(chuàng)建文件(也可以不手動創(chuàng)建,因為fwrite函數(shù)會在最后創(chuàng)建出來,這里為了展示載入過程手動創(chuàng)建了文件。)
?選擇并新增信息。
?
?容量不夠自動擴容。
?保存文件并退出。
?
?再次進入通訊錄并展示。
?好啦,到目前位置,通訊錄就基本完整了。該有的內(nèi)容基本都有了。只不過實現(xiàn)的比較簡單,還有一些沒有細致考慮的東西,比如查找重名的問題無法解決。但是可以再新增函數(shù),實現(xiàn)其他方式的查找,多項查找都滿足才返回需要的數(shù)據(jù)的位置。這些不難,但是基本邏輯與FindByName函數(shù)類似,這里就不多講了(沒錯,是我太懶想摸魚)。
感謝大家的點贊關注,我會保持持續(xù)輸出,動力滿滿!