You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何选择菜单选项4后无法输入学生全名?C语言程序问题

问题排查与修复:添加学生记录时跳过全名输入

核心问题原因

使用scanf("%d", &choice)读取菜单选项后,输入流中会残留一个换行符。后续调用fgets(buf1, BUFSIZE, stdin)时,会直接读取这个换行符,导致程序误以为已经输入了全名,直接跳过该步骤。

修复步骤

  1. 清除输入缓冲区残留字符
    在scanf("%d", &choice)之后,添加代码清除输入流中剩余的换行符:
scanf("%d", &choice);
// 清除缓冲区中残留的换行符
while(getchar() != '\n');
  1. 修复Student ID赋值逻辑
    当前代码中ultimat.studentID = id;未将输入的字符串转换为整数,需要添加atoi转换:
ultimat.studentID = atoi(buf2);
  1. 修复printRecords函数的Class ID访问错误
    原代码中(database)->classID只会访问第一条记录的Class ID,需要改为(database + i)->classID:
fprintf(stderr, "Class ID: %s\n", (database + i)->classID);
  1. 修复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;
    }
  1. 添加内存泄漏防护
    在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:00:57