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

C语言中删除并重命名两个文本文件时触发段错误

葡萄园招聘助手系统段错误问题排查与修复

在实现「Drink My Friend」葡萄园招聘助手管理系统时,第二次调用addApplicant后,执行删除records.txt并将temp.txt重命名为records.txt操作时出现段错误。尝试在deleteThirdLineWithNumber函数调用前后手动关闭文件,问题仍未解决。

需求背景

春天已至「Drink My Friend」葡萄园,需招聘春季可工作的助手。求职者需提供姓名及可工作的星期几,农场各日期所需工人数量固定,满员则不再接收申请。需实现求职者数据的增删改查及列表生成功能。

问题代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
    
enum days_of_week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
};
void deleteThirdLineWithNumber(const char* filename) {
    FILE* fp = fopen(filename, "r+");
    if (fp == NULL) {
        printf("Error opening file\n");
        return;
    }
    char buffer[100];
    int lineNumber = 1;
    int numberFound = 0;
    
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        if (lineNumber == 3 && isdigit(buffer[0])) {
            numberFound = 1;
            break;
        }
        lineNumber++;
    }
    
    if (numberFound) {
        fseek(fp, 0, SEEK_SET);
        int currentLine = 1;
        FILE* tmp = fopen("temp2.txt", "w");
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            if (currentLine != 3) {
                fprintf(tmp, "%s", buffer);
            }
            currentLine++;
        }
        fclose(fp);
        fclose(tmp);
        remove(filename);
        rename("temp2.txt", filename);
    }
    else {
        printf("No number found on third line\n");
        fclose(fp);
    }
}

void addApplicant(char *name, char *day, int week,char *filename) {
    int weekIndex = 0;
    if(strcmp(day, "MONDAY") == 0){
        weekIndex = week*7 + MONDAY;
    }
    else if(strcmp(day, "TUESDAY") == 0){
        weekIndex = week*7 + TUESDAY;
    }
    else if(strcmp(day, "WEDNESDAY") == 0){
        weekIndex = week*7 +WEDNESDAY;
    }
    else if(strcmp(day, "THURSDAY") == 0){
        weekIndex = week*7 + THURSDAY;
    }
    else if(strcmp(day, "FRIDAY") == 0){
        weekIndex = week*7+FRIDAY;
    }
    else if(strcmp(day, "SATURDAY") == 0){
        weekIndex = week*7+THURSDAY;
    }
    else if(strcmp(day, "SUNDAY") == 0){
        weekIndex = SUNDAY  + 7*week;
    }
    if (weekIndex < 0 || weekIndex >= 84) {
        printf("Sorry, %s, week %d does not exist.\n", day, weekIndex);
        return;
    }
    FILE *fp,*temp;
    fp = fopen(filename, "r");
    temp = fopen("temp.txt", "w+");
    if (fp == NULL && temp ==NULL) {
        printf("Error opening file\n");
        return;
    }
    char buffer[100];
    
    for (int i = 0; i < 84*3; i++)
    {
        
         
        if(i % 3 == 0)
        {
            fprintf(temp,"%s",fgets(buffer, sizeof(buffer), fp));
            fgets(buffer, sizeof(buffer), fp);
              
        }
        else if ( i % 3 == 1)
        {
            int numberOfHelpers = atoi(buffer);
            char ch[100];
            if (i == (weekIndex*3 +1))
            {
                if (numberOfHelpers <= 0) {
                    printf("Sorry, the maximum number of helpers has been reached for %s, week %d.\n", day, week);
                }
           
                fprintf(temp, "%d\n", numberOfHelpers-1);
            }
            fprintf(temp, "%d\n", numberOfHelpers);
            fgets(buffer, sizeof(buffer), fp);
        }
        else
        {
            if (i == (weekIndex*3 +2))
            {
                char* names =(buffer);
                int pos = strcspn(names, "\n"); // find position of newline character
                if (pos < strlen(names)) {
                    names[pos] = '\0'; // replace newline character with null character
                }
                strcat(names, name);  
                printf("%s",names);
       
                fprintf(temp,"%s\n",names);
            }
        }
    }
    
    fclose(fp);
    fclose(temp);
    deleteThirdLineWithNumber("temp.txt"); remove(filename); 
    rename("temp.txt",filename); 
}
void initialisingFile(int maximumnumberOfhelper)
{
    char day[10];
    FILE *fp;
    fp = fopen("records.txt", "w");
    if (fp == NULL) {
        printf("Error opening file\n");
        return;
    }
    for (int i = 0; i < 84; i++) {
        if (i % 7 == 0) {
            strcpy(day, "MONDAY   ");
        } else if (i % 7 == 1) {
            strcpy(day, "TUESDAY  ");
        } else if (i % 7 == 2) {
            strcpy(day, "WEDNESDAY");
        } else if (i % 7 == 3) {
            strcpy(day, "THURSDAY ");
        } else if (i % 7 == 4) {
            strcpy(day, "FRIDAY   ");
        } else if (i % 7 == 5) {
            strcpy(day, "SATURDAY ");
        } else {
            strcpy(day, "SUNDAY   ");
        }
        fprintf(fp, "%s\n", day);
        fprintf(fp, "%d\n", maximumnumberOfhelper);
        fprintf(fp, "%s\n", "people:");
    }
       
    fclose(fp);
}
int main() {
    initialisingFile(10);
    addApplicant("sarveshwar", "MONDAY", 0,"records.txt");
    addApplicant("sarveshwar", "MONDAY", 0,"records.txt");
    return 0;
}

