宿舍管理系統——單鏈表+結構體實現入住、退房和查詢功能(C語言版)


本程序的編譯和運行環境如下(如果有運行方面的問題歡迎在評論區留言,也歡迎直接加QQ:2961439733,備注博客園或CSDN即可):

  • 編輯工具:Dev-C++(版本:5.11.0.0)
  • 編譯器:TDM-GCC 4.9.2 64-bit Release
  • 代碼生成語言標准:ISO C99

演示及講解視頻鏈接:https://www.bilibili.com/video/BV1BC4y1a78W

老規矩,源碼放在文章末尾了(源碼上傳到CSDN的話會被后台調整積分

好了開始進入正題,這次又雙叒叕是我那位朋友的題目,不過已經是最后一題了。

課題四:信息管理系統

利用鏈表編寫下列程序(二選一)

1、宿舍管理軟件

用C語言為學生宿舍管理人員編寫一個宿舍管理軟件。設某宿舍有:101,102,201,202四個房間,每個房間可住學生<=4人,鏈表存儲結構:學號、姓名、房間號、后續指針,按房間號有序,實現學生的入住、退房和查詢,按給定學號、姓名、房號查詢。

2、學生成績信息管理

對學生的成績信息進行管理,學生信息包括:學號、姓名、學期、每門課程的成績、平均成績、名次。實現:學生信息的錄入;修改;刪除和查詢,按學期、學號、成績不及格等查詢。

要求:

  1. 要有菜單進行功能選擇
  2. 各個功能要分到不同的函數來寫
  3. 禁止使用goto語句
  4. 鏈表的各種操作要熟練掌握,會進行調試(調試我打算單獨放一篇文章來講,這篇主要講怎么實現這個程序
  5. 鏈表結點如果使用malloc動態分配空間,需要釋放

  看完題目我果斷選擇了第一題,不但好做,而且算是練手吧,因為第二題在我大一C語言課程設計時已經做過類似的了。那么來簡單分析一下這個題如何下手:

首先先畫出一個大致的流程圖:

  接下來就是實現功能1~n,我們確定一下要用到的數據結構。按要求采用鏈表實現,結點是記錄住宿信息的結構體:

  struct DORMITORY {
    int num; //房間號
    char id[15]; //學號
    char name[20]; //姓名
    struct DORMITORY* next;//指針域
  };

  這里我還采用了設計數據庫表時的一些思想,比如主鍵。用學號來標識唯一的一個結構體,避免出現一個人住多個寢室的情況。這里由於題目限制,最多只會有16名學生,所以采用大小確定的二維數組進行保存,用於核對學號是否已經存在。下面再來看看我們要實現的功能。

   功能不多,主要分為入住、退房和查詢三大類。入住即添加一條新的住宿信息,也就是新建鏈表結點;退房意味着刪除一條住宿信息,即從鏈表里刪除一個節點;至於查找嘛,這幾乎是所有的管理類程序都繞不開的一個功能,在這里表現為從鏈表中找到符合條件的節點。它們分別對應着三種對數據的基本操作——增、刪、查。還有一種是修改,題目里沒要求我也就沒實現,各位看官如果有興趣可以自行實現。接下來我們進入到代碼的具體實現環節,其中字符串的比較與復制用到了庫函數strcmp和strcpy。

  首先是主頁面:采用一個死循環,不斷接受輸入來執行各種功能(其余展示頁面同理

 1 void menu() { //主菜單
 2     char t;
 3     int flag = 1;
 4     while(flag) {
 5         system("cls"); //清屏
 6         printf("+--------------------+\n");
 7         printf("|    宿舍管理系統    |\n");
 8         printf("+--------------------+\n");
 9         printf("|  【1】入住 管理    |\n");
10         printf("|                    |\n");
11         printf("|  【2】退房 管理    |\n");
12         printf("|                    |\n");
13         printf("|  【3】信息 查詢    |\n");
14         printf("|                    |\n");
15         printf("|  【4】使用 說明    |\n");
16         printf("|                    |\n");
17         printf("|  【5】退出 系統    |\n");
18         printf("+--------------------+\n");
19         t=getch();    //不回顯輸入
20         switch(t) {
21             case '1':
22                 checkIn();   //入住管理
23                 break;
24             case '2':
25                 checkOut();  //退房管理
26                 break;
27             case '3':
28                 menu_query();//信息查詢
29                 break;
30             case '4':
31                 direction(); //使用說明 
32                 break;
33             case '5':
34                 printf("\n感謝您的使用,再見( ̄︶ ̄)↗");
35                 destroy();  //銷毀鏈表,釋放空間 
36                 flag = 0;   //結束程序
37                 break;
38             default:
39                 break;
40         }
41     }
42 } 

   接下來我們依次實現主菜單里包含的功能:

  • 入住管理:
 1 void checkIn() { //登記入住信息 
 2     char t;
 3     while(head->num > 0) {//還有空余房間,繼續循環 
 4         system("cls");    //清屏 
 5         dormitory node = create();//新建一個節點 
 6         if(node != NULL){ //創建成功 
 7             head->num -= 1;          //剩余房間數減 1 
 8             node->next = head->next; //每次新結點的next指向頭結點的next 
 9             head->next = node;       //讓頭結點指向新建結點 
10         }else{ //創建失敗 
11             printf("學號已存在,請重新進行添加操作!");
12             break;
13         }
14         printf("\n+--------------------+");
15         printf("\n|    是否繼續添加    |");
16         printf("\n+--------------------+");
17         printf("\n|【1】是      【2】否|");
18         printf("\n+--------------------+");
19         t = getch();
20         if(t == '1')
21             continue;
22         else
23             break;
24     }
25     if(head->num == 0)//人數已滿 
26         printf("\n宿舍房間人數已滿,無法繼續入住!");
27     printf("\n即將返回主菜單……"); 
28     Sleep(1500);     //暫停1.5秒后返回主菜單 
29 }

  這里我們解釋一下頭插法的實現過程:

  1.首先建立一個頭結點:

  2.然后新建結點p拷貝head的next指針:

  3.最后更改head的next的指針指向:

  這種方式建立起來的鏈表是逆序的(相對於創建的先后順序),不過不影響我們這個程序的功能實現。

  • 退房管理:
 1 void checkOut() { //退房處理,按學號
 2     char id[15];
 3     int flag = 0; 
 4     dormitory p = head->next;
 5     system("cls"); //清屏 
 6     print(); //打印出全部信息供選擇
 7     //按學號的好處是唯一,不會刪除同一房間號或者重名學生的信息,數據庫里學號相當於主鍵  
 8     printf("請輸入要進行此操作的學生學號(如果是誤觸,請輸入esc確認返回):\n");
 9     scanf("%s", id);
10     if(!strcmp(id, "esc\0")){
11         p =NULL;
12         flag = 1; 
13     } 
14     for(; p != NULL; p = p->next){
15         if(!strcmp(p->id, id)){
16             del(p);      //找到對應學號,刪除
17             head->num += 1;//剩余房間數加 1 
18             printf("退房辦理成功!"); 
19             flag = 1;//把標志改為1 
20         }
21     } 
22     if(!flag)
23         printf("學號不存在!");
24     printf("\n即將返回主菜單……"); 
25     Sleep(1500); //暫停1.5秒后返回主菜單 
26 }
  • 信息查詢(以按學號查詢為例,其他的查詢把代碼里!strcmp(p->id, id)這個判斷條件更改一下即可):
 1 void findById() { //按學號查詢 
 2     char t, id[15]; 
 3     int flag = 0; 
 4     dormitory p = head->next;
 5     system("cls"); //清屏 
 6     printf("請輸入要查詢的學生學號:\n");
 7     scanf("%s", id);
 8     printf("\n+-------------------------------+\n"); 
 9     printf("|         住宿信息(全)          |\n");
10     printf("+-------------------------------+\n");
11     printf("| 宿舍號 |   學   號   | 姓  名 |\n");
12     printf("+-------------------------------+\n");
13     for(; p != NULL; p = p->next){ //輸出與目標學號一致的住宿信息
14         if(!strcmp(p->id, id)){
15             flag = 1;
16             printf("|  %4d  | %11s | %6s |\n", p->num, p->id, p->name);
17         }
18     }
19     printf("+-------------------------------+\n");
20     if(!flag)
21         printf("\n未找到相關信息(>﹏<)");
22     while((t = getch()) != 27);//只有按下ESC鍵才會中斷循環並返回 
23 }

  核心流程里的代碼就這些,其余的部分請參考源碼:

  1 #include<stdio.h>
  2 #include<conio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<windows.h>
  6 
  7 #define N sizeof(struct DORMITORY)//宏定義,N為結構體變量所占內存的大小 
  8 
  9 struct DORMITORY {
 10     int num;  //房間號
 11     char id[15];      //學號
 12     char name[20];    //姓名
 13     struct DORMITORY* next;//指針域
 14 };
 15 //使用 typedef 關鍵字來定義自己習慣的數據類型名稱
 16 //此處的意思為用dormitory來代替struct DORMITORY* 
 17 typedef struct DORMITORY* dormitory;
 18 
 19 char set[16][15];//學號集合,避免出現學號重復
 20 dormitory head;     //鏈表頭節點,不用來保存住宿記錄,方便建立鏈表(頭插法) 
 21 
 22 void menu();           //主菜單
 23 void menu_query();  //信息查詢菜單
 24 void direction();    //使用說明 
 25 void checkIn();        //入住 
 26 void checkOut();       //退房 
 27 void print();        //打印全部信息 
 28 void findAll();        //查看全部信息
 29 void findById();       //按學號查詢 
 30 void findByName();     //按姓名查詢 
 31 void findByNum();      //按宿舍號查詢
 32 void del(dormitory node);    //刪除一條住宿記錄
 33 void destroy();                //銷毀鏈表 
 34 int repeated(char id[15]);     //判斷學號是否重復 
 35 dormitory create();         //創建一條住宿記錄 
 36 
 37 int main() {
 38     //初始化鏈表
 39     head = (dormitory)malloc(N);
 40     //利用結構體中的學號變量記錄剩余房間總數 
 41     head->num = 16; 
 42     //利用字符數組變量id記錄四個房間的剩余房間數,依次是101、102、201、202 
 43     head->id[0] = '4';
 44     head->id[1] = '4';
 45     head->id[2] = '4';
 46     head->id[3] = '4';
 47     head->next = NULL;
 48     menu();
 49     return 0;
 50 }
 51 
 52 void menu() { //主菜單
 53     char t;
 54     int flag = 1;
 55     while(flag) {
 56         system("cls"); //清屏, 然后輸出新的內容
 57         printf("+--------------------+\n");
 58         printf("|    宿舍管理系統    |\n");
 59         printf("+--------------------+\n");
 60         printf("|  【1】入住 管理    |\n");
 61         printf("|                    |\n");
 62         printf("|  【2】退房 管理    |\n");
 63         printf("|                    |\n");
 64         printf("|  【3】信息 查詢    |\n");
 65         printf("|                    |\n");
 66         printf("|  【4】使用 說明    |\n");
 67         printf("|                    |\n");
 68         printf("|  【5】退出 系統    |\n");
 69         printf("+--------------------+\n");
 70         t=getch();    //不回顯輸入
 71         switch(t) {
 72             case '1':
 73                 checkIn();     //入住管理
 74                 break;
 75             case '2':
 76                 checkOut();     //退房管理
 77                 break;
 78             case '3':
 79                 menu_query();//信息查詢
 80                 break;
 81             case '4':
 82                 direction(); //使用說明 
 83                 break;
 84             case '5':
 85                 printf("\n感謝您的使用,再見( ̄︶ ̄)↗");
 86                 destroy();  //銷毀鏈表,釋放空間 
 87                 flag = 0;    //結束程序
 88                 break;
 89             default:
 90                 break;
 91         }
 92     }
 93 }
 94 
 95 void menu_query() { //查詢菜單
 96     char t;
 97     int flag = 1;
 98     while(flag) {
 99         system("cls"); //清屏, 然后輸出新的內容
100         printf("+---------------------+\n");
101         printf("|      信息 查詢      |\n");
102         printf("+---------------------+\n");
103         printf("|  【1】全體  查詢    |\n");
104         printf("|                     |\n");
105         printf("|  【2】學號  查詢    |\n");
106         printf("|                     |\n");
107         printf("|  【3】姓名  查詢    |\n");
108         printf("|                     |\n");
109         printf("|  【4】房間號查詢    |\n");
110         printf("+---------------------+\n");
111         t=getch();  //不回顯輸入
112         switch(t) {
113             case '1':
114                 findAll();     //查詢全部
115                 break;
116             case '2':
117                 findById();     //按學號查詢
118                 break;
119             case '3':
120                 findByName();//按姓名查詢
121                 break;
122             case '4':
123                 findByNum(); //按宿舍號查詢
124                 break;
125             case 27:
126                 flag = 0;     //返回主菜單
127                 break;
128             default:         //屏蔽其他輸入
129                 break;
130         }
131     }
132 }
133 
134 int repeated(char id[15]){ //檢查學號是否已經存在 
135     int i;
136     for(i = 0; i < 16; ++i){
137         if(!strcmp(id, set[i]))//如果學號已經存在,返回1
138             return 1;
139     }
140     return 0;
141 }
142 
143 dormitory create() { //創建一條入住信息
144     dormitory record = (dormitory)malloc(N);//申請空間 
145     //輸入學號
146     printf("請輸入學號:\n");
147     scanf("%s", record->id); 
148     //判重  
149     if(repeated(record->id))
150         return NULL;
151     strcpy(set[16 - head->num], record->id);//將不重復的學號記錄在set數組 
152     //輸入姓名
153     printf("請輸入姓名:\n");  
154     scanf("%s", record->name);
155     //確定要分配的房間號 
156     if(head->id[0] > '0') {
157         record->num = 101;
158         head->id[0] -= 1; 
159     } else if(head->id[1] > '0') {
160         record->num = 102;
161         head->id[1] -= 1;
162     } else if(head->id[2] > '0') {
163         record->num = 201;
164         head->id[2] -= 1;
165     } else {
166         record->num = 202;
167         head->id[3] -= 1;
168     }
169     //指針指向 
170     record->next = NULL; 
171     return record;
172 }
173 
174 void del(dormitory node){ //刪除一條住宿記錄
175     int num = node->num, i = 0;
176     dormitory m = node->next;
177     dormitory p = head->next;
178     //set數組保留的對應學號刪除
179     for(i = 0; i < 16; ++i){
180         if(!strcmp(node->id, set[i])){//找到學號,置空 
181             strcpy(set[i], "\0");
182             break; 
183         }
184     }
185     //把對應的房間數修改
186     if(num == 101)
187         head->id[0] += 1;
188     else if(num == 102)
189         head->id[1] += 1;
190     else if(num == 201)
191         head->id[2] += 1;
192     else
193         head->id[3] += 1;
194     //刪除結點,釋放空間 
195     if(m != NULL){ 
196         // node不是最后一個結點
197         //把node下一個結點的內容拷貝到自身,然后釋放它下一個結點占用的內存 
198         node->num = m->num;
199         strcpy(node->id, m->id);
200         strcpy(node->name, m->name);
201         node->next = m->next;
202         free(m);
203     }else{//node是最后一個結點,釋放node占用的內存 
204         m = head;
205         for(; p != NULL; m = p, p = p->next)
206             if(!strcmp(p->id, node->id))
207                 break;
208         m->next = NULL;
209         free(p);
210     }
211 } 
212 
213 void destroy(){ //銷毀鏈表 
214     dormitory p = NULL;
215     dormitory q = head;
216     while(q != NULL) {
217         p = q;        //指向結構體所在內存地址
218         q = q->next;//找到下一塊結構體所在內存地址 
219         free(p);    //釋放空間 
220     }
221 } 
222 
223 void checkIn() { //登記入住信息 
224     char t;
225     while(head->num > 0) {//還有空余房間,繼續循環 
226         system("cls");       //清屏 
227         dormitory node = create();//新建一個節點 
228         if(node != NULL){ //創建成功 
229             head->num -= 1;             //剩余房間數減 1 
230             node->next = head->next; //每次新結點的next指向頭結點的next 
231             head->next = node;            //讓頭結點指向新建結點 
232         }else{ //創建失敗 
233             printf("學號已存在,請重新進行添加操作!");
234             break;
235         }
236         printf("\n+--------------------+");
237         printf("\n|    是否繼續添加    |");
238         printf("\n+--------------------+");
239         printf("\n|【1】是      【2】否|");
240         printf("\n+--------------------+");
241         t = getch();
242         if(t == '1')
243             continue;
244         else
245             break;
246     }
247     if(head->num == 0)//人數已滿 
248         printf("\n宿舍房間人數已滿,無法繼續入住!");
249     printf("\n即將返回主菜單……"); 
250     Sleep(1500);     //暫停1.5秒后返回主菜單 
251 }
252 
253 void checkOut() { //退房處理,按學號
254     char id[15];
255     int flag = 0; 
256     dormitory p = head->next;
257     system("cls"); //清屏 
258     print(); 
259     //按學號的好處是唯一,不會刪除同一房間號或者重名學生的信息,數據庫里學號相當於主鍵  
260     printf("請輸入要進行此操作的學生學號(如果是誤觸,請輸入esc確認返回):\n");
261     scanf("%s", id);
262     if(!strcmp(id, "esc\0")){
263         p =NULL;
264         flag = 1; 
265     } 
266     for(; p != NULL; p = p->next){
267         if(!strcmp(p->id, id)){
268             del(p);      //找到對應學號,刪除
269             head->num += 1;//剩余房間數加 1 
270             printf("退房辦理成功!"); 
271             flag = 1;//把標志改為1 
272         }
273     } 
274     if(!flag)
275         printf("學號不存在!");
276     printf("\n即將返回主菜單……"); 
277     Sleep(1500); //暫停1.5秒后返回主菜單 
278 }
279 
280 void direction() { //使用說明 
281     char t; 
282     while(1){
283         system("cls"); //清屏 
284         printf("+------------------------------------------+\n");
285         printf("|              使  用  說  明              |\n");
286         printf("+------------------------------------------+\n");
287         printf("| 1. 每個操作都有對應的'【】'按鍵提示      |\n");
288         printf("|                                          |\n");
289         printf("| 2. 如無特殊提示,按'ESC'鍵返回上一個菜單 |\n");
290         printf("|                                          |\n");
291         printf("| 3. 預祝您使用愉快!o(* ̄▽ ̄*)o          |\n");
292         printf("+------------------------------------------+\n");
293         t = getch();
294         if(t == 27)//若輸入為ESC鍵則中斷循環,返回主菜單 
295             break;
296     } 
297 }
298  
299 void print() { //展示全部信息  
300     int i = 0; //記錄共有幾條信息 
301     dormitory p = head->next;
302     system("cls"); //清屏 
303     printf("+-------------------------------+\n"); 
304     printf("|          住宿信息(全)         |\n");
305     printf("+-------------------------------+\n");
306     printf("| 宿舍號 |   學   號   | 姓  名 |\n");
307     printf("+-------------------------------+\n");
308     for(; p != NULL; p = p->next, ++i) //輸出全部信息 
309         printf("|  %4d  | %11s | %6s |\n", p->num, p->id, p->name);
310     printf("+-------------------------------+\n");
311     printf("|         共有%2d條信息          |\n", i);    
312     printf("+-------------------------------+\n"); 
313 }
314 
315 void findAll(){ //查詢全部 
316     char t;
317     print();
318     while((t = getch()) != 27);//只有按下ESC鍵才會中斷循環並返回
319 } 
320 
321 void findById() { //按學號查詢 
322     char t, id[15]; 
323     int flag = 0; 
324     dormitory p = head->next;
325     system("cls"); //清屏 
326     printf("請輸入要查詢的學生學號:\n");
327     scanf("%s", id);
328     printf("\n+-------------------------------+\n"); 
329     printf("|         住宿信息(全)          |\n");
330     printf("+-------------------------------+\n");
331     printf("| 宿舍號 |   學   號   | 姓  名 |\n");
332     printf("+-------------------------------+\n");
333     for(; p != NULL; p = p->next){ //輸出與目標學號一致的住宿信息
334         if(!strcmp(p->id, id)){
335             flag = 1;
336             printf("|  %4d  | %11s | %6s |\n", p->num, p->id, p->name);
337         }
338     }
339     printf("+-------------------------------+\n");
340     if(!flag)
341         printf("\n未找到相關信息(>﹏<)");
342     while((t = getch()) != 27);//只有按下ESC鍵才會中斷循環並返回 
343 }
344 
345 void findByName() { //按姓名查詢 
346     char t, name[15]; 
347     int flag = 0; 
348     dormitory p = head->next;
349     system("cls"); //清屏 
350     printf("請輸入要查詢的學生姓名:\n");
351     scanf("%s", name);
352     printf("\n+-------------------------------+\n"); 
353     printf("|         住宿信息(姓名)        |\n");
354     printf("+-------------------------------+\n");
355     printf("| 宿舍號 |   學   號   | 姓  名 |\n");
356     printf("+-------------------------------+\n");
357     for(; p != NULL; p = p->next){ //輸出與目標學號一致的住宿信息
358         if(!strcmp(p->name, name)) {
359             flag = 1;
360             printf("|  %4d  | %11s | %6s |\n", p->num, p->id, p->name);
361         }
362     }
363     printf("+-------------------------------+\n");
364     if(!flag)
365         printf("\n未找到相關信息(>﹏<)");
366     while((t = getch()) != 27);//只有按下ESC鍵才會中斷循環並返回 
367 }
368 
369 void findByNum() { //按宿舍號查詢 
370     char t;
371     int num, i = 0;
372     int flag = 0;
373     dormitory p = head->next;
374     system("cls"); //清屏 
375     printf("請輸入要查詢的宿舍號:\n");
376     scanf("%d", &num);
377     printf("\n+-------------------------------+\n"); 
378     printf("|         住宿信息(宿舍)        |\n");
379     printf("+-------------------------------+\n");
380     printf("| 宿舍號 |   學   號   | 姓  名 |\n");
381     printf("+-------------------------------+\n");
382     for(; p != NULL; p = p->next){ //輸出與目標學號一致的住宿信息
383         if(p->num == num){
384             i += 1;
385             printf("|  %4d  | %11s | %6s |\n", p->num, p->id, p->name);
386         }
387     }
388     printf("+-------------------------------+\n");
389     printf("|         共有%2d條信息          |\n", i);    
390     printf("+-------------------------------+\n");
391     while((t = getch()) != 27);//只有按下ESC鍵才會中斷循環並返回 
392 }
宿舍管理系統

   希望你能在理解本程序的基礎上完成文章開頭提到的學生成績信息管理,如果能在此基礎上利用文件保存數據,相信你的水平能更上一層樓!碼文不易,看到這里如果對你有幫助的話不妨點個贊支持一波再走吧,3Q~ 😀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM