为何选择菜单选项4后无法输入学生全名?C语言程序问题
问题排查与修复:添加学生记录时跳过全名输入
核心问题原因
使用scanf("%d", &choice)读取菜单选项后,输入流中会残留一个换行符。后续调用fgets(buf1, BUFSIZE, stdin)时,会直接读取这个换行符,导致程序误以为已经输入了全名,直接跳过该步骤。
修复步骤
- 清除输入缓冲区残留字符
在scanf("%d", &choice)之后,添加代码清除输入流中剩余的换行符:
scanf("%d", &choice); // 清除缓冲区中残留的换行符 while(getchar() != '\n');
- 修复Student ID赋值逻辑
当前代码中ultimat.studentID = id;未将输入的字符串转换为整数,需要添加atoi转换:
ultimat.studentID = atoi(buf2);
- 修复
printRecords函数的Class ID访问错误
原代码中(database)->classID只会访问第一条记录的Class ID,需要改为(database + i)->classID:
fprintf(stderr, "Class ID: %s\n", (database + i)->classID);
- 修复
remove_record函数的逻辑错误
原函数的内存拷贝逻辑完全错误,正确的删除逻辑应该是遍历数据库,跳过要删除的记录(这里按Student ID匹配,可按需调整规则):
void remove_record(int studentID){ if (num_rec == 0){ printf("There is nothing to delete here!\n"); return; } struct record *tempMem = malloc(sizeof(struct record) * (num_rec - 1)); if (!tempMem) { perror("malloc failed"); return; } struct record *src = database; struct record *dest = tempMem; int found = 0; for (int i = 0; i < num_rec; i++){ if (src->studentID != studentID || found){ memcpy(dest++, src++, sizeof(struct record)); } else { // 释放要删除记录的字符串内存 free(src->full_name); free(src->class_name); free(src->classID); src++; found = 1; } } if (!found) { printf("Student ID %d not found!\n", studentID); free(tempMem); return; } free(database); database = tempMem; num_rec--; }
同时修改main函数中case5的调用,传入要删除的Student ID:
case 5: { int delID; printf("Enter the Student ID to delete: "); scanf("%d", &delID); while(getchar() != '\n'); // 清除换行 remove_record(delID); break; }
- 添加内存泄漏防护
在add_record函数中,重新分配内存时需先释放原数据库中每个记录的字符串内存:
else { struct record *tempMem = malloc(sizeof(struct record) * num_rec); if (!tempMem) { perror("malloc failed"); num_rec--; // 恢复计数 return; } struct record *mover = database; struct record *head = tempMem; int i; for (i=0; i< num_rec-1; i++){ // 循环次数为num_rec-1,预留位置添加新记录 memcpy(tempMem++, mover++, sizeof(struct record)); } memcpy(tempMem, &addTemp, sizeof(struct record)); // 释放原数据库的字符串内存 for (i=0; i< num_rec-1; i++){ free(database[i].full_name); free(database[i].class_name); free(database[i].classID); } free(database); database = head; }
完整修复后的代码
#include <stdio.h> #include <string.h> #include <stdbool.h> #include <stdlib.h> struct record { int studentID; char *class_name; char *classID; char *full_name; }; int num_rec = 0; void add_record(struct record); void remove_record(int); void printRecords(); struct record *database; void add_record(struct record addTemp){ num_rec++; if (num_rec == 1) { database = malloc(sizeof(struct record)); if (!database) { perror("malloc failed"); num_rec--; return; } memcpy(database, &addTemp, sizeof(struct record)); } else { struct record *tempMem = malloc(sizeof(struct record) * num_rec); if (!tempMem) { perror("malloc failed"); num_rec--; return; } struct record *mover = database; struct record *head = tempMem; int i; for (i=0; i < num_rec-1; i++){ memcpy(tempMem++, mover++, sizeof(struct record)); } memcpy(tempMem, &addTemp, sizeof(struct record)); // 释放原数据库的字符串内存 for (i=0; i < num_rec-1; i++){ free(database[i].full_name); free(database[i].class_name); free(database[i].classID); } free(database); database = head; } } void remove_record(int studentID){ if (num_rec == 0){ printf("There is nothing to delete here!\n"); return; } struct record *tempMem = malloc(sizeof(struct record) * (num_rec - 1)); if (!tempMem) { perror("malloc failed"); return; } struct record *src = database; struct record *dest = tempMem; int found = 0; for (int i = 0; i < num_rec; i++){ if (src->studentID != studentID || found){ memcpy(dest++, src++, sizeof(struct record)); } else { // 释放要删除记录的字符串内存 free(src->full_name); free(src->class_name); free(src->classID); src++; found = 1; } } if (!found) { printf("Student ID %d not found!\n", studentID); free(tempMem); return; } free(database); database = tempMem; num_rec--; } void printRecords(){ int i; for(i = 0; i < num_rec; i++) { int k = i + 1; printf("Student #%d\n", k); fprintf(stderr, "Student full name: %s\n", (database + i)->full_name); fprintf(stderr, "Student ID: %d\n", (database + i)->studentID); fprintf(stderr, "Class name: %s\n", (database + i)->class_name); fprintf(stderr, "Class ID: %s\n", (database + i)->classID); printf("\n"); } } int main(){ const int BUFSIZE = 100; static int accesses = 0; int choice = 0; while (true) { printf("1. print all records \n"); printf("2. print number of records \n"); printf("3. print size of database \n"); printf("4. add record \n"); printf("5. delete record \n"); printf("6. print number of accesses to a database \n"); printf("7. exit \n"); scanf("%d", &choice); // 清除缓冲区残留的换行符 while(getchar() != '\n'); switch (choice){ case 1: printf("This is our current database of records: \n"); if (num_rec == 0){ printf("Oh... It looks like the data base is currently empty.\n"); accesses++; break; } else{ printRecords(); accesses++; break; } case 2: printf("The current number of student records is: %d records\n", num_rec); accesses++; break; case 3: int size_database; int size_struct = sizeof(struct record); size_database = size_struct * num_rec; printf("The size of our database is %i\n", size_database); accesses++; break; case 4: { char *buf1 = malloc(BUFSIZE); char *buf2 = malloc(BUFSIZE); char *buf3 = malloc(BUFSIZE); char *buf4 = malloc(BUFSIZE); struct record ultimat; printf("Please enter this students Full Name: \n"); fgets(buf1, BUFSIZE, stdin); if ((strlen(buf1) > 0) && (buf1[strlen(buf1) - 1] == '\n')) buf1[strlen(buf1) - 1] = '\0'; ultimat.full_name = malloc(strlen(buf1)+1); strcpy(ultimat.full_name, buf1); printf("Please enter this students Student ID: \n"); fgets(buf2, BUFSIZE, stdin); if ((strlen(buf2) > 0) && (buf2[strlen(buf2) - 1] == '\n')) buf2[strlen(buf2) - 1] = '\0'; ultimat.studentID = atoi(buf2); printf("Please enter the Class Name: \n"); fgets(buf3, BUFSIZE, stdin); if ((strlen(buf3) > 0) && (buf3[strlen(buf3) - 1] == '\n')) buf3[strlen(buf3) - 1] = '\0'; ultimat.class_name = malloc(strlen(buf3)+1); strcpy(ultimat.class_name, buf3); printf("Please enter this students Class ID: \n"); fgets(buf4, BUFSIZE, stdin); if ((strlen(buf4) > 0) && (buf4[strlen(buf4) - 1] == '\n')) buf4[strlen(buf4) - 1] = '\0'; ultimat.classID = malloc(strlen(buf4)+1); strcpy(ultimat.classID, buf4); add_record(ultimat); printf("Alright, I added this student to the database! \n"); free(buf1); free(buf2); free(buf3); free(buf4); accesses++; break; } case 5: { int delID; printf("Enter the Student ID to delete: "); scanf("%d", &delID); while(getchar() != '\n'); remove_record(delID); break; } case 6: printf("The current number of data base accesses is: %d accesses\n", accesses); break; case 7: // 退出前释放所有内存 for (int i=0; i<num_rec; i++){ free(database[i].full_name); free(database[i].class_name); free(database[i].classID); } free(database); exit(0); } } return 0; }
内容的提问来源于stack exchange,提问作者zujika
相关产品推荐
相关产品推荐

