write()写入文件出现乱码而非目标字符串的问题求助
问题分析与解决方案
核心问题
sprintf的未定义行为
你在循环中使用sprintf(stringnums, "%d %s", ..., stringnums),输入缓冲区和输出缓冲区是同一个字符数组。根据C标准,这种重叠的内存操作属于未定义行为,会直接导致内存读写混乱,引发乱码。文件打开方式的潜在问题
open(path, O_WRONLY)存在两个隐患:- 若目标文件不存在,
open会直接报错; - 若文件已存在且原有内容长度大于本次写入内容,文件末尾的旧内容不会被清除,也会表现为乱码。
- 若目标文件不存在,
无效尝试的原因
- 仅初始化
stringnums为"\0":第一次循环没问题,但后续sprintf的重叠操作仍会破坏内存数据,无法解决根本问题; - 用
sizeof替代strlen:会写入数组中未使用的内存区域(包含随机值),反而加重乱码。
修复方案
1. 解决sprintf重叠问题
避免输入输出缓冲区重叠,用以下两种方式构建字符串:
方法一:临时缓冲区拼接
// 先初始化字符串为空 stringnums[0] = '\0'; for(int i = 0; i < NUMINROW; i++){ char temp[6]; // 足够存储数字+空格(如"29 ") int num = rand() % (NUMSIZE * 10); snprintf(temp, sizeof(temp), "%d ", num); // 临时存储拼接后的完整字符串 char temp_full[(NUMSIZE + 1) * NUMINROW + 1]; snprintf(temp_full, sizeof(temp_full), "%s%s", temp, stringnums); strcpy(stringnums, temp_full); }
方法二:内存移动高效拼接
无需临时缓冲区,直接移动原有字符串腾出空间写入新内容:
stringnums[0] = '\0'; int current_len = 0; const int max_len = (NUMSIZE + 1) * NUMINROW + 1; for(int i = 0; i < NUMINROW; i++){ int num = rand() % (NUMSIZE * 10); // 计算当前数字转为字符串的长度(含空格) int num_str_len = snprintf(NULL, 0, "%d ", num); // 确保不超出数组容量 if(current_len + num_str_len >= max_len) break; // 将原有字符串向后移动,腾出开头空间 memmove(stringnums + num_str_len, stringnums, current_len + 1); // 写入新数字到开头 snprintf(stringnums, num_str_len + 1, "%d ", num); current_len += num_str_len; }
2. 修正文件打开方式
添加O_CREAT(文件不存在时创建)和O_TRUNC(清空已有内容)标志,并设置合理的文件权限:
desc = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
完整修复后的代码
#include <fcntl.h> #include <unistd.h> #include <time.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #define NUMINROW 10 #define NUMSIZE 3 int main(){ int desc; struct flock fl; char stringnums[(NUMSIZE + 1) * NUMINROW + 1]; char* path = "randnums.txt"; srand(time(NULL)); // 修正文件打开方式 desc = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (desc == -1) perror("open"); if (fcntl(desc, F_GETLK, &fl) == -1) perror("fcntl_getlk"); fl.l_type = F_WRLCK; if (fcntl(desc, F_SETLK, &fl) == -1) perror("fcntl_setlk"); // 修正字符串构建逻辑 stringnums[0] = '\0'; int current_len = 0; const int max_len = (NUMSIZE + 1) * NUMINROW + 1; for(int i = 0; i < NUMINROW; i++){ int num = rand() % (NUMSIZE * 10); int num_str_len = snprintf(NULL, 0, "%d ", num); if(current_len + num_str_len >= max_len) break; memmove(stringnums + num_str_len, stringnums, current_len + 1); snprintf(stringnums, num_str_len + 1, "%d ", num); current_len += num_str_len; } if (write(desc, stringnums, strlen(stringnums)) == -1) perror("write"); fl.l_type = F_UNLCK; if (fcntl(desc, F_SETLK, &fl) == -1) perror("fcntl_setlk"); if (close(desc) == -1) perror("close"); return 0; }
内容的提问来源于stack exchange,提问作者Єгорій
相关产品推荐
相关产品推荐

