C语言文件字符替换异常:双引号替换为成对符号失败
双引号替换逻辑的问题排查与修复
问题背景
需要将文本文件中的双引号按顺序替换:第1、3...个双引号替换为两个反引号(``),第2、4...个替换为两个单引号('')。原代码执行后未达到预期效果,具体输入输出如下:
输入文本(test.txt)
"some text here" "read it"
实际输出
"some text here" "read it"``````````````````````````````````````````````````
预期输出
``some text here'' ``read it''
原代码核心问题
- 缓冲区长度计算错误:
size_t chars = sizeof(buffer)/sizeof(buffer[0]);取了缓冲区总大小(51)而非实际读取的numRead值,导致遍历大量未初始化的空字符。 - 插入字符逻辑混乱:遇到双引号时的
while循环直接将指针移到缓冲区末尾,后续遍历逻辑完全失效,且未正确插入第二个替换符号。 - 文件写入逻辑错误:未将文件指针移到开头,导致处理后的内容追加到原文件末尾;且仅写入
MAX_READ个字符,截断了部分处理结果。 - 缓冲区溢出风险:固定大小的缓冲区在插入字符时容易超出容量,引发内存越界。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #define MAX_READ 50 int main(){ int fd; fd = open("test.txt", O_RDWR); if (fd == -1){ perror("Failed to open file"); exit(EXIT_FAILURE); } char buffer[MAX_READ * 2 + 1]; // 预留足够空间,应对字符数量翻倍的情况 ssize_t numRead; numRead = read(fd, buffer, MAX_READ); if (numRead == -1){ perror("Failed to read file"); exit(EXIT_FAILURE); } buffer[numRead] = '\0'; char result[MAX_READ * 2 + 1]; // 单独存储处理后的结果,避免原缓冲区操作混乱 int result_idx = 0; int quote_count = 1; // 记录双引号的序号,从1开始计数 for(int i = 0; i < numRead; i++){ if(buffer[i] == '"'){ if(quote_count % 2 != 0){ // 奇数序号双引号,替换为两个反引号 result[result_idx++] = '`'; result[result_idx++] = '`'; }else{ // 偶数序号双引号,替换为两个单引号 result[result_idx++] = '\''; result[result_idx++] = '\''; } quote_count++; }else{ // 非双引号字符直接复制到结果缓冲区 result[result_idx++] = buffer[i]; } } result[result_idx] = '\0'; // 确保字符串以终止符结尾 // 将文件指针移到文件开头,准备覆盖原内容 if(lseek(fd, 0, SEEK_SET) == -1){ perror("Failed to seek file"); exit(EXIT_FAILURE); } // 截断文件,避免原内容长度大于新内容时残留多余字符 if(ftruncate(fd, result_idx) == -1){ perror("Failed to truncate file"); exit(EXIT_FAILURE); } ssize_t numWrite = write(fd, result, result_idx); if (numWrite == -1){ perror("Failed to write file"); exit(EXIT_FAILURE); } close(fd); // 关闭文件,释放资源 return 0; }
关键修正说明
- 独立结果缓冲区:用单独的缓冲区存储处理后的内容,避免在原缓冲区中插入字符导致的遍历逻辑混乱,代码更易维护。
- 基于实际读取长度遍历:循环仅处理
numRead个有效字符,跳过未初始化的缓冲区空间。 - 直接写入替换符号:遇到双引号时直接写入两个目标符号,无需移动后续字符,逻辑简单且高效。
- 文件指针重置与截断:通过
lseek重置文件指针到开头,用ftruncate截断文件,确保原内容被完全覆盖,不会残留旧内容。 - 预留足够空间:结果缓冲区大小设为原缓冲区的2倍+1,确保每个双引号替换为两个字符时不会溢出。
内容的提问来源于stack exchange,提问作者Emil11
相关产品推荐
相关产品推荐

