1.面对的需求:
编写程序,建立一个班级学生的通讯录系统,每条信息包括:学号、姓名、性别、电话号码、住址、生日(为包含年、月、日信息的结构体变量)。编写两个查找函数,分别根据学生的学号(整型,不重复)、姓名(可能有同名)查找并输出学生的全部信息。在main函数中验证。要求:班级人数、学生记录均由键盘输入。
2.问题的解决思路:
首先我们可以定义一个结构体数组来存储学生的基本信息:学号,姓名,年龄,性别,生日等信息。结构体的是可以嵌套定义的,但不允许递归定义。接着根据用户输入的班级人数,创建一个足够大的结构体数组来存储学生记录,再通过循环来讲每个学生的基本信息输入到结构体中,然后编写两个函数,一个根据学号查找,另一个根据姓名查找。这两个函数都需要通过循环来遍历整个学生数组,检查每个学生的学号或姓名是否匹配,最后在main函数中验证结果。值得注意的是,由于本题涉及的变量名较多,建议在定义变量的时候尽量做到见文知意。
3.功能模块详述:
(1)定义结构体类型:包含哪些成员:
准确的说,我们定义了两结构体 ,第一个结构体名为DATA 是存放学生出生年月日的数据,birth_year ;birth_month;birth_day;是我们定义的变量,在名为students的结构体内我们定义学生的学号student_ID;学生的姓名student_name[20]将其存入到数组中;学生的年龄student_age;学生的性别char gender[30];将其存入到数组中;学生的家庭住址char address[30];
最后我们把第一个结构体引用到第二个里面 struct DATE date;结构体的是可以嵌套定义的,但不允许递归定义。
(2)定义和输入:定义哪些变量,输入什么,
具体说明实现功能:实现什么功能,如何实现(这里我把两者结合了):
在main主函数部分我们需要输入学生所在班级的总人数来确定用户需要输入多少位同学的信息方便后续的查找。所以我们在主函数部分定义了num来确定。由于在我们人为的控制了最多只能存入100位同学的信息,所以我们在输入每一位同学的信息时我们会做一次判断来确保程序不会出错,如果超出范围则会提示“请重新输入”提示用户重新输入。接着就是输入每一位学生的信息,这里需要做一个循环,循环的次数由之前输入学生人数来确定
for( int i=0;i<num;i++)(num由之前输入),即第一次循环结束后i的值为1,由于第一次的循环i=0;所以我们在写提示词的时候printf("第%d位学生的性别:\n", i + 1);需要在“,”后面写i+1,其他同理。在输入每一位学生信息的时候scanf("%ld", &stu[i].student_ID); 除了需要注意不同的占位符,还有&stu[i].student_ID 结构体数组的引用与结构体变量的引用相似,通过结构体成员运算符”.”来引用各个成员,例如后面的 stu[i].student_name,又因为student_name是一维数组,其数组名就可以代表其地址故不需要再加&。最后我们需要定义number_to_find变量来最后通过学号来查找该同学的信息,由于跟之前的相似,这里就不做多的解释。
接着程序从main主函数运行到调用函数部分,开始执行被调函数,这里我们定义find_number函数来判断是否有该学生,并输出相应的信息。由于我们定义的是void函数 所以没有返回值。void find_number( struct students stu[], int num, long int number_to_find) ,在括号里面的都是我们定义的形式参数,int exchange=0;在这里我们也定义了exchange来判断是否有该同学,如果有在打印全部的信息后,exchange会被赋值为1,而if(!exchange) printf("没有找到该学生\n");如果exchange=0则if里面的条件为真,就会输出“没有找到该学生”。至此通过学号来查找学生的方式结束。再然后通过学生姓名来查找也是通过相同的思路,不过我们需要通过#include<string.h>中的strcmp()方法来判断在姓名是否一样,因为这里需要通过比较字符串来判断。剩下的与通过学号判断的方法一样,就不在多说了。但是,无论在main函数中还是定义结构体变量时我们在定义变量名是要做到见文知意,这样不仅可以提高代码的阅读性和维护性也方便他人快速看懂你写的代码。
(3)输出:
但用户输入每一位学生信息后,通过输入其学号来判断是否存在该同学,如果存在,就输出全部信息。
请输入学生人数但不超过(100人):
1
请输入学生信息:
第1位学生的性别:
男
第1位学生的学号:
1221
第1位学生的姓名:
aaa
第1位学生的年龄:
19
第1位学生的家庭住址:
苏州市
第1位学生的生日:
2004 11 11
请输入要查找的学生学号:
1221
找到学生信息:
学号:1221
姓名:aaa
年龄:19
性别:男
家庭住址:苏州市
生日:2004--11--11
以上就是输出的内容。
4.源程序:
#include<stdio.h>
#include<string.h>
#define N 100
struct DATE{
int birth_year;
int birth_month;
int birth_day;
};
struct students{
long int student_ID;
char student_name[20];
int student_age;
char gender[30];
char address[30];
struct DATE date;
};
//查找学号的函数:
void find_number(struct students stu[], int num, long int number_to_find) {
int exchange=0;
for (int i = 0; i < num; i++)
{
if (stu[i].student_ID == number_to_find) {
printf("\n找到学生信息:\n");
printf("学号:%ld\n", stu[i].student_ID);
printf("姓名:%s\n", stu[i].student_name);
printf("年龄:%d\n", stu[i].student_age);
printf("性别:%s\n", stu[i].gender);
printf("家庭住址:%s\n", stu[i].address);
printf("生日:%d--%02d--%02d\n", stu[i].date.birth_year, stu[i].date.birth_month, stu[i].date.birth_day);
exchange=1;}
if(!exchange)
printf("没有找到该学生\n");
}
}
int main(){
int number_to_find;//目标要求判断的学号
int a;
int num,i;
struct students stu[100];//定义结构体stu
//输入学生人数
printf("请输入学生人数但不超过%d人\n:",N);
scanf("%d", &num);
if (num > N)
{
printf("学生人数不能超过%d\n", N);
}
//输入学生信息
printf("请输入学生信息:\n");
for (i=0;i<num;i++){
printf("第%d位学生的性别:\n", i + 1);
scanf(" %s", &stu[i].gender);
printf("第%d位学生的学号:\n", i + 1);
scanf("%ld", &stu[i].student_ID);
printf("第%d位学生的姓名:\n", i + 1);
scanf("%s", stu[i].student_name); // 数组名student_name表示首地址,不用再加 “&”
printf("第%d位学生的年龄:\n", i + 1);
scanf("%d", &stu[i].student_age);
printf("第%d位学生的家庭住址:\n", i + 1);
scanf("%s", stu[i].address);// 数组名address表示首地址,不用再加 “&”
printf("第%d位学生的生日:\n", i + 1);
scanf("%d %d %d", &stu[i].date.birth_year, &stu[i].date.birth_month, &stu[i].date.birth_day);
//学生信息查找---学号
printf("请输入要查找的学生学号:\n");
scanf("%ld", &number_to_find);
find_number(stu, num, number_to_find);
}
}
5.代码的优缺点:
有点:
(1).代码中定义DATE和students两个结构体变量,分别来存储学生的学号和生日信息,结构清晰,方便理解。
(2).利用函数实现功能的模块化,信息输入和输出是通过俩个不同的函数执行的,通过find_number函数实现了根据学号查找学生信息的功能,使得代码逻辑更加模块化,提高了代码的可读性。
(3).在在主函数中,当输入的学生人数超过预设的最大值N时,程序会提示错误并阻止继续输入,这有助于避免数据溢出的风险。在通过逐项输入学生的信息,使得交互过程清晰。
缺点:
(1).当前实现中,如果在第一个学生信息输入后就找到了匹配的学号,程序将直接输出结果并结束,而不会继续录入其他学生信息。所以改程序只能查找一位同学的信息,但如果想查找多位同学的信息时,应该在调用函数的时候加一层循环,来确定要调用几次函数,这个需要通过用户想查找几个学的来确定。
(2).在读取字符串(如gender、student_name、address)时,没有限制输入长度,如果用户输入的字符串超过了数组定义的大小,可能会导致数据溢出,从而程序错误。
6.思路拓展:
由于原来的程序只能查找一位同学的信息,不太符合现实的生活要求,所以在源代码上做了一次改变,我在通过学号查找学生信息外面套了一层while循环,并提示用户如果输入-1就停止查找学生信息。
While(true){
printf("请输入要查找的学生学号(如果输入-1就结束查找):\n");
scanf("%ld", &number_to_find);
find_number(stu, num, number_to_find);
}
if (number_to_find==-1){
break;}