C语言应用实例:学生管理系统1(指针、结构体综合应用,动态内存分配)
前面我们学习了指针和结构体,接下来我们以 学生管理系统 为例,综合运用一下它们
要求实现功能:增删查改
一、功能实现
1.菜单
为了方便使用,首先我们应当创建一个菜单函数,便于后续操作
void menu() {printf("Student Manage\n");printf("==[1001]添加学生==\n");printf("==[1002]查询所有学生==\n");printf("==[1003]根据ID查询学生==\n");printf("==[1004]根据ID修改信息==\n");printf("==[1005]根据ID删除信息==\n");printf("==[1006]退出系统==\n");printf("请输入功能编号:\n");
}2.添加
接下来我们可以围绕上述功能分别定义函数来实现
首先是添加学生操作(addStu)
为了减少内存占用同时提高运行效率,这里我们采取动态分配的方式来分配内存
struct Student *addStu(Student *stulist, int *size, int *len) {//扩容判断int s = *size;int l = *len;if (s == l) {l = l * 2;struct Student *newStulist = (Student *)malloc(sizeof(Student) * l);for (int i = 0; i < s; i++) {newStulist[i] = stulist[i];}stulist = newStulist;printf("***扩容完成len=%d***\n", l);}printf("请输入\n姓名 学号 年龄 学分\n");char name[50];int id;int age;float score;scanf("%s %d %d %f", name, &id, &age, &score);//创建一个学生结构体变量Student stu;//把信息都存入学生结构体中strcpy(stu.name, name);stu.id = id;stu.age = age;stu.score = score;stulist[s] = stu;*size = s + 1;*len = l;printf("添加成功\n");return stulist;
}注:这里需要注意,由于重新分配了内存,并返回了新结构体,所以主函数处应注意接收返回值,否则调用的仍是旧的内存地址,会出现乱码(如下)
// 修复:接收ctrl函数的返回值struct Student *newStulist = ctrl(stulist, &size, &len);if (newStulist == 0) { // 退出系统free(stulist);break;}stulist = newStulist; // 更新指针
3.查找
1)查找所有
传递、调用,代码如下
void printAllStu(Student *stulist, int *size) {int s = *size;printf("======All Students======\n");//分割线for (int i = 0; i < s; i++) {struct Student stu = stulist[i];printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);}
}2)ID查找
同理,代码如下
void getStuById(Student *stulist, int *size) {int s = *size;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);for (int i = 0; i < s; i++) {struct Student stu = stulist[i];if (stu.id == id) {printf("ID存在,信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);return;}}printf("没有查找到ID为%d的学生!\n", id);
}4.删除
同上,删除时只需将删除位置后的数往前挪动,覆盖住原数后size-1即可
代码如下
void delStuById(Student *stulist, int *size) {int s = *size;struct Student stu;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);int index = -1;for (int i = 0; i < s; i++) {stu = stulist[i];if (stu.id == id) {index = i;break;}}if (index == -1) {printf("没有查找到ID为%d的学生\n", id);return;}for (int i = index; i < s - 1; i++) {stulist[i] = stulist[i + 1];}printf("ID存在,被删除的信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);*size = s - 1;printf("没有查找到ID为%d的学生!\n", id);
}5.更改
循环、判断、修改、传递,代码如下
void changeInfoById(Student *stulist, int *size) {int s = *size;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);for (int i = 0; i < s; i++) {struct Student stu = stulist[i];if (stu.id == id) {printf("ID存在,信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);printf("请输入新的信息:\n姓名 学号 年龄 学分\n");char name[50];int sid;int age;float score;scanf("%s %d %d %f", name, &sid, &age, &score);strcpy(stu.name, name);stu.id = sid;stu.age = age;stu.score = score;stulist[i] = stu;return;}}printf("没有查找到ID为%d的学生!\n", id);
}二、完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct Student {char name[50];int id;int age;float score;
};void menu() {printf("Student Manage\n");printf("==[1001]添加学生==\n");printf("==[1002]查询所有学生==\n");printf("==[1003]根据ID查询学生==\n");printf("==[1004]根据ID修改信息==\n");printf("==[1005]根据ID删除信息==\n");printf("==[1006]退出系统==\n");printf("请输入功能编号:\n");
}
/*
//测试用例
void initTestData(Student *stulist, int *size, int *len){char str[5]={'a','b','c','d','e'};for(int i=0;i<100;i++){char name[50]="Name";name[4]=str[i%5];int id=i+100;int age=18+i%80;float score=12.5+i;scanf("%s %d %d %f", name, &id, &age, &score);//创建一个学生结构体变量Student stu;//把信息都存入学生结构体中strcpy(stu.name, name);stu.id = id;stu.age = age;stu.score = score;stulist[s] = stu;*size=s+1;}}
*/struct Student *addStu(Student *stulist, int *size, int *len) {//扩容判断int s = *size;int l = *len;if (s == l) {l = l * 2;struct Student *newStulist = (Student *)malloc(sizeof(Student) * l);for (int i = 0; i < s; i++) {newStulist[i] = stulist[i];}stulist = newStulist;printf("***扩容完成len=%d***\n", l);}printf("请输入\n姓名 学号 年龄 学分\n");char name[50];int id;int age;float score;scanf("%s %d %d %f", name, &id, &age, &score);//创建一个学生结构体变量Student stu;//把信息都存入学生结构体中strcpy(stu.name, name);stu.id = id;stu.age = age;stu.score = score;stulist[s] = stu;*size = s + 1;*len = l;printf("添加成功\n");return stulist;
}//打印所有学生信息
void printAllStu(Student *stulist, int *size) {int s = *size;printf("======All Students======\n");for (int i = 0; i < s; i++) {struct Student stu = stulist[i];printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);}}//根据id查找学生信息
void getStuById(Student *stulist, int *size) {int s = *size;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);for (int i = 0; i < s; i++) {struct Student stu = stulist[i];if (stu.id == id) {printf("ID存在,信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);return;}}printf("没有查找到ID为%d的学生!\n", id);
}//根据id修改信息
void changeInfoById(Student *stulist, int *size) {int s = *size;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);for (int i = 0; i < s; i++) {struct Student stu = stulist[i];if (stu.id == id) {printf("ID存在,信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);printf("请输入新的信息:\n姓名 学号 年龄 学分\n");char name[50];int sid;int age;float score;scanf("%s %d %d %f", name, &sid, &age, &score);strcpy(stu.name, name);stu.id = sid;stu.age = age;stu.score = score;stulist[i] = stu;return;}}printf("没有查找到ID为%d的学生!\n", id);
}//根据ID删除学生信息
void delStuById(Student *stulist, int *size) {int s = *size;struct Student stu;int id;printf("请输入一个学生ID:\n");scanf("%d", &id);int index = -1;for (int i = 0; i < s; i++) {stu = stulist[i];if (stu.id == id) {index = i;break;}}if (index == -1) {printf("没有查找到ID为%d的学生\n", id);return;}for (int i = index; i < s - 1; i++) {stulist[i] = stulist[i + 1];}printf("ID存在,被删除的信息如下:\n");printf("--姓名:%s | 年龄:%d | 学号:%d | 学分:%.2f|--\n", stu.name, stu.age, stu.id, stu.score);*size = s - 1;printf("没有查找到ID为%d的学生!\n", id);
}//控制面板
struct Student *ctrl(Student *stulist, int *size, int *len) {int cid = 0;scanf("%d", &cid);if (cid == 1001) {stulist = addStu(stulist, size, len);} else if (cid == 1002) {printAllStu(stulist, size);} else if (cid == 1003) {getStuById(stulist, size);} else if (cid == 1004) {changeInfoById(stulist, size);} else if (cid == 1005) {delStuById(stulist, size);} else if (cid == 1006) {free(stulist);return 0;} else {printf("输入有误,请重试!");}return stulist;
}int main() {int len = 10;int size = 0;struct Student *stulist = (Student *)malloc(sizeof(Student) * len);while (1) {printf("===========begin=========\n");menu();// 修复:接收ctrl函数的返回值struct Student *newStulist = ctrl(stulist, &size, &len);if (newStulist == 0) { // 退出系统free(stulist);break;}stulist = newStulist; // 更新指针printf("===========End===========\n\n");}return 0;
}三、常见问题
1.为什么要传递指针而不是数据本身?
函数内修改的是局部变量而不是原数据本身,如果想要修改原数据还需要在主函数中接收返回值,而传递地址(指针)则可以直接修改原数据,省去部分步骤
2.为什么数组不被定义就可以直接使用?
(以本文中stulist为例)
C语言中,指针可以使用数组下标语法:ptr[i]等价于*(ptr + i)
已知数组本身就是指针数据,即一个地址,所以指针变量在被分配内存后可以当作数组使用
