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; } } }
错误原因分析
r+模式的文件长度残留问题:使用r+模式打开原文件时,写入新内容后原文件的长度不会自动调整。即使写入内容长度与原文件一致,也可能因文件系统缓存、指针位置等问题,导致末尾旧字符未被完全覆盖。- 字符类型不匹配:
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
相关产品推荐
相关产品推荐

