前面提到了数组最大的问题,就是不支持动态的扩缩容,它是静态内存分配的,一旦分配完成,其容量是固定的。为了支持学生的动态增长,才引入链表。
其实除了链表,还有一种解决该问题的方式,就是动态数组——动态申请内存的数组。
在之前学生成绩管理系统中,我们定义了一个存储学生信息的结构,该结构初始化大小为MAX_STUDENTS,导致系统最大支持的学生数为MAX_STUDENTS。
#define MAX_STUDENTS 100
Student students[MAX_STUDENTS]; // 学生数组
可以将它改为动态内存申请的形式(指针的典型用法)。
Student *stu_sys_init(int size)
{
Student *stu_sys;
stu_sys = malloc(size * sizeof(Student));
if (stu_sys == NULL) {
printf("student system malloc failed!\n");
}
return stu_sys;
}
其中核心处理如下,当存储学生的数组大小不够时,重新申请2倍内存,存放学生数据,释放原有内存。
if(student_count >= g_max_student) {
old_max_student = g_max_student;
g_max_student = g_max_student << 1;
stu_reinit = stu_sys_init(g_max_student);
if (stu_reinit == NULL) {
printf("Database is full!\n");
return;
}
memcpy(stu_reinit, students, old_max_student * sizeof(Student));
free(students);
students = stu_reinit;
}
所以整个系统可以重新实现为:
#include
#include
#include
#include // for access() function
#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"
#define TRUE 1
#define FALSE 0
typedef struct {
int id; // 学号
char name[MAX_NAME_LEN]; // 姓名
float score; // 成绩
} Student;
int student_count = 0; // 学生数量
Student *students; // 学生数组指针
int g_max_student = MAX_STUDENTS;
Student *stu_sys_init(int num)
{
Student *stu_sys;
stu_sys = malloc(num * sizeof(Student));
if (stu_sys == NULL) {
printf("student system malloc failed!\n");
}
return stu_sys;
}
int write_student_info(Student *s)
{
FILE *fp = fopen(STUDENT_SYSTEM, "a");
if (fp == NULL) {
printf("fopen student_system failed!\n");
return 1;
}
fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);
fclose(fp);
return 0;
}
int check_if_student_exsit(int id)
{
int i;
for(i = 0; i < student_count; i++) {
if(students[i].id == id) {
return 1;
}
}
return 0;
}
void update_student_info(Student s, int need_write)
{
Student *stu_reinit;
int old_max_student;
if(student_count >= g_max_student) {
old_max_student = g_max_student;
g_max_student = g_max_student << 1;
stu_reinit = stu_sys_init(g_max_student);
if (stu_reinit == NULL) {
printf("Database is full!\n");
return;
}
memcpy(stu_reinit, students, old_max_student * sizeof(Student));
free(students);
students = stu_reinit;
}
if (!check_if_student_exsit(s.id)) {
students[student_count++] = s;
if (need_write) {
printf("Student added successfully, all student: %d!\n", student_count);
write_student_info(&s);
}
} else {
printf("student has in db, do nothing!\n");
}
}
void add_student()
{
Student s;
printf("Enter student ID: ");
scanf("%d", &s.id);
printf("Enter student name: ");
scanf("%s", s.name);
s.score = 0.0; // 初始成绩设置为0
update_student_info(s, TRUE);
}
void print_title()
{
printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}
void display_all_students()
{
int i;
printf("-------- All students info --------\n");
if (student_count == 0) {
printf("No students!\n");
} else {
print_title();
for(i = 0; i < student_count; i++) {
printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);
}
}
printf("-------- End -----------\n");
}
void find_student_by_id()
{
int id, i;
printf("Enter student ID to search: ");
scanf("%d", &id);
for(i = 0; i < student_count; i++) {
if(students[i].id == id) {
print_title();
printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);
return;
}
}
printf("Student with ID %d not found!\n", id);
}
void find_student_by_name()
{
int i, is_find = 0;
char name[MAX_NAME_LEN];
printf("Enter student name to search: ");
scanf("%s", name);
for(i = 0; i < student_count; i++) {
if(strcmp(students[i].name, name) == 0) {
print_title();
printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);
is_find = 1;
}
}
if (is_find == 0) {
printf("Student with name %s not found!\n", name);
}
}
void add_score()
{
int id, i;
float score;
printf("Enter student ID: ");
scanf("%d", &id);
printf("Enter student score: ");
scanf("%f", &score);
for(i = 0; i < student_count; i++) {
if(students[i].id == id) {
students[i].score = score;
printf("Score added successfully!\n");
return;
}
}
printf("Student with ID %d not found!\n", id);
}
void display_average_score()
{
float total = 0.0;
int i;
for(i = 0; i < student_count; i++) {
total += students[i].score;
}
printf("Average score of all students: %.2f\n", total / student_count);
}
int init_student_info()
{
if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在
return 0;
}
FILE *fp = fopen(STUDENT_SYSTEM, "r");
if (fp == NULL) {
printf("fopen student_system failed!\n");
return 1;
}
#define BUF_SIZE 1024
char buf[BUF_SIZE];
int i = 0;
Student s;
while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {
sscanf(buf, "%d %s %f\n", &s.id, s.name, &s.score);
update_student_info(s, FALSE);
}
fclose(fp);
return 0;
}
int main()
{
int choice;
int ret;
students = stu_sys_init(MAX_STUDENTS);
if (students == NULL) {
printf("student system init failed, exit!\n");
return -1;
}
ret = init_student_info();
if (ret) {
printf("init_student_info failed!\n");
return 1;
}
display_all_students();
do {
printf("\nStudent Score Management System\n");
printf("1. Add Student\n");
printf("2. Display All Students\n");
printf("3. Find Student by ID\n");
printf("4. Find Student by Name\n");
printf("5. Add Score\n");
printf("6. Display Average Score\n");
printf("7. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch(choice) {
case 1:
add_student();
break;
case 2:
display_all_students();
break;
case 3:
find_student_by_id();
break;
case 4:
find_student_by_name();
break;
case 5:
add_score();
break;
case 6:
display_average_score();
break;
case 7:
printf("Exiting...\n");
break;
default:
printf("Invalid choice!\n");
}
} while(choice != 7);
return 0;
}
使用指针来动态管理内存的时候,需要注意释放内存,否则容易引起内存泄漏,导致系统内存被消耗完,最后可能出现oom的问题。