问题分析

  1. 文件读取逻辑混乱

    • addApplicant循环中i%3==0分支连续调用两次fgets,但仅写入一次内容到临时文件,导致后续buffer内容与预期不符,甚至出现文件指针越界读取,触发非法内存访问。
    • i%3==2分支仅在匹配目标索引时写入内容,其余情况完全跳过,导致临时文件缺失大量行,后续deleteThirdLineWithNumber处理时读取到不完整的文件,引发错误。
  2. 栈内存溢出

    • 在i%3==2的目标索引分支中,直接对栈上的buffer执行strcat操作,当原buffer内容加上name的长度超过buffer的100字节上限时,会导致栈溢出,直接触发段错误。
  3. 星期枚举值错误

    • 处理SATURDAY时,错误使用了THURSDAY的枚举值,导致对应日期的索引计算错误,后续操作会修改错误的行。
  4. 文件操作无错误检查

    • deleteThirdLineWithNumber和addApplicant中的文件删除、重命名操作未做错误检查,若操作失败会导致后续流程异常。

修复后的代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
    
enum days_of_week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
};

void deleteThirdLineWithNumber(const char* filename) {
    FILE* fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("Error opening file\n");
        return;
    }
    char buffer[100];
    int lineNumber = 1;
    int numberFound = 0;
    
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        if (lineNumber == 3 && isdigit(buffer[0])) {
            numberFound = 1;
            break;
        }
        lineNumber++;
    }
    
    if (numberFound) {
        fseek(fp, 0, SEEK_SET);
        int currentLine = 1;
        FILE* tmp = fopen("temp2.txt", "w");
        if (tmp == NULL) {
            printf("Error creating temp file\n");
            fclose(fp);
            return;
        }
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            if (currentLine != 3) {
                fprintf(tmp, "%s", buffer);
            }
            currentLine++;
        }
        fclose(fp);
        fclose(tmp);
        if (remove(filename) != 0) {
            printf("Error removing original file\n");
            remove("temp2.txt");
            return;
        }
        if (rename("temp2.txt", filename) != 0) {
            printf("Error renaming temp file\n");
            remove("temp2.txt");
            return;
        }
    } else {
        printf("No number found on third line\n");
        fclose(fp);
    }
}

