C语言实现大学生考勤管理系统

时间:2021-10-26 06:26:19

程序设计题:大学生考勤系统

1 问题描述

该系统要求实现一个简单、实用的学生考勤系统程序,主要功能包括考勤数据的新增、删除、修改、查找、统计、排序、输出等。所有统计数据都要利用文件系统保存,以备系统下次运行时使用。通过此课题,熟练掌握文件、数组、指针的各种操作,以及一些基本算法的应用。

2 功能要求

代码要能提供以下几个基本功能。

(1)考勤数据是由多条数据记录构成,其信息包括:学号(唯一)、姓名、班级、考勤日期(由月和日组成)等等。

(2)数据保存形式:所有信息要以文本或二进制文件保存。

(3)需要实现的功能

a 新增学生信息数据(避免重复记录,若在,不可再增加)。

b 查找数据(可按学号、姓名、考勤日期等查找)。

c 修改学生记录(可以先查找,再修改)。

d 删除学生记录(请参考上面修改的处理)。

e  显示学生考勤数据列表(可显示部分或全部)。

f  排序(可按学号、姓名、考勤日期等排序)。

g 数据统计(对考勤数据统计分析,统计完成后,可以通过考勤系统中得出考勤明细表,考勤日报表、考勤汇总表、考勤异常表,请假汇总表等)。

h  保存数据到文件中并从文件中读入数据。

(4)界面功能要求:

1) 采用友好的界面,实现一个功能控制菜单。

2) 每次操作都从该菜单选择,利用循环结构使得一次运行程序可进行多次操作。

备注:

(1)数据完整性保证。例如:学号和姓名必须严格、规范。

(2)要求报表格式灵活、形式多样、内容清楚,具体请学生自己构思、设计。

(3)考勤符号:出 勤√   旷 课 X   事 假 △   病 假 ○   迟 到 +  早 退 –

(4)考勤时间段不少于十条。

3 其他要求

(1)界面美观,交互方便。

(2)注释详细:每个函数有注释说明功能,对参数、返回值也要以注释的形式说明用途;关键的语句段要求有注释解释。

(3)程序的层次清晰,可读性强。

(4)变量、函数命名符合规范。

(5)如有可能,可使用MFC 等开发工具,实现彩色或图形操作界面。

4 开发环境

可以选择TC2.0、TC3.0、VC++6.0、vs2010等开发环境,或者与老师讨论,选择自己熟悉的开发工具与平台。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxsize 15
#define maxnum 1000
 
typedef struct {
 char Student_ID[maxsize];
 char Name[maxsize];
 char Class_Number[maxsize];
 char Attandance_date[maxsize];
 char Attandance_Result[maxsize];
} student;
 
student Students[maxnum];
 
