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

C语言二维数组存入结构体后指针访问数据异常问题

二维数组存入结构体的指针错误问题解决

问题描述

我有一个固定列数的二维数组const unsigned long test_tileset[n][8],想要存入定义好的DynamicTileset结构体中。赋值后校验指针地址一致,但通过结构体访问数组元素时会得到固定的错误随机数据,直接访问原数组却完全正常。

核心原因

二维数组和二级指针的类型语义完全不兼容:

  • 二维数组test_tileset在内存中是连续的整块区域,退化为指针时类型是unsigned long (*)[8](指向包含8个unsigned long的数组的指针)。
  • 结构体中的unsigned long **tileset是指向指针的指针,它的内存布局是一个指针数组,每个指针指向独立的一维数组。
  • 当你把test_tileset强制传给unsigned long **类型参数时,虽然地址值相同,但访问tileset[0][i]时,编译器会错误地把数组首地址当作指针值去解引用(取到的是数组第一个元素的内容,而非下一级指针),再计算偏移,最终导致非法内存访问,得到错误数据。

解决方案

方法一:修改结构体成员类型匹配二维数组(推荐)

直接把结构体的tileset成员类型改为二维数组对应的指针类型,同时可以额外存储行数方便后续使用:

typedef struct DynamicTileset {
    // 指向包含8个unsigned long的数组的指针
    unsigned long (*tileset)[8];
    LinkedList* usedTiles;
    short* tilemap;
    int rows; // 存储数组的行数
} DynamicTileset;

对应的创建函数修改参数类型:

DynamicTileset* createDynamicTileset(unsigned long (*tileset)[8], int rows) {
    DynamicTileset* dynamicTileset = malloc(sizeof(DynamicTileset));
    dynamicTileset->tileset = tileset;
    dynamicTileset->rows = rows;
    dynamicTileset->usedTiles = createLinkedList();
    dynamicTileset->tilemap = NULL;
    return dynamicTileset;
}

调用时直接传入数组和行数:

DynamicTileset* title_tileset = createDynamicTileset(test_tileset, 1);

方法二:手动转换为二级指针(兼容原有结构体)

如果不想修改结构体定义,可以手动创建一个指针数组,每个元素指向二维数组的一行,再把这个指针数组赋值给tileset:

DynamicTileset* createDynamicTileset(const unsigned long (*tileset)[8], int rows) {
    DynamicTileset* dynamicTileset = malloc(sizeof(DynamicTileset));
    // 分配存储行指针的数组
    unsigned long** ptr_array = malloc(rows * sizeof(unsigned long*));
    for (int i = 0; i < rows; i++) {
        ptr_array[i] = (unsigned long*)tileset[i];
    }
    dynamicTileset->tileset = ptr_array;
    dynamicTileset->usedTiles = createLinkedList();
    dynamicTileset->tilemap = NULL;
    return dynamicTileset;
}

注意:这种方法需要额外分配内存,后续记得释放ptr_array避免内存泄漏;如果原数组是const类型,建议把结构体的tileset改为const unsigned long **以避免编译警告。

完整修正代码(方法一示例)

// 放在单独的.c文件或.h中
#include <stdio.h>
#include <stdlib.h>

const unsigned long test_tileset[1][8] = {
    {   0x12345678,
        0x23456789,
        0x3456789A,
        0x456789AB,
        0x56789ABC,
        0x6789ABCD,
        0x789ABCDE,
        0x89ABCDEF
    }
};

typedef struct Node
{
    int data;
    struct Node *next;
} Node;

typedef struct LinkedList
{
    Node *head;
    Node *tail;
    int size;
} LinkedList;

typedef struct DynamicTileset {
    unsigned long (*tileset)[8];
    LinkedList* usedTiles;
    short* tilemap;
    int rows;
} DynamicTileset;

LinkedList* createLinkedList() {
    LinkedList* list = malloc(sizeof(LinkedList));
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
    return list;
}

DynamicTileset* createDynamicTileset(unsigned long (*tileset)[8], int rows) {
    DynamicTileset* dynamicTileset = malloc(sizeof(DynamicTileset));
    dynamicTileset->tileset = tileset;
    dynamicTileset->rows = rows;
    dynamicTileset->usedTiles = createLinkedList();
    dynamicTileset->tilemap = NULL;
    return dynamicTileset;
}

// 主文件代码
int main() {
    DynamicTileset* title_tileset = createDynamicTileset(test_tileset, 1);

    if (title_tileset->tileset != test_tileset) {
        printf("tileset pointer is wrong\n");
    }
    int is_correct = 1;
    for (int i=0; i<8; i++) {
        if (title_tileset->tileset[0][i] != test_tileset[0][i]) {
            printf("first tile index %d is wrong\n", i);
            is_correct = 0;
            break;
        }
    }
    if (is_correct) {
        printf("All tiles are accessed correctly\n");
    }

    // 释放内存避免泄漏
    free(title_tileset->usedTiles);
    free(title_tileset);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:40:39