void addApplicant(char *name, char *day, int week, char *filename) {
    int weekIndex = -1;
    if(strcmp(day, "MONDAY") == 0){
        weekIndex = week*7 + MONDAY;
    } else if(strcmp(day, "TUESDAY") == 0){
        weekIndex = week*7 + TUESDAY;
    } else if(strcmp(day, "WEDNESDAY") == 0){
        weekIndex = week*7 + WEDNESDAY;
    } else if(strcmp(day, "THURSDAY") == 0){
        weekIndex = week*7 + THURSDAY;
    } else if(strcmp(day, "FRIDAY") == 0){
        weekIndex = week*7 + FRIDAY;
    } else if(strcmp(day, "SATURDAY") == 0){
        weekIndex = week*7 + SATURDAY;
    } else if(strcmp(day, "SUNDAY") == 0){
        weekIndex = week*7 + SUNDAY;
    }

    if (weekIndex < 0 || weekIndex >= 84) {
        printf("Sorry, %s week %d does not exist.\n", day, week);
        return;
    }

    FILE *fp = fopen(filename, "r");
    FILE *temp = fopen("temp.txt", "w");
    if (fp == NULL || temp == NULL) {
        printf("Error opening file\n");
        if (fp) fclose(fp);
        if (temp) fclose(temp);
        return;
    }

    char buffer[100];
    int currentEntry = 0;
    while (currentEntry < 84) {
        if (!fgets(buffer, sizeof(buffer), fp)) break;
        fprintf(temp, "%s", buffer);

        if (!fgets(buffer, sizeof(buffer), fp)) break;
        int numberOfHelpers = atoi(buffer);
        if (currentEntry == weekIndex) {
            if (numberOfHelpers <= 0) {
                printf("Sorry, the maximum number of helpers has been reached for %s week %d.\n", day, week);
                fprintf(temp, "%d\n", numberOfHelpers);
            } else {
                fprintf(temp, "%d\n", numberOfHelpers - 1);
            }
        } else {
            fprintf(temp, "%s", buffer);
        }

        if (!fgets(buffer, sizeof(buffer), fp)) break;
        if (currentEntry == weekIndex && numberOfHelpers > 0) {
            buffer[strcspn(buffer, "\n")] = '\0';
            char names[200];
            strcpy(names, buffer);
            strcat(names, " ");
            strcat(names, name);
            fprintf(temp, "%s\n", names);
        } else {
            fprintf(temp, "%s", buffer);
        }

        currentEntry++;
    }

    fclose(fp);
    fclose(temp);

    deleteThirdLineWithNumber("temp.txt");
    if (remove(filename) != 0) {
        printf("Error removing original file\n");
        remove("temp.txt");
        return;
    }
    if (rename("temp.txt", filename) != 0) {
        printf("Error renaming temp file\n");
        remove("temp.txt");
        return;
    }
}

void initialisingFile(int maximumnumberOfhelper) {
    char day[10];
    FILE *fp = fopen("records.txt", "w");
    if (fp == NULL) {
        printf("Error opening file\n");
        return;
    }
    for (int i = 0; i < 84; i++) {
        switch (i % 7) {
            case 0: strcpy(day, "MONDAY   "); break;
            case 1: strcpy(day, "TUESDAY  "); break;
            case 2: strcpy(day, "WEDNESDAY"); break;
            case 3: strcpy(day, "THURSDAY "); break;
            case 4: strcpy(day, "FRIDAY   "); break;
            case 5: strcpy(day, "SATURDAY "); break;
            case 6: strcpy(day, "SUNDAY   "); break;
        }
        fprintf(fp, "%s\n", day);
        fprintf(fp, "%d\n", maximumnumberOfhelper);
        fprintf(fp, "people:\n");
    }
    fclose(fp);
}

int main() {
    initialisingFile(10);
    addApplicant("sarveshwar", "MONDAY", 0, "records.txt");
    addApplicant("sarveshwar", "MONDAY", 0, "records.txt");
    return 0;
}

修复说明

  1. 重构addApplicant的文件读取逻辑,按每个日期条目(3行一组)读取和写入,避免原循环中混乱的fgets调用和内容缺失问题。
  2. 将姓名拼接操作改为使用更大的临时数组,避免栈溢出风险。
  3. 修复SATURDAY对应的枚举值错误。
  4. 在文件删除和重命名操作中增加错误检查,避免操作失败后引发异常。
  5. 调整deleteThirdLineWithNumber的文件打开模式为r,并增加临时文件创建的错误检查。

内容的提问来源于stack exchange,提问作者Sarveshwar Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:07:35