前面我们学习了指针和结构体,接下来我们以 学生管理系统 为例,综合运用一下它们
要求实现功能:增删查改
一、功能实现
1.菜单
为了方便使用,首先我们应当创建一个菜单函数,便于后续操作
cs
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)
为了减少内存占用同时提高运行效率,这里我们采取动态分配的方式来分配内存
cs
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;
}
注:这里需要注意,由于重新分配了内存,并返回了新结构体,所以主函数处应注意接收返回值,否则调用的仍是旧的内存地址,会出现乱码(如下)
cs
// 修复:接收ctrl函数的返回值
struct Student *newStulist = ctrl(stulist, &size, &len);
if (newStulist == 0) { // 退出系统
free(stulist);
break;
}
stulist = newStulist; // 更新指针
3.查找
1)查找所有
传递、调用,代码如下
cs
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查找
同理,代码如下
cs
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即可
代码如下
cs
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.更改
循环、判断、修改、传递,代码如下
cs
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);
}
二、完整代码
cs
#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)
已知数组本身就是指针数据,即一个地址,所以指针变量在被分配内存后可以当作数组使用