整體練習-學生管理系統(tǒng)
在學習的最后,我們?yōu)榇蠹覝蕚淞艘粋€比較綜合的練習,這里會用到很多我們前面所學習到的知識。
1. 系統(tǒng)介紹
在這里,我們首先采用了數(shù)組的方式來存儲我們輸入的內(nèi)容。同時,我們這里利用里前面學習到的 struct
來結(jié)構(gòu)化存儲我們的學生信息。
我們實現(xiàn)了基本的對于數(shù)據(jù)操作的幾項功能:增、刪、改、查。
也就是我們可以向這個系統(tǒng)中添加數(shù)據(jù),刪除數(shù)據(jù),修改數(shù)據(jù),還有就是查詢數(shù)據(jù)。這里的查詢數(shù)據(jù),我們又分為了全部無條件的查詢,和按照姓名條件的查詢。
2. 功能
系統(tǒng)的功能里面我們設計了添加、刪除、修改、列表顯示和查詢等 5 個功能。
添加:添加就是將數(shù)據(jù)添加到存儲數(shù)據(jù)的數(shù)組中;
刪除:刪除就是根據(jù)指定的序列號刪除特定的一條數(shù)據(jù);
修改:修改就是根據(jù)指定的序列號來修改學生的成績;
列表顯示:列表的顯示,其實就是無條件的查詢,也就是在沒有特點查詢條件的情況下,將存儲的數(shù)據(jù)全部顯示出來;
查詢:這里的查詢,就是按照姓名這個特性的條件。把符合這個條件的數(shù)據(jù)篩選出來,并顯示出來。
3. 示例程序
#include <stdio.h>
#include <string.h>
#define StudentNumbers 50
#define NameLength 50
typedef struct
{
int id;
char name[NameLength];
int age;
int score;
int flag;
} Student;
int add(Student student, Student Students[]);
int del(int id, Student students[]);
int display(Student students[]);
int update(int id, Student students[]);
int search(char name[], Student students[]);
int main()
{
int id = -1;
char name[NameLength];
int choice = 0;
int stop = 0;
Student students[StudentNumbers];
Student student;
for (int i = 0; i < StudentNumbers; i++)
{
students[i].id = i;
students[i].flag = 0;
}
while (stop == 0)
{
printf("-------------------------\n");
printf("* 學生管理系統(tǒng) *\n");
printf("-------------------------\n");
printf("1 添加\n");
printf("2 修改成績\n");
printf("3 查詢\n");
printf("4 刪除\n");
printf("5 顯示學生列表\n");
printf("0 退出程序\n");
printf("請直接輸入數(shù)字選項:");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("請輸入學生姓名:");
scanf("%s", student.name);
printf("請輸入學生的年齡:");
scanf("%d", &student.age);
printf("請輸入學生成績:");
scanf("%d", &student.score);
add(student, students);
break;
case 2:
printf("請輸入要修改成績的學生編號:");
scanf("%d", &id);
update(id, students);
break;
case 3:
printf("請輸入要查找的學生姓名:");
scanf("%s", name);
search(name, students);
break;
case 4:
printf("請輸入要刪除的學生編號:");
scanf("%d", &id);
del(id, students);
break;
case 5:
display(students);
break;
case 0:
stop = 1;
break;
default:
printf("輸入選項有誤\n");
break;
}
}
return 0;
}
int add(Student student, Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].flag == 0)
{
strcpy(students[i].name, student.name);
students[i].age = student.age;
students[i].score = student.score;
students[i].flag = 1;
return 0;
}
}
return 1;
}
int del(int id, Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].id == id)
{
students[i].flag = 0;
return 0;
}
}
return 1;
}
int display(Student students[])
{
printf("******************\n");
printf("學生列表\n");
printf("******************\n");
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].flag == 1)
{
printf("學生編號:%d,學生姓名:%s,年齡:%d,成績:%d\n", students[i].id, students[i].name, students[i].age, students[i].score);
}
}
printf("******************\n");
return 0;
}
int update(int id, Student students[])
{
int score = -1;
printf("請輸入新的成績:");
scanf("%d", &score);
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].id == id)
{
students[i].score = score;
return 0;
}
}
return 1;
}
int search(char name[], Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (strcmp(name, students[i].name) == 0)
{
printf("學生編號: %d,學生姓名: %s,年齡: %d,成績: %d\n", students[i].id, students[i].name, students[i].age, students[i].score);
return 0;
}
}
printf("沒有查找到相關(guān)學生信息。\n");
return 1;
}
很多人可能會第一次接觸這么長的程序,會產(chǎn)生畏懼的心理。其實不用擔心。要相信自己可以看懂的。
我們分開來講解一下。
在程序的最開始我們需要引入程序中可能需要使用的函數(shù)的頭文件。這里我們因為要使用 printf
、 scanf
等,所以需要 stdio
函數(shù)庫。因為要使用 strcpy
、 strcmp
函數(shù),所以需要 string
函數(shù)庫。
#include <stdio.h>
#include <string.h>
為了便于程序中的維護,不用在很多出修改共用的數(shù)值。所以這里定義了一個常量
#define StudentNumbers 50
#define NameLength 50
為了存儲學生的信息。我們用了 struct
來定義學生的信息。里面包含學生的編號 id
,姓名 name
這是一個字符串,年齡 age
,成績 score
,標志位 flag
這個變量是用來表示是否有學生信息存儲在該位置的。不過這里我們使用了之前沒有介紹的一個 typedef
。這個關(guān)鍵字使用的好處是使得后面使用這個 struct
的時候不用每次都用關(guān)鍵字 struct
來定義,只要用這個結(jié)構(gòu)的名稱直接定義就可以了,如同我們定義整數(shù)等內(nèi)置類型一樣方便。
typedef struct
{
int id;
char name[NameLength];
int age;
int score;
int flag;
} Student;
為了便于維護,我們沒有按照函數(shù)出現(xiàn)的順序來寫。不過 C 語言一直秉承著先定義再使用的原則。所以。如果你使用的函數(shù)沒有在使用前出現(xiàn),而是在后面的話,那么你就需要先讓編譯器知道這個函數(shù)的基本情況。這個時候我們會先把函數(shù)的定義寫在前面。
我們可以看到下面我們定義了這個系統(tǒng)的功能。每個功能我們都會寫一個函數(shù)。其實不寫這些函數(shù),把所有的功能寫在 main
函數(shù)內(nèi)部也是可以的。但是這樣會在維護上存在問題。進行測試也會變得困難。
int add(Student student, Student Students[]);
int del(int id, Student students[]);
int display(Student students[]);
int update(int id, Student students[]);
int search(char name[], Student students[]);
這里定義了一些需要使用的變量。stop
變量是用來控制程序循環(huán)的,也就是控制程序在什么時候可以結(jié)束循環(huán)的。我們定義了一個 Student
的數(shù)組,用來存儲學生的信息。用一個單獨的變量來存儲單條的學生信息。
int id = -1;
char name[NameLength];
int choice = 0;
int stop = 0;
Student students[StudentNumbers];
Student student;
這里我們通過循環(huán)來初始化我們的數(shù)組。
for (int i = 0; i < StudentNumbers; i++)
{
students[i].id = i;
students[i].flag = 0;
}
循環(huán)語句如果在不改變條件的情況下會一直循環(huán)。確保我們的系統(tǒng)可以一直運行。
while (stop == 0)
在接收到輸入后。我們就會通過 switch
來進行相應的匹配。完成對應的操作。這比使用大量的 if
語句簡約了很多。
switch (choice)
在子程序中,也就是實現(xiàn)增、刪、改、查這些功能程序中。我們用了循環(huán)語句來訪問數(shù)組中的元素。同時,利用了判斷語句與特定的變量,來判斷該位置是否存有學生信息。
運行結(jié)果:
utopia@DESKTOP:~$ ./test
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:1
請輸入學生姓名:張三
請輸入學生的年齡:22
請輸入學生成績:100
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:1
請輸入學生姓名:李四
請輸入學生的年齡:21
請輸入學生成績:90
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:1
請輸入學生姓名:王二
請輸入學生的年齡:23
請輸入學生成績:99
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:5
******************
學生列表
******************
學生編號:0,學生姓名:張三,年齡:22,成績:100
學生編號:1,學生姓名:李四,年齡:21,成績:90
學生編號:2,學生姓名:王二,年齡:23,成績:99
******************
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:2
請輸入要修改成績的學生編號:1
請輸入新的成績:80
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:5
******************
學生列表
******************
學生編號:0,學生姓名:張三,年齡:22,成績:100
學生編號:1,學生姓名:李四,年齡:21,成績:80
學生編號:2,學生姓名:王二,年齡:23,成績:99
******************
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:4
請輸入要刪除的學生編號:1
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:5
******************
學生列表
******************
學生編號:0,學生姓名:張三,年齡:22,成績:100
學生編號:2,學生姓名:王二,年齡:23,成績:99
******************
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:1
請輸入學生姓名:張五
請輸入學生的年齡:20
請輸入學生成績:70
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:5
******************
學生列表
******************
學生編號:0,學生姓名:張三,年齡:22,成績:100
學生編號:1,學生姓名:張五,年齡:20,成績:70
學生編號:2,學生姓名:王二,年齡:23,成績:99
******************
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:3
請輸入要查找的學生姓名:張五
學生編號: 1,學生姓名: 張五,年齡: 20,成績: 70
-------------------------
* 學生管理系統(tǒng) *
-------------------------
1 添加
2 修改成績
3 查詢
4 刪除
5 顯示學生列表
0 退出程序
請直接輸入數(shù)字選項:
在程序中,我們首先添加了 3 條學生的記錄。然后我們進行了列表顯示。接著,我們嘗試修改了其中一個學生成績,并再次查看列表,發(fā)現(xiàn)成績修改生效了。然后,我們刪除了一個學生,列表顯示結(jié)果其已經(jīng)被刪除了。然后我們又嘗試添加了一個學生。列表顯示結(jié)果添加成功。最后我們按照姓名查找了一個學生。
4. 小結(jié)
在這里,我們知識綜合利用了我們之前所學習的一部分知識來完成一個接近實際可用的系統(tǒng)。
當然作為一個可以使用的系統(tǒng),我們還會設計到數(shù)據(jù)輸入時合法性的校驗,以及數(shù)據(jù)持久化的存儲等等一系列的問題需要考慮。
同時在一個系統(tǒng)規(guī)模變大以后,其存儲的結(jié)構(gòu)和方式會影響到數(shù)據(jù)的操作效率,最直觀的就是完成一次操作所需要的時間會發(fā)生較大甚至巨大的變化。這個時候,通過改善數(shù)據(jù)結(jié)構(gòu)與算法會起到非常重大的作用。但是切記實現(xiàn)功能在很多時候時一個系統(tǒng)的第一要務,而優(yōu)化系統(tǒng)則是在你實現(xiàn)一個系統(tǒng)以后在做的事情。有本書中寫過,永遠不要上來就設計一個龐大的系統(tǒng)。軟件的設計這個時候是另外一個重要的部分。我們這里既沒有考慮設計,也沒有考慮算法與數(shù)據(jù)結(jié)構(gòu)。只是通過我們現(xiàn)有的知識,來實現(xiàn)一個較為完整的功能。
學習沒有終點,人生短暫而漫長。需要你不斷的通過學習來找尋樂趣。不然這短暫的人生稍縱即逝,這漫長的人生會讓你苦悶不堪。所以閑來沒事,用多種方式多學習一點。盡量找點可靠的信息來源看。謝謝大家!