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

动态分配含像素数组的结构体时触发Segfault问题排查

结构体嵌套二维像素数组时的段错误问题分析

我尝试分配包含像素数组的结构体时触发了段错误,找不到错误所在。最初直接通过malloc分配结构体及像素内存,赋值时触发段错误;后来改为先在栈中生成像素数组,再malloc分配结构体并使用memcpy复制,同样在复制时触发Segfault。以下是两种实现的代码示例,想请教我的malloc使用哪里出错了?(注:这是简化示例,实际项目中需要完成该结构体的分配)


两种错误实现代码

第一种实现

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex;
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;

    Tex_Array* wall_tex = malloc(sizeof(Tex_Array) + (tex_w * tex_h) * tex_num * sizeof(uint32_t));

    /* Texture generation */

    for(int x = 0; x < tex_w; x++) {
        for(int y = 0; y < tex_h; y++)
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h + x * 128 / tex_w;
            wall_tex->tex[0][tex_w * y + x] = 65536 * 254 * (x != y && x != tex_w - y);
            wall_tex->tex[1][tex_w * y + x] = xycolor + 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[2][tex_w * y + x] = 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[3][tex_w * y + x] = xorcolor + 256 * xorcolor + 65536 * xorcolor;
            wall_tex->tex[4][tex_w * y + x] = 256 * xorcolor;
            wall_tex->tex[5][tex_w * y + x] = 65536 * 192 * (x % 16 && y % 16);
            wall_tex->tex[6][tex_w * y + x] = 65536 * ycolor;
            wall_tex->tex[7][tex_w * y + x] = 128 + 256 * 128 + 65536 * 128;
        }
    }

    /* Test if the program arrives here */

    printf("Generation is finished !\n");

    /* rest of initialization just for example */

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    return 0;

}

第二种实现

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex;
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;

    uint32_t tex[8][tex_w * tex_h];

    /* Texture generation */

    for(int x = 0; x < tex_w; x++) {
        for(int y = 0; y < tex_h; y++)
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h + x * 128 / tex_w;
            tex[0][tex_w * y + x] = 65536 * 254 * (x != y && x != tex_w - y);
            tex[1][tex_w * y + x] = xycolor + 256 * xycolor + 65536 * xycolor;
            tex[2][tex_w * y + x] = 256 * xycolor + 65536 * xycolor;
            tex[3][tex_w * y + x] = xorcolor + 256 * xorcolor + 65536 * xorcolor;
            tex[4][tex_w * y + x] = 256 * xorcolor;
            tex[5][tex_w * y + x] = 65536 * 192 * (x % 16 && y % 16);
            tex[6][tex_w * y + x] = 65536 * ycolor;
            tex[7][tex_w * y + x] = 128 + 256 * 128 + 65536 * 128;
        }
    }

    printf("Generation is finished !\n"); // It's okay'

    /* rest of initialization */

    Tex_Array* wall_tex = malloc(sizeof(Tex_Array) + sizeof(tex));

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    memcpy(wall_tex->tex, tex, sizeof(tex)); // Segfault here

    /* Test if the program arrives here */

    printf("Struct alloc is finished !\n");

    return 0;

}

问题根源分析

两种实现的核心错误完全一致:混淆了二级指针uint32_t**和二维数组uint32_t[][N]的内存布局,且未初始化二级指针就直接访问。

对第一种实现的错误解析

  1. wall_tex->tex是一个二级指针,本身仅占用一个指针大小的内存,你分配的结构体+像素数据的内存块,并没有给这个二级指针赋值,此时它是一个野指针(指向随机内存地址)。
  2. 直接访问wall_tex->tex[0][...]相当于先读取野指针指向的地址的第0个元素(另一个野指针),再用这个野指针访问像素数据,必然触发段错误。
  3. 你的内存布局设想错误:二级指针需要先指向一个一级指针数组,每个一级指针再指向对应的像素数据块,而非把像素数据直接跟结构体堆在一起。

对第二种实现的错误解析

  1. 同样,wall_tex->tex是未初始化的野指针,memcpy(wall_tex->tex, tex, sizeof(tex))是往野指针指向的随机地址拷贝数据,直接触发段错误。
  2. 栈上的tex是二维数组,本质是连续的一维内存块;而结构体中的uint32_t**是二级指针,需要指向指针数组,两者内存布局完全不同,无法直接用memcpy完成复制。

两种正确实现方案

方案一:使用连续内存块(减少碎片,释放方便)

