C语言学生管理系统多文件拆分、头文件及Makefile编写方法
C语言多文件拆分规则与问题修复
核心拆分规则
- 头文件(.h)仅存放声明内容:包括公共结构体定义、函数声明、宏定义,禁止在头文件中写函数实现、全局变量的实际定义,否则多文件包含时会触发重复定义错误
- 头文件必须添加防重复包含保护,避免同一头文件被多次引入引发编译冲突
- 跨文件使用的全局变量,需要在头文件中用
extern关键字声明,仅在某一个.c源文件中做实际的变量定义 - 自定义头文件在.c文件中引入时使用双引号包裹,系统标准库头文件使用尖括号包裹
- 主函数
main()单独存放于main.c,业务处理逻辑独立存放于process.c
原代码自带bug说明
拆分前的原始代码本身存在多处逻辑错误,拆分时一并修复:
List函数循环条件书写错误:while(temp =! NULL)为赋值+逻辑非运算,正确写法为while(temp != NULL)Search、Delete函数字符串比较逻辑错误:误用字符串拷贝函数strcpy做比较,会直接覆盖链表节点存储的姓名数据,正确比较函数为strcmp,字符串相等时返回值为0Delete函数结构体类型书写错误:定义的结构体名为struct Person,代码中误写为struct Student- 主循环逻辑缺陷:执行完单次操作后未重新读取用户输入,会触发死循环
- 打印语句缺少换行符,输出内容会挤在同一行
拆分后完整代码
1. main.h(公共头文件)
#ifndef MAIN_H #define MAIN_H // 引入依赖的标准库 #include <stdio.h> #include <stdlib.h> #include <string.h> // 公共结构体定义 struct Person{ char name[20]; char phone[15]; struct Person* next; }; // 跨文件全局变量声明 extern struct Person* head; // 功能函数声明 void Enroll(char* name, char* phone); void List(); void Search(char* name); void Delete(char* name); #endif
2. process.c(数据处理逻辑实现)
#include "main.h" // 全局链表头节点实际定义,整个程序仅在此处定义一次 struct Person* head = NULL; void Enroll(char* name, char* phone){ struct Person* person = (struct Person*) malloc(sizeof(struct Person)); strcpy(person->name, name); strcpy(person->phone, phone); person->next = NULL; if (head == NULL){ head = person; }else{ person->next = head; head = person; } } void List(){ struct Person* temp = head; printf("---List---\n"); while(temp != NULL){ printf("%s %s\n", temp->name, temp->phone); temp = temp->next; } } void Search(char* name){ struct Person* temp = head; while(temp != NULL){ if (strcmp(temp->name, name) == 0){ printf("%s %s\n", temp->name, temp->phone); return; } temp = temp->next; } printf("%s Could not find\n", name); } void Delete(char* name){ struct Person* temp1 = head; struct Person* temp2 = head; while(temp1 != NULL){ if (strcmp(temp1->name, name) == 0){ if (temp1 == temp2){ head = head->next; free(temp1); }else{ temp2->next = temp1->next; free(temp1); } printf("%s Delete Success\n", name); return; } temp2 = temp1; temp1 = temp1->next; } printf("%s Could not find\n", name); }
3. main.c(主函数交互逻辑)
#include "main.h" int main(){ char name[20]; char phone[15]; int select; printf("Welcome to the Enrollment Management System!\n"); printf("[1] Enroll [2] List [3] Search [4] Delete [5]Quit\nSelection: "); scanf("%d", &select); while(select != 5){ if (select == 1){ printf("Name: "); scanf("%s", name); printf("Phone: "); scanf("%s", phone); Enroll(name, phone); } if (select == 2){ List(); } if (select == 3){ printf("Name: "); scanf("%s", name); Search(name); } if (select == 4){ printf("Name: "); scanf("%s", name); Delete(name); } // 每次操作完成后重新读取用户选择,避免死循环 printf("\n[1] Enroll [2] List [3] Search [4] Delete [5]Quit\nSelection: "); scanf("%d", &select); } return 0; }
4. Makefile(编译配置)
CC = gcc CFLAGS = -Wall -g TARGET = student_manage OBJS = main.o process.o all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^ clean: rm -f $(OBJS) $(TARGET)
编译运行方法
在代码所在目录执行make命令即可自动完成编译,生成名为student_manage的可执行文件,执行./student_manage即可启动程序;执行make clean可清除所有编译生成的中间文件和可执行程序。
内容的提问来源于stack exchange,提问作者Daulet Suyenish
相关产品推荐
相关产品推荐

