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

Realloc触发SIGABRT问题排查:图路径规划程序崩溃求助

问题分析与修复:顶点连接函数中的SIGABRT崩溃

让我们一步步拆解你的问题,先找到触发SIGABRT的根源,再给出修复方案和优化建议。

为什么会触发SIGABRT?

SIGABRT在这里的核心原因是内存越界操作破坏了堆的元数据——malloc/realloc的底层机制检测到堆损坏后,会调用abort()终止程序。你的代码里有几个关键的内存操作错误:

1. 首次扩容时的内存大小计算错误

在处理v1->neighbors[0] == NULL的分支中,你写了:

real = (Vertex**) realloc(v1->neighbors, sizeof(Vertex*)+1);

sizeof(Vertex*)+1表示「一个指针的大小 + 1字节」,但你需要存储两个指针(新邻居 + NULL终止符),正确的大小应该是2 * sizeof(Vertex*)。这个错误会导致分配的内存空间不足,后续写入v1->neighbors[1] = NULL时直接越界,破坏堆的内部结构。

2. 处理v2空邻居分支的双重错误

在处理v2->neighbors[0] == NULL的分支中:

  • 内存大小计算错误:你用sizeof(Vertex*)申请内存,但之后要写入v2->neighbors[1] = NULL,需要至少2个指针的空间,应该是2 * sizeof(Vertex*)。
  • 未定义变量:v2->neighbors = realocado;中的realocado是拼写错误,应该是real。这个错误会导致未定义行为,直接将非法地址赋值给v2->neighbors,进一步破坏堆。

3. 邻居计数循环的冗余与潜在风险

计算邻居数量的循环里,aux = v1->neighbors[i];是冗余的(因为初始aux已经是v1->neighbors[0]),而且如果堆已经被破坏,邻居列表的NULL终止符被覆盖,循环会无限执行,导致i值过大,申请超出系统限制的内存,最终触发崩溃。

修复后的代码

以下是修正了所有上述问题的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct vertex Vertex;
struct vertex {
    char* name;
    Vertex** neighbors;
    float x, y;
};

// 假设你已经实现了areNeighbors函数
int areNeighbors(Vertex* v1, Vertex* v2) {
    if (v1->neighbors[0] == NULL) return 0;
    int i = 0;
    while (v1->neighbors[i] != NULL) {
        if (v1->neighbors[i] == v2) return 1;
        i++;
    }
    return 0;
}

Vertex* create_vertex(char* name, float x, float y) {
    Vertex* vertex = (Vertex*) malloc(sizeof(Vertex));
    if (!vertex) {
        printf("Failed to allocate vertex\n");
        return NULL;
    }
    vertex->x = x;
    vertex->y = y;
    vertex->name = (char*) malloc(strlen(name) + 1);
    if (!vertex->name) {
        free(vertex);
        printf("Failed to allocate vertex name\n");
        return NULL;
    }
    strcpy(vertex->name, name);
    // 初始分配1个指针的空间(存储NULL)
    vertex->neighbors = (Vertex**) malloc(sizeof(Vertex*));
    if (!vertex->neighbors) {
        free(vertex->name);
        free(vertex);
        printf("Failed to allocate neighbors list\n");
        return NULL;
    }
    vertex->neighbors[0] = NULL;
    return vertex;
}

void creates_connection(Vertex* v1, Vertex* v2) {
    if (areNeighbors(v1, v2)) {
        printf("Vertices ja sao vizinhos\n");
        return;
    }

    // 处理v1的邻居列表
    if (v1->neighbors[0] == NULL) {
        // 需要2个指针的空间:v2 + NULL
        Vertex** real = (Vertex**) realloc(v1->neighbors, 2 * sizeof(Vertex*));
        if (real != NULL) {
            v1->neighbors = real;
            v1->neighbors[0] = v2;
            v1->neighbors[1] = NULL;
        } else {
            printf("Nao foi possivel realocar memoria para v1\n");
        }
    } else {
        // 计算当前邻居数量(包括NULL终止符的索引)
        int i = 0;
        while (v1->neighbors[i] != NULL) {
            i++;
        }
        // 扩容为i+2个指针:原有i个(i-1个邻居 + NULL) + 新邻居 + 新NULL
        Vertex** real = (Vertex**) realloc(v1->neighbors, (i + 1) * sizeof(Vertex*));
        if (real != NULL) {
            v1->neighbors = real;
            v1->neighbors[i] = v2;
            v1->neighbors[i + 1] = NULL;
        } else {
            printf("Nao foi possivel realocar memoria para v1\n");
        }
    }

    // 处理v2的邻居列表
    if (v2->neighbors[0] == NULL) {
        Vertex** real = (Vertex**) realloc(v2->neighbors, 2 * sizeof(Vertex*));
        if (real != NULL) {
            v2->neighbors = real; // 修正变量名错误
            v2->neighbors[0] = v1;
            v2->neighbors[1] = NULL;
        } else {
            printf("Nao foi possivel realocar memoria para v2\n");
        }
    } else {
        int i = 0;
        while (v2->neighbors[i] != NULL) {
            i++;
        }
        Vertex** real = (Vertex**) realloc(v2->neighbors, (i + 1) * sizeof(Vertex*));
        if (real != NULL) {
            v2->neighbors = real;
            v2->neighbors[i] = v1;
            v2->neighbors[i + 1] = NULL;
        } else {
            printf("Nao foi possivel realocar memoria para v2\n");
        }
    }
}

优化建议

当前的实现每次添加邻居都需要遍历整个列表计数,效率较低,而且容易出错。建议给Vertex结构体添加一个neighbor_count字段,记录当前邻居的数量,避免遍历:

typedef struct vertex Vertex;
struct vertex {
    char* name;
    Vertex** neighbors;
    float x, y;
    int neighbor_count; // 新增:记录当前邻居的数量(不包括NULL终止符)
};

然后在create_vertex中初始化neighbor_count = 0,添加邻居时直接使用这个计数来计算内存大小:

// 在create_vertex中添加
vertex->neighbor_count = 0;

// 添加邻居时的逻辑简化(以v1为例)
if (v1->neighbor_count == 0) {
    Vertex** real = (Vertex**) realloc(v1->neighbors, 2 * sizeof(Vertex*));
    if (real) {
        v1->neighbors = real;
        v1->neighbors[0] = v2;
        v1->neighbors[1] = NULL;
        v1->neighbor_count = 1;
    }
} else {
    Vertex** real = (Vertex**) realloc(v1->neighbors, (v1->neighbor_count + 2) * sizeof(Vertex*));
    if (real) {
        v1->neighbors = real;
        v1->neighbors[v1->neighbor_count] = v2;
        v1->neighbors[v1->neighbor_count + 1] = NULL;
        v1->neighbor_count++;
    }
}

这样不仅提高了效率,还避免了遍历列表可能带来的错误,代码也更简洁。

内容的提问来源于stack exchange,提问作者yamunaq

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:05:48