将结构体、指针数组、像素数据分配在同一个连续内存块中,避免多次malloc:

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex; // 指向内存块中的指针数组
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;
    const size_t pixel_count_per_tex = tex_w * tex_h;
    const size_t ptr_array_size = tex_num * sizeof(uint32_t*);
    const size_t pixel_data_size = tex_num * pixel_count_per_tex * sizeof(uint32_t);

    // 分配结构体 + 指针数组 + 像素数据的连续内存
    Tex_Array* wall_tex = malloc(sizeof(Tex_Array) + ptr_array_size + pixel_data_size);
    if (!wall_tex) {
        perror("malloc failed");
        return 1;
    }

    // 初始化指针数组:紧跟结构体之后
    uint32_t** ptr_array = (uint32_t**)((char*)wall_tex + sizeof(Tex_Array));
    // 像素数据紧跟指针数组之后
    uint32_t* pixel_data = (uint32_t*)((char*)ptr_array + ptr_array_size);
    wall_tex->tex = ptr_array;

    // 为每个纹理指针赋值,指向对应的像素块
    for (int i = 0; i < tex_num; i++) {
        wall_tex->tex[i] = pixel_data + i * pixel_count_per_tex;
    }

    // 生成纹理数据
    for(int x = 0; x < tex_w; x++) {
        for(int y = 0; y < tex_h; y++)
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h + x * 128 / tex_w;
            const size_t idx = tex_w * y + x;
            wall_tex->tex[0][idx] = 65536 * 254 * (x != y && x != tex_w - y);
            wall_tex->tex[1][idx] = xycolor + 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[2][idx] = 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[3][idx] = xorcolor + 256 * xorcolor + 65536 * xorcolor;
            wall_tex->tex[4][idx] = 256 * xorcolor;
            wall_tex->tex[5][idx] = 65536 * 192 * (x % 16 && y % 16);
            wall_tex->tex[6][idx] = 65536 * ycolor;
            wall_tex->tex[7][idx] = 128 + 256 * 128 + 65536 * 128;
        }
    }

    printf("Generation is finished !\n");

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    // 释放:仅需一次free即可
    free(wall_tex);
    return 0;
}

方案二:分散分配内存(灵活适配不同大小纹理)

分别分配结构体、指针数组、每个纹理的像素块,适合纹理大小不一致的场景:

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex;
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;
    const size_t pixel_count_per_tex = tex_w * tex_h;

    // 分配结构体
    Tex_Array* wall_tex = malloc(sizeof(Tex_Array));
    if (!wall_tex) {
        perror("malloc struct failed");
        return 1;
    }

    // 分配指针数组
    wall_tex->tex = malloc(tex_num * sizeof(uint32_t*));
    if (!wall_tex->tex) {
        perror("malloc ptr array failed");
        free(wall_tex);
        return 1;
    }

    // 为每个纹理分配像素内存
    for (int i = 0; i < tex_num; i++) {
        wall_tex->tex[i] = malloc(pixel_count_per_tex * sizeof(uint32_t));
        if (!wall_tex->tex[i]) {
            perror("malloc pixel data failed");
            // 回滚已分配的内存
            for (int j = 0; j < i; j++) {
                free(wall_tex->tex[j]);
            }
            free(wall_tex->tex);
            free(wall_tex);
            return 1;
        }
    }

    // 生成纹理数据
    for(int x = 0; x < tex_w; x++) {
        for(int y = 0; y < tex_h; y++)
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h + x * 128 / tex_w;
            const size_t idx = tex_w * y + x;
            wall_tex->tex[0][idx] = 65536 * 254 * (x != y && x != tex_w - y);
            wall_tex->tex[1][idx] = xycolor + 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[2][idx] = 256 * xycolor + 65536 * xycolor;
            wall_tex->tex[3][idx] = xorcolor + 256 * xorcolor + 65536 * xorcolor;
            wall_tex->tex[4][idx] = 256 * xorcolor;
            wall_tex->tex[5][idx] = 65536 * 192 * (x % 16 && y % 16);
            wall_tex->tex[6][idx] = 65536 * ycolor;
            wall_tex->tex[7][idx] = 128 + 256 * 128 + 65536 * 128;
        }
    }

    printf("Generation is finished !\n");

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    // 释放:按分配逆序释放
    for (int i = 0; i < tex_num; i++) {
        free(wall_tex->tex[i]);
    }
    free(wall_tex->tex);
    free(wall_tex);

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:15:41