int num = 0;
char buf[maxsize];
/*实现每次输入结束最后输入回车退出的功能,更好的实现与用户的交互 */
void wait_for_Enter() {
 getchar();
 getchar();
}
/*为了实现对日期进行排序,我的想法是对于月份,直接用atoi截取出来转化成月份,对于天数,则需要用以下函数计算*/
int convert(char str[]) {
 int i,j,res = 0, cnt = 0;
 for (i = strlen(str) - 3; i >= 0; i--) {
 if (str[i] >= '0'&&str[i] <= '9') res *= 10, res += (str[i] - '0');
 else break;
 }
 return res;//返回天数,也就是一月中的第几天,例如11月5日,返回的就是5;5月23日,返回的就是23
}
/*该函数实现的是把student类型变量b的所有信息赋给student类型的变量a*/
void copy(student *a,student *b) {
 strcpy(a->Student_ID , b->Student_ID);
 strcpy(a->Name , b->Name);
 strcpy(a->Class_Number , b->Class_Number);
 strcpy(a->Attandance_Result , b->Attandance_Result);
 strcpy(a->Attandance_date , b->Attandance_date);
}
/*此函数的作用是实现对已存在的学生不可再次添加的作用*/
bool judge(char *ID) {
 int i;
 for (i = 0; i < num; i++) {
 if (strcmp(Students[i].Student_ID, ID) == 0) return false;
 }
 return true;
}
/*输入函数,为了简化代码*/
void setInfo(char pinfo[], char desinfo[]) {
 printf("%s:", pinfo);
 scanf("%s", desinfo);
}
/*输出每个学生的详细信息*/
void PrintAllInformation() {
 int i;
 printf("------------------------------------\n");
 for (i = 0; i < num; i++)
 printf("%s %s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result);
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*输出每个学生的部分信息*/
void PrintPartInformation() {
 int i;
 printf("------------------------------------\n");
 for (i = 0; i < num; i++)
 printf("%s %s %s\n", Students[i].Name, Students[i].Attandance_date, Students[i].Attandance_Result);
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*该函数实现的是向系统中添加同学*/
void ADD() {
 char ID[maxsize];
 printf("请输入学生的学号:");
 scanf("%s", ID);
 if (!judge(ID)) {
 printf("此人已经存在\n");
 printf("添加完成!请按回车键返回\n");
 wait_for_Enter();
 return;
 }
 strcpy(Students[num].Student_ID, ID);
 setInfo("请输入学生的姓名", Students[num].Name);
 setInfo("请输入学生的班级", Students[num].Class_Number);
 setInfo("请输入学生的考勤日期", Students[num].Attandance_date);
 setInfo("请输入学生的考勤结果出 勤 √ 旷 课 X 事 假 △ 病 假 ○ 迟 到 + 早 退 –", Students[num].Attandance_Result);
 num++;//同学人数加一
 printf("添加成功!按回车键返回\n");
 wait_for_Enter();
}
/*该函数实现的是查找的功能,可以按学号,姓名,考勤日期进行查找*/
void Find() {
 int i, op, flag = -1;
 char information[maxsize];
 printf("<1>按学号查找 <2>按姓名查找 <3>按考勤日期查找\n");
 scanf("%d", &op);
 if (op == 1) {
 printf("请输入该生学号:");
 scanf("%s", information);
 for (i = 0; i < num; i++) {
 if (strcmp(information, Students[i].Student_ID) == 0) printf("%s %s %s %s %s\n\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result), flag = 1;
 
 }
 } else if (op == 2) {
 printf("请输入该生姓名:");
 scanf("%s", information);
 for (i = 0; i < num; i++) {
 if (strcmp(information, Students[i].Name) == 0) printf("%s %s %s %s %s\n\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result), flag = 1;
 }
 } else {
 printf("请输入考勤日期:");
 scanf("%s", information);
 for (i = 0; i < num; i++) {
 if (strcmp(information, Students[i].Attandance_date) == 0) printf("%s %s %s %s %s\n\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result), flag = 1;;
 }
 }
 if (flag == -1) printf("不存在此信息!\n");
 printf("查找完成!按回车键返回\n");
 wait_for_Enter();
}
/*该函数实现的是对系统中已经存在的信息进行修改,类似上面的查找,也可以根据不同的信息选择想要修改的信息进行修改*/
void Change() {
 int i, j = -1;
 char op[2], information[maxsize], find[maxsize];
 printf("<1>按学号修改 <2>按姓名修改 <3>按考勤日期修改\n");
 scanf("%s", op);
 if (op[0] == '1') setInfo("请输入该生学号", information);
 else if (op[0] == '2') setInfo("请输入该生姓名", information);
 else setInfo("请输入考核日期", information);
 strcpy(find, information);
 if(op[0]=='1')
 for (i = 0; i < num; i++) {
 if (strcmp(find, Students[i].Student_ID) == 0) j = i;
 }
 else if(op[0]=='2')
 for (i = 0; i < num; i++) {
 if (strcmp(find, Students[i].Name) == 0) j = i;
 }
 else
 for (i = 0; i < num; i++) {
 if (strcmp(find, Students[i].Attandance_date) == 0) j = i;
 }
 if (j == -1) {
 printf("不存在要找的信息!\n");
 printf("修改完成!按回车键返回\n");
 wait_for_Enter();
 return;
 }
 setInfo("<1>修改学号 <2>修改姓名 <3>修改考勤日期", op);
 if (op[0] == '1') {
 setInfo("请输入修改后的新学号", information);
 strcpy(Students[j].Student_ID, information);
 } else if (op[0] == '2') {
 setInfo("请输入修改后的新姓名", information);
 strcpy(Students[j].Name, information);
 } else {
 setInfo("请输入修改后的新考核日期", information);
 strcpy(Students[j].Attandance_date, information);
 }
 printf("修改完成!按回车键返回!\n");
 wait_for_Enter();
}
/*该函数实现的是对已经存在于系统种的同学的信息进行删除操作,具体想法是学生人数num--,后面所有人的信息前移一个位置,实现信息的覆盖*/
void Delete() {
 int i, j,flag = -1;
 char op[2],information[maxsize];
 setInfo("请输入:<1>按学号删除<2>按姓名删除", op);
 if (op[0] == '1') {
 setInfo("请输入学号", information);
 for (i = 0; i < num; i++) {
 if (strcmp(Students[i].Student_ID, information) == 0) {
 flag = 1;
 for (j = i + 1; j < num; j++) {
 copy(&Students[i], &Students[j]);
 
 }
 }
 }
 } else {
 setInfo("请输入姓名", information);
 for (i = 0; i < num; i++) {
 if (strcmp(Students[i].Name, information) == 0) {
 flag = 1;
 for (j = i + 1; j < num; j++) {
 copy(&Students[i], &Students[j]);
 
 }
 }
 }
 }
 if (flag == -1) {
 printf("不存在此信息!\n");
 printf("删除完成!按回车键返回\n");
 wait_for_Enter();
 return ;
 }
 num--;
 printf("不存在此信息!\n");
 printf("删除完成!按回车键返回\n");
 wait_for_Enter();
}
/*此函数实现的是功能5 对系统中已经存在的信息进行输出*/
void Print() {
 int op;
 printf("请选择\n<1>部分打印(输出学生姓名和考勤日期和考勤情况)\n<2>全部打印(输出所有学生的所有信息):");
 scanf("%d", &op);
 if (op == 1) PrintPartInformation();
 else PrintAllInformation();
 
}
/*交换两个变量的所有成员的数值,因为成员都是char数组,所以用到了strcmp函数。此函数主要是为排序进行服务,采用指针进行交换*/
void exchange(student *a, student *b) {
 char tmp[maxsize];
 strcpy(tmp, a->Student_ID);
 strcpy(a->Student_ID, b->Student_ID);
 strcpy(b->Student_ID, tmp);
 
 strcpy(tmp, a->Name);
 strcpy(a->Name, b->Name);
 strcpy(b->Name, tmp);
 
 strcpy(tmp, a->Class_Number);
 strcpy(a->Class_Number, b->Class_Number);
 strcpy(b->Class_Number, tmp);
 
 strcpy(tmp, a->Attandance_Result);
 strcpy(a->Attandance_Result, b->Attandance_Result);
 strcpy(b->Attandance_Result, tmp);
 
 strcpy(tmp, a->Attandance_date);
 strcpy(a->Attandance_date, b->Attandance_date);
 strcpy(b->Attandance_date, tmp);
 return;
}
/*实现功能6排序,可以按学号,姓名,考勤日期进行排序,使用的是冒泡排序对所要求的信息进行排序*/
void Order() {
 int op, i, j;
 char tmp[maxsize];
 printf("请输入:<1>按学号从小到大排序 <2>按学生姓名ASCLL码排序 <3>按考勤日期从小到大排序:\n");
 scanf("%d", &op);
 if (op == 1) {
 for (i = 0; i < num; i++) {
 for (j = i+1; j < num; j++) {
 if (strcmp(Students[i].Student_ID, Students[j].Student_ID) > 0) {
 exchange(&Students[i], &Students[j]);
 }
 }
 }
 } else if (op == 2) {
 for (i = 0; i < num; i++) {
 for (j = i+1; j < num; j++) {
 if (strcmp(Students[i].Name, Students[j].Name) > 0) {
 exchange(&Students[i], &Students[j]);
 }
 }
 }
 } else {
 int month_1, month_2, day_1, day_2;
 for (i = 0; i < num; i++) {
 month_1 = atoi(Students[i].Attandance_date);
 day_1 = convert(Students[i].Attandance_date);
 for (j = i+1; j < num; j++) {
 month_2 = atoi(Students[j].Attandance_date);
 day_2 = convert(Students[j].Attandance_date);
 if(month_1>month_2) exchange(&Students[i], &Students[j]);
 else if(month_1==month_2&&day_1>day_2) exchange(&Students[i], &Students[j]);
 }
 
 }
 }
 printf("排序成功!按回车键返回\n");
 wait_for_Enter();
}
/*输出考勤明细表,考勤明细表具体值得是啥样的表,是按我个人的理解,如果我理解有问题,可以再叫我改*/
void Detail_Print() {
 int i, j;
 char tmp[maxsize];
 int month_1, month_2, day_1, day_2;
 for (i = 0; i < num; i++) {
 month_1 = atoi(Students[i].Attandance_date);
 day_1 = convert(Students[i].Attandance_date);
 for (j = 0; j < num; j++) {
 month_2 = atoi(Students[j].Attandance_date);
 day_2 = convert(Students[j].Attandance_date);
 if (month_1 < month_2) exchange(&Students[i], &Students[j]);
 else if (month_1 == month_2 && day_1 < day_2) exchange(&Students[i], &Students[j]);
 }
 }
 printf("------------------------------------\n");
 printf("考勤明细表:\n");
 printf("%s:\n", Students[0].Attandance_date);
 printf("%s %s %s %s\n", Students[0].Student_ID, Students[0].Name, Students[0].Class_Number, Students[0].Attandance_Result);
 strcmp(tmp, Students[0].Attandance_date);
 for (i = 1; i < num; i++) {
 if (strcmp(Students[i].Attandance_date, tmp) != 0) {
 printf("%s:\n", Students[i].Attandance_date);
 strcmp(tmp, Students[i].Attandance_date);
 }
 printf("%s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_Result);
 }
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*考勤日报表*/
void Daily_Print() {
 int i;
 char information[maxsize];
 setInfo("请输入要查看的日期", information);
 printf("------------------------------------\n");
 printf("%s的考勤情况:\n", information);
 for (i = 0; i < num; i++) {
 if (strcmp(information, Students[i].Attandance_date) == 0) printf("%s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_Result);
 }
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*考勤异常表,输出所有不是 ‘对勾 '的人的信息*/
void Informal_Print() {
 int i, cnt = 0;
 printf("------------------------------------\n");
 printf("考勤异常表:\n");
 for (i = 0; i < num; i++) {
 if (strcmp(Students[i].Attandance_Result, "√") != 0)
 printf("%s %s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result), cnt++;
 }
 printf("考勤异常人数:%d人\n", cnt);
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*请假异常表,输出所有请假的人的信息*/
void AskForLeave_Print() {
 int i, cnt = 0;
 printf("------------------------------------\n");
 printf("请假异常表\n");
 for (i = 0; i < num; i++) {
 if (strcmp(Students[i].Attandance_Result, "○") == 0 || strcmp(Students[i].Attandance_Result, "○") == 0)
 printf("%s %s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result), cnt++;
 }
 printf("请假人数:%d人\n", cnt);
 printf("------------------------------------\n");
 printf("打印成功!按回车键返回\n");
 wait_for_Enter();
}
/*事项功能7进行数据统计*/
void Statistics() {
 char op[2];
 setInfo("请选择\n<1>考勤明细表\n<2>考勤日报表\n<3>考勤异常表\n<4>请假汇总表",op);
 if (op[0] == '1') {
 Detail_Print();
 } else if (op[0] == '2') {
 Daily_Print();
 } else if (op[0] == '3') {
 Informal_Print();
 } else {
 AskForLeave_Print();
 }
}
 
int main() {
 int i, a, b = 1;
 FILE *fp= fopen("Manage.txt", "at+");
 if (!fp) {
 printf("错误!未能打开文件\n");
 exit(0);
 }
 fscanf(fp, "%d", &num);//读入已经在系统中的学生的个数
 printf("当前系统中储存的学生个数:%d人\n", num);
 for (i = 0; i < num; i++) {//读入系统中学生的信息
 fscanf(fp, "%s%s%s%s%s", &Students[i].Student_ID, &Students[i].Name, &Students[i].Class_Number, &Students[i].Attandance_date, &Students[i].Attandance_Result);
 }
 fclose(fp);
 while (b != 0) {
 printf("==============================================================================\n\n");
 printf("  大学生考勤系统\n\n");
 printf("==============================================================================\n\n");
 printf("<1> 新增学生数据 <2> 查找学生数据 <3>修改学生记录 \n");
 printf("<4>删除学生记录 <5> 显示学生考勤的数据列表 <6> 对指定数据进行排序 \n");
 printf("<7>进行数据统计 <8> quit\n\n");
 scanf("%d", &a);
 switch (a) {
 case 1:
 ADD();
 break;
 case 2:
 Find();
 break;
 case 3:
 Change();
 break;
 case 4:
 Delete();
 break;
 case 5:
 Print();
 break;
 case 6:
 Order();
 break;
 case 7:
 Statistics();
 break;
 case 8:
 printf("已退出\n");
 b = 0;
 break;
 }
 system("cls");//清屏函数,为了使界面更加美观
 }
 //在最后把信息输入到文件,保留以备下次运行使用
 FILE *F=fopen("Manage.txt","wt");//注意这里是wt 只写打开或建立一个文本文件,只允许写数据
 fprintf(F, "%d\n", num);
 for (int i = 0; i < num; i++) {
 fprintf(F, "%s %s %s %s %s\n", Students[i].Student_ID, Students[i].Name, Students[i].Class_Number, Students[i].Attandance_date, Students[i].Attandance_Result);
 }
 fclose(F);
 //文件操作结束
 return 0;
}

2020.6.14小小的更新一下:

很多小伙伴私信问我为什么自己机器上运行不了,可能的原因是因为我编写这个程序时用的是.cpp后缀命名的c++文件,而你用的是.c后缀命名的c语言文件,这二者有着很多的差别,例如c语言里是没有bool类型的变量的,所以到你们的机器上可能会报错。

大家可以把.c文件换成.cpp文件再次运行一下,或者bool类型的变量用int类型的0和1来代替,这个程序是绝对没有问题的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_43727229/article/details/102978439