CodeWars字符串求和C代码报signal:6及free无效指针错误求助
字符串数字求和代码的内存错误排查
我用C语言实现了CodeWars《Sum String as Numbers》问题的解决方案,本地运行结果正确,也通过了所有测试用例,但触发了Caught unexpected signal: 6和free(): invalid pointer错误。我查阅了相关问题和论坛未找到解决方法,代码仅使用size_t类型,未进行指针自增(如a++)这类可能导致free失效的操作。
代码模块说明
char *to_num(const char *a,size_t *size):将ASCII字符串转换为数字数组,返回动态分配的数组并去除前导零void no_zeros(char *a):删除字符串的前导零- 自定义
len函数:以特定终止符计算数组长度 char *fill(char* a,size_t size):给数组补前导零至指定长度char *strsum(const char *a, const char *b):主函数,返回两个字符串数字的求和结果
程序流程
- 调用
to_num将输入字符串转为数字数组 - 若两个数组长度不同,调用
fill补全较短的数组 - 逐位相加得到结果字符串,调用
no_zeros处理结果的前导零问题
完整代码
#include <stdio.h> #include <malloc.h> #include <string.h> void display(const char *a,size_t size){ for(size_t i=0;a[i]!=0 && i<size;i++){ if(a[i]>'0'){ printf("%c",a[i]); } else{ printf("%d",a[i]); } } printf("\n"); } char *to_num(const char *a,size_t *size){ size_t i=0,j=0; *size = strlen(a); char *result = malloc((*size+1)*sizeof(char)); if(result==NULL){return 0;} while(a[i]=='0'){i++;} while(a[i]!=0){ result[j] = a[i]; i++; j++; } result[j]=0; *size = j; for(size_t i=0;i<*size;i++){ result[i] = result[i]-'0'; } result[*size] =10; return result; } void no_zeros(char *a){ size_t i=0,j=0; while(a[i]=='0'){i++;} while(a[i]!=0){ a[j] = a[i]; i++; j++; } a[j]=0; } size_t len(char *a){ size_t s=0; for(size_t i=0;a[i]!=10;i++){ s++; } return s; } char *fill(char* a,size_t size){ size_t a_size = len(a); char *copy = malloc((size+2)*sizeof(char)); if(copy==NULL){return 0;} for(size_t i=0;i<size-a_size;i++){ copy[i] = 0; } for(size_t i=0;i<a_size;i++){ copy[i+size-a_size] = a[i]; } copy[size] = 0; return copy; } char *strsum(const char *a, const char *b) { size_t size_a,size_b,bigger,smaller; char *x,*y; x = to_num(a,&size_a); y = to_num(b,&size_b); bigger = size_a>=size_b ? size_a : size_b; smaller = size_a<=size_b ? size_a : size_b; if(bigger != smaller){ if(bigger == size_a){ y = fill(y,bigger); size_b = bigger; } else{ x = fill(x,bigger); size_a = bigger; } } char *result = malloc((bigger+2)*sizeof(char)); if(result==NULL){return 0;} int carry=0; size_t i; for(i=bigger;i>=0;i--){ result[i] = (x[i-1]+y[i-1]+carry)%10+'0'; carry = (x[i-1]+y[i-1]+carry)/10; if(i==0) break; } result[bigger+1]=0; no_zeros(result); if(result[0]==0){return "0";} free(x); free(y); return result; } int main(){ printf("%s\n",strsum("9567","800")); }
错误原因与修复方案
1. 数组越界访问(触发SIGABRT)
strsum中的循环存在严重越界:
for(i=bigger;i>=0;i--){ result[i] = (x[i-1]+y[i-1]+carry)%10+'0'; // ... }
当i=0时,i-1会因size_t是无符号整数而溢出为最大值,导致访问x[-1]和y[-1],直接触发内存错误。
修复:调整循环逻辑,从最后一位开始计算,单独处理进位:
int carry = 0; size_t i; // 从最后一位(索引bigger-1)开始计算 for(i = bigger - 1; i < bigger; i--) { int sum = x[i] + y[i] + carry; result[i+1] = (sum % 10) + '0'; carry = sum / 10; if(i == 0) break; } // 处理最高位的进位 if(carry != 0) { result[0] = carry + '0'; result[bigger+1] = '\0'; } else { // 无进位时,将结果整体前移一位,去掉首位空位置 memmove(result, result+1, bigger); result[bigger] = '\0'; }
2. 指针覆盖导致内存泄漏与free错误
调用fill时直接覆盖原指针,导致to_num分配的内存无法释放:
y = fill(y,bigger);
后续free(y)释放的是fill返回的新指针,但原指针指向的内存永久泄漏;若fill返回NULL,还会触发空指针free。
修复:先释放原指针,再赋值新指针:
if(bigger != smaller){ if(bigger == size_a){ char *temp_y = fill(y, bigger); free(y); y = temp_y; size_b = bigger; } else{ char *temp_x = fill(x, bigger); free(x); x = temp_x; size_a = bigger; } }
3. 返回字符串常量导致free错误
strsum中直接返回字符串常量"0":
if(result[0]==0){return "0";}
函数返回char*,调用者可能尝试free该指针,但字符串常量位于只读内存,无法被free,触发free(): invalid pointer。
修复:动态分配内存存储"0",避免返回常量:
no_zeros(result); // 处理全零情况 if(result[0] == '\0') { free(result); result = malloc(2); if(result) strcpy(result, "0"); }
4. 终止符不一致导致长度计算错误
to_num用10作为数组终止符,而fill用0,导致len函数计算长度错误,进而引发内存操作异常。
修复:统一使用\0作为终止符:
// to_num函数最后一行修改为 result[*size] = '\0'; // len函数修改为 size_t len(char *a){ size_t s=0; while(a[s] != '\0') s++; return s; }
5. no_zeros处理后的空字符串问题
当结果全为零时,no_zeros会将result处理为空字符串(result[0] = '\0'),此时直接返回会导致后续逻辑错误。结合第3点的修复即可解决。
内容的提问来源于stack exchange,提问作者will
相关产品推荐
相关产品推荐

