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

用C数组存储结构体后指针读取出现地址偏移的原因与修复

问题根源分析

你遇到的问题本质是两种数组类型的混淆,加上一处内存分配的错误,导致内存访问的偏移计算完全错误。我们一步步拆解:

1. 内存分配的核心错误

你创建的是一个指针数组(Path **array),每个元素是指向Path结构体的指针。但在给每个元素分配内存时,你写错了:

array[i] = malloc(sizeof(Path *)); // 错误:分配的是指针的大小,不是结构体的大小

这里应该分配Path结构体本身的大小,而不是指针的大小:

array[i] = malloc(sizeof(Path)); // 正确:分配能容纳整个Path结构体的内存

你的错误导致每个array[i]指向的内存块只有指针的大小(64位系统下是8字节,即0x10),但实际Path结构体的大小是0x20(从你观察到的地址间隔可以推断),这已经造成了内存越界,后续对path->next_hop和path->weight的修改可能会破坏堆内存。

2. PrintTable函数的类型不匹配

你的PrintTable函数声明是:

void PrintTable(Path *paths, int n)

它期望接收一个连续的Path结构体数组的首地址,所以代码里用paths + i来计算第i个结构体的地址——这是基于连续结构体数组的偏移逻辑(偏移量是i * sizeof(Path))。

但你传给它的是array[0],也就是指针数组里第一个Path*的地址。此时paths实际上指向的是Path*类型的元素(而不是Path结构体),所以paths + i的偏移量是i * sizeof(Path*)(64位下是i*8,即0x10的间隔),这和每个Path结构体实际的地址间隔0x20完全不匹配。你手动改成paths + (2*i)刚好凑对了偏移,但这是治标不治本的歪招,本质是类型不兼容导致的。


正确的修复方案

有两种合理的修复方式,根据你的需求选择:

方案一:改用连续的结构体数组(推荐)

如果你的场景不需要动态释放单个结构体,直接分配一块连续的Path结构体数组更高效,也符合PrintTable的设计:

// 直接分配n个连续的Path结构体
Path *array = malloc(items * sizeof(Path));

// 初始化每个结构体(不需要再循环malloc)
for (int i=0; i<items; i++) {
    array[i].next_hop = -1;
    array[i].weight = INT_MAX; // 注意:INT_MAX是int类型,如果weight是float,建议用FLT_MAX
}

// 调用PrintTable时直接传数组首地址
PrintTable(array, items);

这种方式下,array本身就是连续的结构体数组,PrintTable里的paths + i会正确计算每个结构体的地址,完全不需要调整偏移。

方案二:修改PrintTable适配指针数组

如果你必须使用指针数组(比如需要单独释放某个结构体),那么要修改PrintTable的参数类型为Path**,然后遍历每个指针:

// 修改函数声明为接收指针数组
void PrintTable(Path **paths, int n)
{
    if(paths == NULL || n <= 0)
        return;
    printf("%s %8s %8s\n", "Net ID", "Weight", "Next Hop");
    for(int i = 0; i < n; i++)
    {
        Path *p = paths[i]; // 直接取指针数组的第i个元素
        // 注意:要检查p是否为NULL,避免空指针访问
        if (p == NULL) {
            printf("%d %8s %8s\n", vertices[i], "NULL", "NULL");
            continue;
        }
        printf("%d %8.2f %8d\n", vertices[i], p->weight, p->next_hop);
    }
}

// 调用时传指针数组的首地址
PrintTable(array, items);

同时别忘了修复之前的内存分配错误,把sizeof(Path*)改成sizeof(Path)。


额外注意点
  • 如果weight是float类型,用INT_MAX赋值可能会有类型转换问题,建议用<float.h>里的FLT_MAX。
  • 内存分配后记得检查malloc的返回值是否为NULL,避免空指针访问。
  • 程序结束时要记得释放内存:如果是连续数组,直接free(array);如果是指针数组,要先循环free(array[i]),再free(array)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:40:18