1 实践项目
本课程我们学习了Linux C程序设计,学习在Linux系统下使用C语言编程。那么,我们就可以使用C语言来开发应用程序。
我们使用C语言来开发一个“学生信息管理系统”,可以管理学生的信息。
那么,在这个软件系统中,我们要充分使用C语言的各个知识点,加深对C语言编程的学习。所以,我们列举几个需要实践操作的知识点:
- 函数的使用,对软件功能模块进行划分,不同的功能使用不同的函数来定义;
- 源文件和头文件的使用;不同的功能模块,使用不同的文件来封装;
- 结构体的使用,使用结构体来定义操作的对象,管理一个对象的数据和行为;
- 函数指针的使用,在结构体中定义函数指针成员,模拟对象的行为;
- 文件的操作,系统管理的学生信息,存储到文件中,所以,学习文件的创建和读写操作;
- 顺序表的使用;使用数组来管理学生信息;
- 链表的使用;使用链表来管理学生信息;
- 学习面向对象编程的思路,在软件设计中,我们把需要操作的数据封装成对象,对象有自己的数据和行为。所以,我们定义一个管理员对象,管理员可以对学生信息进行增加、删除、修改的操作。管理员的这些操作,可以定义为函数指针,指向不同的函数。
所以,通过学习这个“学生信息管理系统”软件,我们可以加深对C语言编程的理解。而且,作者给出的思路是“面向对象编程”的思路,读者一开始,就可以理解C语言实现面向对象编程的过程。
软件启动运行如下:
可以看到,编译程序:
gcc main.c manager.c array.c list.c public.c student.c -o exe
编译得到exe可执行程序,然后,执行 ./exe 程序。可以看到,这是一个学生信息管理系统,支持管理员的登陆,支持学生信息的查找、增加、删除、修改功能。
后续我们有课程,学习“Linux系统编程”,学习了Linux系统编程之后,我们可以编写更加复杂的系统软件,例如,开发一个网络服务器等等。
2 软件需求分析
我们开发一个学生信息管理系统,要求实现如下的功能模块:
- 学生信息的管理,由一个管理员来操作;
- 管理员的操作权限,有对学生信息的查询、增加、删除、修改功能;
- 管理员需要使用用户名和密码登陆系统;
- 管理的学生信息,支持数组的管理;
- 管理的学生信息,支持链表的管理;
- 代码同时支持顺序表和链表的操作,可以通过函数指针,指向不同的操作;
我们把学生信息管理系统软件,分解成这些功能需求。
那么,我们就使用C语言来开发程序,实现这些软件需求。
3 软件代码概要设计
在上一章节中,我们分析了“学生信息管理系统”软件的需求,分析出软件需要实现的功能模块。那么,下面,我们来分析每一个功能模块的实现方式。
首先,我们从整体上分析软件的设计,该软件涉及到什么对象,每个对象之间有什么操作。那么,可以概括如下:
- 学生信息对象,该对象存储一个学生的信息;
- 学生信息集合,管理所有学生信息对象的集合;
- 学生信息的集合,使用数组来定义;
- 学生信息的集合,使用链表来定义;
- 管理员对象,可以管理学生的信息,支持学生信息的查询、增加、删除、修改的操作;
- 管理员对象,需要用户名和密码的验证,才可以登陆和使用系统;
所以,我们对软件进行分析,抽象出软件功能涉及到的对象。然后,通过这些对象的操作,实现一个完整的软件系统。
例如,管理员对象的操作,支持系统的登陆,对学生信息的查询、增加、删除、修改功能。就是基于管理员对象进行操作,实现一个软件的功能设计。所以,这也就是一个面向对象编程的思想。然后操作,都是基于对象进行设计。
所以,我们使用结构体来定义对象类型,在结构体中使用函数指针来定义对象的行为。
4 管理员的定义
在学生信息管理系统中,任何操作都是由“管理员”来执行。管理员登陆到系统,然后,对学生信息进行查询、增加、删除、修改的操作。
所以,我们可以定义管理员的类型如下:
//========================================
//管理者的结构体;
//========================================
structmanager
{
structarray_set stud_array; //学生集合的 数组结构;
//================
//stud_list是一个链表结点,当作链表的表头来使用;
//================
structlist_node stud_list; //学生集合的 链表结构;
int is_login; //标记是否登陆系统成功, 0 -- 没有登陆, 1 -- 登陆;
//================
//定义函数指针;
//================
//增加一个学生信息;
int (*pfunc_stud_add)(structmanager* pm, structstud* ps);
//删除一个学生信息;
int (*pfunc_stud_del)(structmanager* pm, unsignedint number);
//修改一个学生的信息;
int (*pfunc_stud_modify)(structmanager* pm, structstud* ps);
//初始化学生的信息,加载到对应的集合中;
int (*pfunc_stud_init)(structmanager* pm);
//学生信息存储到文件中;
int (*pfunc_stud_store)(structmanager* pm);
//输出学生的信息;
void (*pfunc_stud_print)(structmanager* pm);
//根据学号, 获取一个学生的信息;
int (*pfunc_stud_get)(structmanager* pm, unsignedint number, structstud* ps);
};
可以看到,我们定义了struct manager管理员类型。然后,定义该对象如下:
//========================================
//定义全局对象, 是学生信息的管理者;
//========================================
structmanager stud_manager;
然后,我们对软件系统的操作,都是由整个管理员来进行。所以,在main函数中,定义如下:
//========================================
//程序的入口地址;
//========================================
int main(intargc, char* argv[])
{
...
//==================
//初始化学生信息管理者对象;
//下面的操作,都是由学生信息管理者进行操作;
//==================
if(manager_init(&stud_manager))
return 1;
//==================
//进入循环工作;
//==================
while(-1 != step)
{
print_usage(); //输出操作手册;
LOG("====== ====== ======\n");
LOG("%s", TEXT_INPUT_OPE);
memset(buf, 0, 16);
scanf("%s", buf);//获取用户输入的操作步骤;
step = atoi(buf); //把字符串转换成数值;
//==================
//判断用户输入怎么样的操作,然后,执行相应的动作;
//==================
switch(step)
{
case 1: manager_login(&stud_manager); break;
case 2: manager_show_student(&stud_manager);break;
case 3: manager_add_student(&stud_manager);break;
case 4: manager_del_student(&stud_manager);break;
case 5: manager_modify_student(&stud_manager);break;
case 6: step = -1; break; //设置退出循环的标记,结束程序运行;
default:
LOG("%s\n", TEXT_INPUT_ERR);
break;
}//end switch
}//end while
...
}
所以,可以看到,很多操作,都是基于stud_manager对象进行操作。其中,管理员的操作,通过函数指针来指定操作函数,例如:
//========================================
//设置管理者的函数指针, 指向数组 或者 链表的操作函数;
//========================================
void manager_init_set_func(structmanager* pm)
{
#if 0
//====================
//配置使用数组管理;
//====================
pm->pfunc_stud_add = array_stud_add;
pm->pfunc_stud_del = array_stud_del;
pm->pfunc_stud_modify = array_stud_modify;
pm->pfunc_stud_init = array_stud_init;
pm->pfunc_stud_store = array_stud_store;
pm->pfunc_stud_print = array_stud_print;
pm->pfunc_stud_get = array_stud_get;
#else
//====================
//配置使用链表管理;
//====================
pm->pfunc_stud_add = list_stud_add;
pm->pfunc_stud_del = list_stud_del;
pm->pfunc_stud_modify = list_stud_modify;
pm->pfunc_stud_init = list_stud_init;
pm->pfunc_stud_store = list_stud_store;
pm->pfunc_stud_print = list_stud_print;
pm->pfunc_stud_get = list_stud_get;
#endif
}
所以,我们给管理员对象的函数指针,定义指向不同的函数,那么,可以调用不同的函数来操作。
例如,查询显示学生信息的函数如下:
//========================================
//显示所有学生信息;
//========================================
int manager_show_student(structmanager* pm)
{
//===================
//判断管理员是否已经登陆,如果没有登陆,就返回,不允许继续操作;
//===================
if(!manager_is_login(pm))
return 1;
pm->pfunc_stud_print(pm); //通过函数指针,输出所有学生的信息;
return 0;
}
例如,通过pfunc_stud_print函数指针,调用指向的函数。
我们在这个软件中,对学生信息的管理,使用数组和链表来管理。所以,可以通过函数指针的设置,定义使用不同的数据管理方式。
通过这个代码,我们学习函数指针的定义和使用。通过函数指针,可以给结构体的对象指定一个函数。
学生信息使用数组管理
在代码中,我们定义array.c和array.h文件来管理“数组”的操作。使用数组来管理学生信息,如下:
在array.h头文件中,对外引出操作函数,如下:
int array_stud_add(structmanager* pm, structstud* ps);
int array_stud_del(structmanager* pm, unsignedint number);
int array_stud_modify(structmanager* pm, structstud* ps);
int array_stud_init(structmanager* pm);
int array_stud_store(structmanager* pm);
void array_stud_print(structmanager* pm);
int array_stud_get(structmanager* pm, unsignedint number, structstud* ps);
然后,设置给管理员对象的函数指针,如下:
//====================
//配置使用数组管理;
//====================
pm->pfunc_stud_add = array_stud_add;
pm->pfunc_stud_del = array_stud_del;
pm->pfunc_stud_modify = array_stud_modify;
pm->pfunc_stud_init = array_stud_init;
pm->pfunc_stud_store = array_stud_store;
pm->pfunc_stud_print = array_stud_print;
pm->pfunc_stud_get = array_stud_get;
所以,最终管理员可以通过函数指针,调用这些函数。以数组的方式,管理学生信息。
学生信息使用链表管理
在代码中,我们定义list.c和list.h文件来管理“链表”的操作。使用链表来管理学生信息,如下:
在list.h头文件中,对外引出操作函数,如下:
int list_stud_add(structmanager* pm, structstud* ps);
int list_stud_del(structmanager* pm, unsignedint number);
int list_stud_modify(structmanager* pm, structstud* ps);
int list_stud_init(structmanager* pm);
int list_stud_store(structmanager* pm);
void list_stud_print(structmanager* pm);
int list_stud_get(structmanager* pm, unsignedint number, structstud* ps);
然后,设置给管理员对象的函数指针,如下:
//====================
//配置使用链表管理;
//====================
pm->pfunc_stud_add = list_stud_add;
pm->pfunc_stud_del = list_stud_del;
pm->pfunc_stud_modify = list_stud_modify;
pm->pfunc_stud_init = list_stud_init;
pm->pfunc_stud_store = list_stud_store;
pm->pfunc_stud_print = list_stud_print;
pm->pfunc_stud_get = list_stud_get;
所以,最终管理员可以通过函数指针,调用这些函数。以链表的方式,管理学生信息。
7 文件操作
在“学生信息管理软件”中,需要对学生信息进行存储。所以,需要使用文件来存储学生信息。那么,有如下的操作:
- 打开文件,读取数据。查询学生信息的时候,需要把文件中的数据读取处理;
- 打开文件,写入数据。当增加一个学生信息的时候,需要把学生信息写入到文件中;
而且,在系统登陆操作中,需要用户名和密码的验证。我们预先把用户名和密码保存到pwd.txt文件中。
那么,管理员登陆系统的时候,就读取pwd.txt文件中的信息。对比用户输入的用户名和密码信息。
所以,在这个程序中,我们学习文件的操作。
8 软件编译运行
编写了代码之后,我们可以编译、运行程序,如下:
gcc main.c manager.c array.c list.c public.c student.c -o exe
此时,编译出exe程序,然后,执行软件,如下:
可以看到,运行一个学生信息管理系统软件。支持管理员的登陆,管理员可以对学生信息进行查询、增加、删除、修改的操作。
所以,首先,我们创建pwd.txt文件,存放管理员登陆的用户名和密码。如下:
那么,登陆系统的操作如下:
此时,输入步骤1,然后,输入登陆的用户名和密码,提示用户登陆成功!
然后,输入步骤3,增加一个学生的信息。所以,我们输入学生的信息。然后,再执行步骤2,查询学生的信息,如下图:
可以看到,我们添加了一个学生的信息。然后,我们可以修改和删除学生的信息,注意:修改一个学生信息的时候,修改相同学号的学生信息。如下图:
可以看到,学号16280这一个学生的信息,被修改过来了。接下来,我们删除学生信息,如下:
可以看到,输入步骤4,然后,输入需要删除学生信息的学号,最终,提示删除成功。然后,再查询学生信息,没有信息可以查询。
读者可以自行修改代码,测试软件的运行,加深对C语言的学习和使用。
9 总结
本章节我们实践开发了一个“学生信息管理系统”软件,使用C语言来开发一个软件系统。我们结合结构体和函数指针的应用,使用面向对象的设计思想,进行软件设计。
读者可以在这个软件的基础上进行扩展,完善更多的功能。加深对C语言编程的学习。在后续的课程中,我们学习“Linux系统编程”,可以开发出更复杂的软件系统。
读者要仔细分析,掌握好每一个知识点,然后,自己总结出对该知识点的理解。自己总结出来的知识,理解才深刻,才是自己掌握的知识。
韦凯峰 Linux C/C++ 程序设计教程,Linux 系统编程,Openwrt 系统开发,微信:13926572996,QQ:1523520001,博客:www.mylinux.vip
版权归原作者 Linux编程学堂 所有, 如有侵权,请联系我们删除。