char[]截断后出现多余字符的问题排查与修复咨询
问题修复:char[]截断后出现多余字符
问题现象
按指定长度截断char[]时,新数组频繁出现乱码,不同截断长度表现如下:
- 截取1/2个字符时,结果带冗余乱码:
@▬w @▬n @▬k @▬a // 预期为d、n、k、a的反转结果 @id @an @ok @la // 预期为di、an、ok、la的反转结果 - 截取3个字符时结果正常:
nid ran rok mla - 截取超过3个字符时再次出现乱码:
qp░nnid qp░aran qp░trok qp░amla - 截取长度超过最长行时结果正常:
eynnid scnaran etrok amla
问题代码
char **read(FILE *file, int lineLength, int *pLines) { size_t total = 0; size_t allocated = START; int sor = 0; char buffer[MAX_LENGTH]; char shortened[lineLength]; ///////// //printf("%d", sizeof(shortened)); char **lines= (char **)malloc(allocated* sizeof(char *)); while (fgets(buffer, MAX_LENGTH, file) != NULL) { for (int i = 0; i < lineLength; i++) { shortened[i] = buffer[i]; } int length = strlen(shortened); if (shortened[length - 1] == '\n') { shortened[length - 1] = '\0'; } if (line == allocated) { allocated*= 2; lines= realloc(sorok, allocated* sizeof(char *)); } lines[line] = (char *)malloc(lineLength); strcpy(lines[line], shortened); line++; } *pLines = line; return lines; }
修复要点及修正代码
核心问题分析
- 字符串无终止符:C语言字符串必须以
'\0'结尾,strlen、strcpy等函数依赖它识别边界。直接复制lineLength个字符后,shortened未添加终止符,导致函数越界读取内存产生乱码。 - 内存分配不足:
malloc(lineLength)仅分配lineLength字节,但存储截断后的字符串需要额外1字节存'\0',否则strcpy会越界写入。 - 变量名错误:代码中出现未定义的
line、sorok变量,属于笔误(sor应为line,sorok应为lines)。 - 换行符处理越界:若截断长度小于原行长度,换行符不在
shortened内,此时访问shortened[length-1]会越界。
修复后的代码
#include <stdlib.h> #include <string.h> #include <stdio.h> #define START 4 #define MAX_LENGTH 1024 char **read(FILE *file, int lineLength, int *pLines) { size_t allocated = START; int line = 0; // 修正变量名,替换原未使用的sor char buffer[MAX_LENGTH]; // 给shortened多留1字节存终止符 char shortened[lineLength + 1]; char **lines = (char **)malloc(allocated * sizeof(char *)); if (!lines) return NULL; // 新增内存分配失败判断 while (fgets(buffer, MAX_LENGTH, file) != NULL) { // 复制指定长度字符 memcpy(shortened, buffer, lineLength); // 强制添加字符串终止符,确保strlen等函数正常工作 shortened[lineLength] = '\0'; // 处理换行符:仅当截断后的字符串末尾是换行符时替换 size_t len = strlen(shortened); if (len > 0 && shortened[len - 1] == '\n') { shortened[len - 1] = '\0'; } // 扩容逻辑修正:使用正确的变量名lines if (line == allocated) { allocated *= 2; char **temp = realloc(lines, allocated * sizeof(char *)); if (!temp) { // 内存分配失败时,先释放已分配的内存避免泄漏 for (int i = 0; i < line; i++) free(lines[i]); free(lines); *pLines = 0; return NULL; } lines = temp; } // 分配内存时+1,预留终止符位置 lines[line] = (char *)malloc(strlen(shortened) + 1); if (!lines[line]) { // 内存分配失败时清理资源 for (int i = 0; i < line; i++) free(lines[i]); free(lines); *pLines = 0; return NULL; } strcpy(lines[line], shortened); line++; } *pLines = line; return lines; }
关键修复说明
- 强制添加终止符:复制
lineLength个字符后,直接设置shortened[lineLength] = '\0',确保字符串边界正确。 - 内存分配修正:
malloc(strlen(shortened)+1)仅分配实际需要的内存(也可使用lineLength+1,前者更节省空间)。 - 变量名修正:替换未定义变量,避免编译错误。
- 内存安全优化:添加内存分配失败的判断与资源清理,避免内存泄漏。
- 换行符处理优化:先判断字符串长度大于0,再访问末尾字符,避免越界。
内容的提问来源于stack exchange,提问作者Đániel Labanc
相关产品推荐
相关产品推荐

