给三级指针/数组的数组成员赋值时触发段错误(Segfault)
问题描述
尝试创建结构体指针的二维数组(数组的数组),但在设置第一个数组指针时触发段错误,GDB显示错误发生在palArray[i/4][i%4] = tmpColor;行。提供可编译代码片段,希望找到问题原因或更简单的实现方式,三级指针处理起来很棘手。
错误原因分析
- 内存分配完全错误
原代码中malloc(sizeof(***palArray) * number * colors)逻辑混乱:***palArray是color_t类型,分配的内存仅能存储number*colors个color_t结构体,但color_t***是指向指针数组的指针,需要分层级分配内存——先存调色板指针的外层数组,再为每个调色板存颜色指针的内层数组。 - 循环逻辑错误
- 循环条件
i < (number * colors * 3)错误:每个颜色占3字节RGB数据,总循环次数应为number * colors,每次循环处理3字节,而非将总数量乘以3。 - 索引计算
i/4和i%4无依据:应该按调色板索引、颜色索引的层级遍历,而非基于字节索引的除法。
- 循环条件
- 数组越界风险
原循环中i+1、i+2会导致paldat越界访问,因为循环终点接近number*colors*3,超出了数组实际长度。
修复方案
方案1:正确分配三级指针内存
按层级分配内存,修正循环逻辑:
color_t*** palettesToColorArray(pSpr_t* sprObj){ int palette_count = ((sprObj->palnum & 0xF0) >> 4) + 1; int colors_per_palette = (sprObj->palnum & 0x0F) + 1; // 第一步:分配存储调色板指针的外层数组 color_t*** palArray = malloc(sizeof(color_t**) * palette_count); if(palArray == NULL){ puts("\n!!> ERR: Memory allocation failure (palettes)"); exit(1); } int byte_idx = 0; for(int pal = 0; pal < palette_count; pal++){ // 第二步:为每个调色板分配存储颜色指针的内层数组 palArray[pal] = malloc(sizeof(color_t*) * colors_per_palette); if(palArray[pal] == NULL){ puts("\n!!> ERR: Memory allocation failure (colors)"); exit(1); } for(int col = 0; col < colors_per_palette; col++){ // 按RGB顺序读取字节,每次移动3位 color_t* tmpColor = createColorNoAlpha( sprObj->paldat[byte_idx], sprObj->paldat[byte_idx+1], sprObj->paldat[byte_idx+2] ); palArray[pal][col] = tmpColor; byte_idx += 3; } } return palArray; }
注意:释放内存时要逐层释放,避免内存泄漏:
// 释放内存 for(int i = 0; i < palCount; i++){ for(int j = 0; j < colCount; j++){ free(colArray[i][j]); // 释放单个color_t对象 } free(colArray[i]); // 释放调色板的颜色指针数组 } free(colArray); // 释放调色板指针数组
方案2:简化结构,避免三级指针
如果觉得三级指针过于复杂,推荐改用以下两种更易维护的结构:
方式A:二维结构体数组(非指针)
直接分配结构体数组,无需为单个颜色动态分配内存:
color_t** palettesToColorArray(pSpr_t* sprObj){ int palette_count = ((sprObj->palnum & 0xF0) >> 4) + 1; int colors_per_palette = (sprObj->palnum & 0x0F) + 1; // 分配外层调色板数组 color_t** palArray = malloc(sizeof(color_t*) * palette_count); if(palArray == NULL){ puts("\n!!> ERR: Memory allocation failure"); exit(1); } int byte_idx = 0; for(int pal = 0; pal < palette_count; pal++){ // 分配内层颜色数组 palArray[pal] = malloc(sizeof(color_t) * colors_per_palette); if(palArray[pal] == NULL){ puts("\n!!> ERR: Memory allocation failure"); exit(1); } for(int col = 0; col < colors_per_palette; col++){ palArray[pal][col].red = sprObj->paldat[byte_idx]; palArray[pal][col].grn = sprObj->paldat[byte_idx+1]; palArray[pal][col].blu = sprObj->paldat[byte_idx+2]; palArray[pal][col].alp = 255; byte_idx +=3; } } return palArray; }
方式B:一维数组模拟二维结构
用连续内存的一维数组存储所有颜色,通过索引计算模拟二维结构,内存管理最简单:
color_t* palettesToColorArray(pSpr_t* sprObj){ int palette_count = ((sprObj->palnum & 0xF0) >> 4) + 1; int colors_per_palette = (sprObj->palnum & 0x0F) + 1; int total_colors = palette_count * colors_per_palette; // 分配连续内存存储所有颜色 color_t* palArray = malloc(sizeof(color_t) * total_colors); if(palArray == NULL){ puts("\n!!> ERR: Memory allocation failure"); exit(1); } int byte_idx = 0; for(int i = 0; i < total_colors; i++){ palArray[i].red = sprObj->paldat[byte_idx]; palArray[i].grn = sprObj->paldat[byte_idx+1]; palArray[i].blu = sprObj->paldat[byte_idx+2]; palArray[i].alp = 255; byte_idx +=3; } return palArray; }
访问时通过palArray[pal_idx * colors_per_palette + col_idx]定位对应颜色即可。
内容的提问来源于stack exchange,提问作者YourAverageYeet
相关产品推荐
相关产品推荐

