C语言中unsigned char循环超过127次时出现内存泄漏求助
分析unsigned char循环值≥128时的内存泄漏问题
问题根源定位
先看Valgrind的泄漏报告,明确泄漏来自letter_frequencies函数里的malloc调用。咱们直接拆解这个函数的问题:
size_t *letter_frequencies(char *str) { size_t *frequencies = malloc(sizeof(size_t) * 26); // 分配了26个size_t的内存 for (int i = 0; i < 26; i++) frequencies[i] = 0; while (*str) { if (!isascii((unsigned char)*str)) return NULL; // 这里直接返回,内存没释放! if (isalpha(*str)) frequencies[tolower(*str) - 'a']++; str++; } return frequencies; }
当检测到非ASCII字符时,函数直接返回NULL,但之前通过malloc申请的frequencies内存完全没被释放——这就是泄漏的直接原因。
那为什么只有c≥128时才会触发?这和字符的符号特性有关:
- 你的
xor_against_key中,str[i]是有符号char类型(默认范围-128~127),而key是unsigned char(0~255)。 - 原
bytes数组的内容是十六进制转换来的,所有字节最高位都是0(比如0x1b、0x37),也就是都在0~127范围内。当c≥128时,它的最高位是1,和原字节异或后,结果的最高位会变成1,对应的有符号char就是负数(比如0^128=128,作为有符号char就是-128)。 - 传给
isascii时,这个负数被转成unsigned char就是128255,超出了`isascii`识别的0127范围,于是触发return NULL,内存泄漏就此发生。 - 而
c<128时,异或结果的最高位还是0,对应字符在0~127范围内,不会触发提前返回,frequencies能被正常free,所以没有泄漏。
修复方案
只需要在letter_frequencies函数返回NULL前,先释放已经申请的内存,同时补上几个细节优化:
size_t *letter_frequencies(char *str) { size_t *frequencies = malloc(sizeof(size_t) * 26); if (!frequencies) { // 增加malloc失败的容错 return NULL; } for (int i = 0; i < 26; i++) frequencies[i] = 0; while (*str) { if (!isascii((unsigned char)*str)) { free(frequencies); // 返回前释放内存 return NULL; } // 把char转成unsigned char再传给isalpha/tolower,避免负数导致未定义行为 if (isalpha((unsigned char)*str)) { frequencies[tolower((unsigned char)*str) - 'a']++; } str++; } return frequencies; }
验证说明
修复后再用Valgrind检测,你会发现所有内存都被正常释放:
- 当循环
c到255时,即使触发非ASCII检测,frequencies也会被提前释放,不会留下泄漏。 - 之前观察到的"c≥128时每次循环漏一块内存"的现象会完全消失。
内容的提问来源于stack exchange,提问作者abasar
相关产品推荐
相关产品推荐

