編寫xx管理系統,內有指導教程!
建議大家做xx管理系統的時候按本文的方法來做,一開始可能會覺得有些啰嗦,沒必要,但是當你程序越寫越長的時候你會感受到好處的。
想要一起學習C++的可以加裙六二六八七一九一六,裙內有各種資料滿足大家,歡迎加裙
一、數據結構抽象化
大家現在做的xx管理統應該都是基於鏈表的,以往看到很多版本的xx管理系統,都是鏈表管理和數數據處理揉合在一起的。我不知道你們怎麼想,反正我是一看到各種next指針就頭疼,再放到繁雜的數據處理中,寫起來固然頭痛,要是再出個什麼bug的就更悲劇了。
其實我想你們老師應該都有講過,其實鏈表的操作無非就是創建/插入/刪除/遍歷/銷毀幾種簡單的操作,但為什麼一放到數據處理中就往往讓我們頭痛呢?其實這和人一樣,我們專心做一件事時往往完成得很好,但同時做兩件事,一心二用,就必然手忙腳亂了。所以在設計階段我們就應該把鏈表管理和數據處理分開,也就是把鏈表從具體的數據邏輯中「抽象」出來。其實這也就是設計模式中的「一個模塊只處理一件事」的原則。
抽象鏈表的一個重要技巧就是把鏈表結點中存放具體數據的數據域用兩個特徵量(void* data; int len)來表示,因為我們的鏈表應該完全和具體的數據處理無關,所以我們也不必知道結點中存放的是什麼數據,只要知道數據塊的頭指針和數據長度,能夠進行賦值操作就足夠了。在我的示範代碼中,data存放在結點struct中,len存放在整個鏈表的結構中,因為一般情況下每個結點的數據len都是相同的(同一類數據),所以len統一存放在鏈表結構中就行了。
以下是示範代碼,在代碼中我們可以看到在鏈表管理的部分我們完全沒有出現具體數據的影子,也就是編寫這部分代碼的時候一心想著鏈表就行了;而在main()的具體數據處理部分中則完全沒有出現鏈表的具體操作,不用處理麻煩的next指針之類的東西。這樣一來兩部分代碼的編寫都能一心一意,減少了出錯的可能,調試的時候也方便。
想要一起學習C++的可以加裙六二六八七一九一六,裙內有各種資料滿足大家,歡迎加裙
#include
#include
#include
// 鏈表結點結構,貯存鏈表中的一個結點
typedef struct list_node_type_struct
{
void* m_data; // 抽象的數據域,void*的類形使得我們的鏈表可以貯存任何類型的數據
struct list_node_type_struct* m_prev;
struct list_node_type_struct* m_next;
} list_node_type;
// 鏈表結構,貯存整個鏈表
typedef struct list_type_struct
{
size_t m_item_size; // 結點中數據域的大小
size_t m_list_size; // 鏈表元素個數
struct list_node_type_struct m_head; // 不存放數據的頭結點
} list_type;
list_type* list_create(size_t item_size)
{
list_type* new_list = malloc(sizeof(list_type)); // 為了簡單就不做異常檢測了
// 建立一個空的鏈表
new_list->m_list_size = 0;
new_list->m_item_size = item_size;
new_list->m_head.m_next = &new_list->m_head; // 空的鏈表
new_list->m_head.m_prev = &new_list->m_head;
return new_list;
}
list_node_type* list_insert(list_type* list, list_node_type* node, void* data)
{
list_node_type* new_node = malloc(sizeof(list_node_type));
new_node->m_data = malloc(list->m_item_size);
memcpy(new_node->m_data, data, list->m_item_size); // 將data賦值給新結點
// 在node結點之前插入新結點,如果node為null的話就默認在鏈表尾部插入
if(!node)
{
return list_insert(list, &list->m_head, data); // 尾部插入
}
else
{
new_node->m_next = node; // node結點之前插入
new_node->m_prev = node->m_prev;
new_node->m_next->m_prev = new_node;
new_node->m_prev->m_next = new_node;
}
list->m_list_size += 1;
return new_node;
}
void list_remove(list_type* list, list_node_type* node)
{
// 刪除結點
node->m_next->m_prev = node->m_prev;
node->m_prev->m_next = node->m_next;
free(node->m_data);
free(node);
list->m_list_size -= 1;
return;
}
// 一組鏈表的遍歷函數
list_node_type* list_head(list_type* list) { return list->m_list_size > 0 ? list->m_head.m_next : NULL; }
list_node_type* list_tail(list_type* list) { return list->m_list_size > 0 ? list->m_head.m_prev : NULL; }
list_node_type* list_next(list_type* list, list_node_type* node) { return node != list->m_head.m_prev ? node->m_next : NULL; }
list_node_type* list_prev(list_type* list, list_node_type* node) { return node != list->m_head.m_next ? node->m_prev : NULL; }
void list_destroy(list_type* list)
{
// 銷毀整個鏈表
while(list->m_list_size > 0)
list_remove(list, list->m_head.m_next);
free(list);
return;
}
// 以下是示範程序
int main()
{
// 示範一:讀入5個數存入鏈表,再列印出來
{
list_type* list;
list_node_type* node;
int i;
int data;
list = list_create(sizeof(int)); // 創建鏈表
for(i = 0; i
{
// 輸入數據
printf("input the %d th number", i + 1);
scanf("%d", &data);
list_insert(list, NULL, &data);
}
for(node = list_head(list); node != NULL; node = list_next(list, node))
{
// 輸出數據
printf("%d", *(int*)node->m_data);
}
list_destroy(list); // 炸毀整個鏈表
}
// 示範二:讀入5個學生姓名和成績,刪除第4個,再列印出來
{
typedef struct student_info_type_struct
{
char m_name[16];
int m_score;
} student_info_type;
student_info_type data;
list_type* list;
list_node_type* node;
int i;
list = list_create(sizeof(student_info_type)); // 創建鏈表
for(i = 0; i
{
// 輸入數據
printf("input name and score of %d th student", i + 1);
scanf("%s%d", data.m_name, &data.m_score);
list_insert(list, NULL, &data);
}
for(node = list_head(list), i = 0; i
node = list_next(list, node);
list_remove(list, node);
for(node = list_head(list); node != NULL; node = list_next(list, node))
{
// 輸出數據
data = *(student_info_type*)node->m_data;
printf("name %s, score %d", data.m_name, data.m_score);
}
list_destroy(list); // 炸毀整個鏈表
}
return 0;
}
想要一起學習C++的可以加裙六二六八七一九一六,裙內有各種資料滿足大家,歡迎加裙
二、界面處理與數據處理分離
這個和前面的一樣,也是要符合「一心一意」的原則,在處理界面(比如顯示一些菜單、接受輸入數據、輸出計算結果等)的時候也不要和數據處理的代碼揉合在一起,比如一個求兩個數之和的代碼:
void calculate_sum()
{
int a, b;
printf("input two number"); // 這樣寫就是不好的,和數據處理混在了一起
scanf("%d%d", &a, &b);
printf("sum = %d", a + b);
return;
}
int main()
{
calculate_sum();
return 0;
}
應該寫成:
int calculate_sum(int a, int b)
{
return a + b; // 數據處理,這裡就不用去管具體的界面內容
}
int main()
{
int a, b, sum;
// 界面處理
printf("input two number");
scanf("%d%d", &a, &b);
sum = calculate_sum(); // 在界面處理中也不用管具體的數據處理方式,得到結果就行了
printf("sum = %d", a + b);
return 0;
}
可能大家還看不出改過的代碼有什麼好處,但是實際編寫的時候我們的數據處理不可能是a + b那麼簡單,界面也肯定不止幾個scanf/printf,所以在開始編寫的時候就應該自覺把這兩個內容分為不同的模塊,這樣在代碼量越來越大的時候就不會一心二用了。
基本就這麼多了,只要大家寫代碼的時候時刻注意這兩點,不要圖一時方便而偸懶,寫出一個好的xx管理系統應該都不難的。
想要一起學習C++的可以加裙六二六八七一九一六,裙內有各種資料滿足大家,歡迎加裙
※C語言模擬ATM自動櫃員機界面
※C語言編程簡單加密示例
※C語言編程時常犯十八個錯誤集錦
※學好C語言C加加之時,定是你拿高薪之日
TAG:C加加 |
※django框架:創建管理員賬號,構建站點後台管理系統
※用 Python 管理系統進程
※搭建SaaS管理系統,菲特云為瑜伽館提供信息化管理流程
※個人管理系列
※月子中心管理系統的管理制度模板
※晨科文件管理系統,助力文件管理集中化
※兩級監管護理管理系統的設計與實踐
※時間管理系統化方法:GTD—儘管去做
※晨科資產管理系統,為管理者打造完美辦公平台
※教學管理系統中有哪些常見報表?
※理想ONE熱管理系統解析
※Python框架:Django寫圖書管理系統
※WMS倉庫管理系統與RFID倉儲管理系統哪個更好?
※基於遠程語音體征監測居家健康管理系統研究與設計
※優科網路發布SmartZone網路控制器——業內首款基於控制器的有線無線管理系統
※什麼是電池管理系統?
※智能空調管理系統
※開源的文檔在線管理系統MinDoc
※代理商分級管理系統建立獎勵機制
※娶媳婦要娶管理系的,在外能管理公司,在家能管理財務