动态分配含像素数组的结构体时触发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]的内存布局,且未初始化二级指针就直接访问。
对第一种实现的错误解析
wall_tex->tex是一个二级指针,本身仅占用一个指针大小的内存,你分配的结构体+像素数据的内存块,并没有给这个二级指针赋值,此时它是一个野指针(指向随机内存地址)。- 直接访问
wall_tex->tex[0][...]相当于先读取野指针指向的地址的第0个元素(另一个野指针),再用这个野指针访问像素数据,必然触发段错误。 - 你的内存布局设想错误:二级指针需要先指向一个一级指针数组,每个一级指针再指向对应的像素数据块,而非把像素数据直接跟结构体堆在一起。
对第二种实现的错误解析
- 同样,
wall_tex->tex是未初始化的野指针,memcpy(wall_tex->tex, tex, sizeof(tex))是往野指针指向的随机地址拷贝数据,直接触发段错误。 - 栈上的
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
相关产品推荐
相关产品推荐

