You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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):主函数,返回两个字符串数字的求和结果

程序流程

  1. 调用to_num将输入字符串转为数字数组
  2. 若两个数组长度不同,调用fill补全较短的数组
  3. 逐位相加得到结果字符串,调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:11:48