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

C语言偏移加密程序问题:复制回原文件时最后一个字符未被覆盖

偏移密码文件加密程序的末尾字符未覆盖问题排查与修复

问题背景

我正在编写一个使用偏移密码加密文本文件的简单C程序,需求如下:

  • 读取文本文件的每个字符,将每个字符的ASCII值增加某个整数,覆盖原文件完成加密。

我用temp.txt临时存储修改后的数据,再复制回原文件,但加密时最后一个字符未被覆盖:原文件内容为test,加密后temp.txt内容正确为uftu,但原文件最终变成uftt(末尾t未被修改)。

以下是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void encrypt(char *filename) {
    FILE *fp, *ft;
    int key = 1;
    char ch;
    fp = fopen(filename, "r+");
    ft = fopen("temp.txt", "w+");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to generate encryption key");
        exit(2);
    }
    //modifying ASCII values and storing it in temp.txt
    while (1) {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        ch = ch + key; //offset
        fputc(ch, ft);
    }
    rewind(fp);
    rewind(ft);
    //copying temp to original file
    while (1) {
        ch = fgetc(ft);
        if (ch == EOF)
            break;
        fputc(ch, fp);
    }
    printf("The file has been encrypted successfully");
    fclose(fp);
    fclose(ft);
}

void decrypt(char *filename) {
    FILE *fp, *ft;
    char ch;
    fp = fopen(filename, "r+");
    ft = fopen("temp.txt", "w+");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to access encryption key");
        exit(2);
    }
    //decrementing the chars by the same ASCII value to get back original text into temp.txt
    while (1) {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        ch = ch - 1;
        fputc(ch, ft);
    }
    rewind(fp);
    rewind(ft);
    //copying decrypted data to original file
    while (1) {
        ch = fgetc(ft);
        if (ch == EOF)
            break;
        fputc(ch, fp);
    }
    printf("File Decrypted Successfully");
}

int main(void) {
    int choice;
    char name[100], ch;
    FILE *fs, *ft;
    printf("To encrypt/decrypt a file: ");
    while (1) {
        printf("\nMENU");
        printf("\n1.Encrypt\n2.Decrypt\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);
        fflush(stdin);
        switch (choice) {
          case 1:
            printf("Enter the name of the file to be encrypted: ");
            fgets(name, 99, stdin);
            strtok(name,"\n");
            encrypt(name);
            return 0;
            break;
          case 2:
            printf("Enter the name of the file to be decrypted: ");
            fgets(name, 99, stdin);
            strtok(name,"\n");
            decrypt(name);
            return 0;
            break;
        }
    }
}

错误原因分析

  1. r+模式的文件长度残留问题:使用r+模式打开原文件时,写入新内容后原文件的长度不会自动调整。即使写入内容长度与原文件一致,也可能因文件系统缓存、指针位置等问题,导致末尾旧字符未被完全覆盖。
  2. 字符类型不匹配:fgetc()返回int类型(包含EOF的标识值-1),但代码中将其赋值给char类型变量。若系统中char为无符号类型,EOF会被转换为0xFF,导致无法正确判断循环终止条件,引发异常。

修复方案

方案1:替换原文件(更可靠)

放弃将temp内容复制回原文件的方式,改为关闭原文件后删除原文件,再将temp.txt重命名为原文件名,完全替换原文件,避免残留问题。

修改后的加密/解密函数示例:

void encrypt(char *filename) {
    FILE *fp, *ft;
    int key = 1;
    int ch; // 改为int类型,正确处理EOF
    fp = fopen(filename, "r");
    ft = fopen("temp.txt", "w");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to create temp file");
        fclose(fp);
        exit(2);
    }
    // 加密并写入temp
    while ((ch = fgetc(fp)) != EOF) {
        ch = ch + key;
        fputc(ch, ft);
    }
    // 关闭文件
    fclose(fp);
    fclose(ft);
    // 删除原文件,重命名temp为原文件名
    remove(filename);
    rename("temp.txt", filename);
    printf("The file has been encrypted successfully");
}

void decrypt(char *filename) {
    FILE *fp, *ft;
    int ch; // 改为int类型
    fp = fopen(filename, "r");
    ft = fopen("temp.txt", "w");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to create temp file");
        fclose(fp);
        exit(2);
    }
    // 解密并写入temp
    while ((ch = fgetc(fp)) != EOF) {
        ch = ch - 1;
        fputc(ch, ft);
    }
    fclose(fp);
    fclose(ft);
    remove(filename);
    rename("temp.txt", filename);
    printf("File Decrypted Successfully");
}

方案2:修复原文件写入逻辑

若坚持使用r+模式,需在写入完成后截断原文件到当前指针位置,并修正字符类型:

void encrypt(char *filename) {
    FILE *fp, *ft;
    int key = 1;
    int ch; // 改为int类型
    fp = fopen(filename, "r+");
    ft = fopen("temp.txt", "w+");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to create temp file");
        fclose(fp);
        exit(2);
    }
    // 加密写入temp
    while ((ch = fgetc(fp)) != EOF) {
        ch = ch + key;
        fputc(ch, ft);
    }
    rewind(fp);
    rewind(ft);
    // 复制temp到原文件
    while ((ch = fgetc(ft)) != EOF) {
        fputc(ch, fp);
    }
    // 截断原文件到当前写入位置
    ftruncate(fileno(fp), ftell(fp));
    printf("The file has been encrypted successfully");
    fclose(fp);
    fclose(ft);
    // 可选:删除临时文件
    remove("temp.txt");
}

额外优化点

  • 将ch的类型从char改为int,确保正确识别fgetc()返回的EOF。
  • 错误处理时关闭已打开的文件,避免资源泄漏。
  • 将加密/解密的key改为可配置参数,而非固定为1。
  • 避免使用fflush(stdin)(未定义行为),改用getchar()清除输入缓冲区的换行符。

内容的提问来源于stack exchange,提问作者Ayush Kumar Shukla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:54:26