C语言中char*返回异常字符串输出问题排查
C语言棋盘打印输出异常:缺失字符串终止符与内存泄漏问题
我有5年Python开发经验,C语言学习不足1年,最近实现棋盘位置打印功能时,代码总是返回奇怪的输出,怀疑是指针相关问题。
相关代码
main函数
int main(int argc, char const *argv[]) { POSITION a = STARTPOS; printPos(a); return 0; }
POSITION是自定义的typedef struct类型。
printPos函数
void printPos(POSITION pos) { printf("%s\n", getBoardStr(pos)); printf("%s\n", getBoardStr(pos)); char * a = getBoardStr(pos); printf("%s\n", a); }
getBoardStr函数
char * getBoardStr(POSITION pos) { BITBOARD i = SIZE_uINT64xCHAR_BIT_1; uint8_t iter = 0; char * out = malloc(65); while(i > 0) { if(pos.WPs & i) out[iter] = 'P'; else if(pos.BPs & i) out[iter] = 'p'; else if(pos.WNs & i) out[iter] = 'N'; else if(pos.BNs & i) out[iter] = 'n'; else if(pos.WBs & i) out[iter] = 'B'; else if(pos.BBs & i) out[iter] = 'b'; else if(pos.WRs & i) out[iter] = 'R'; else if(pos.BRs & i) out[iter] = 'r'; else if(pos.WQs & i) out[iter] = 'Q'; else if(pos.BQs & i) out[iter] = 'q'; else if(pos.WKs & i) out[iter] = 'K'; else if(pos.BKs & i) out[iter] = 'k'; else out[iter] = '.'; i >>= 1; ++iter; } return out; }
注:BITBOARD是uint64_t的别名,SIZE_uINT64xCHAR_BIT_1代表sizeof(uint64_t)*(CHAR_BIT - 1)。
问题分析
输出异常的核心原因有两个:
- 缺失字符串终止符:C语言中
printf("%s")要求字符串必须以'\0'(空字符)结尾。getBoardStr分配了65字节内存(刚好存64个棋盘字符+1个终止符),但循环结束后没有添加'\0',导致printf会读取内存中后续的随机垃圾数据,出现乱码。 - 内存泄漏:每次调用
getBoardStr都会通过malloc分配堆内存,但原代码中没有调用free释放这些内存,长期运行会耗尽系统可用内存。
修复方案
1. 给字符串添加终止符
修改getBoardStr函数,在循环结束后添加'\0',同时增加内存分配失败的判断:
char * getBoardStr(POSITION pos) { BITBOARD i = SIZE_uINT64xCHAR_BIT_1; uint8_t iter = 0; char * out = malloc(65); if (out == NULL) { // 检查内存分配是否成功 perror("malloc failed"); exit(EXIT_FAILURE); } while(i > 0) { if(pos.WPs & i) out[iter] = 'P'; else if(pos.BPs & i) out[iter] = 'p'; else if(pos.WNs & i) out[iter] = 'N'; else if(pos.BNs & i) out[iter] = 'n'; else if(pos.WBs & i) out[iter] = 'B'; else if(pos.BBs & i) out[iter] = 'b'; else if(pos.WRs & i) out[iter] = 'R'; else if(pos.BRs & i) out[iter] = 'r'; else if(pos.WQs & i) out[iter] = 'Q'; else if(pos.BQs & i) out[iter] = 'q'; else if(pos.WKs & i) out[iter] = 'K'; else if(pos.BKs & i) out[iter] = 'k'; else out[iter] = '.'; i >>= 1; ++iter; } out[iter] = '\0'; // 添加字符串终止符 return out; }
2. 释放堆内存
修改printPos函数,每次获取getBoardStr返回的指针后,使用free释放内存:
void printPos(POSITION pos) { char *board1 = getBoardStr(pos); printf("%s\n", board1); free(board1); char *board2 = getBoardStr(pos); printf("%s\n", board2); free(board2); char *a = getBoardStr(pos); printf("%s\n", a); free(a); }
修复效果
添加终止符后,printf能正确识别字符串的结束位置,输出正常的棋盘内容;释放内存则解决了堆内存泄漏问题,避免资源浪费。
内容的提问来源于stack exchange,提问作者leftclick
相关产品推荐
相关产品推荐

