移植C# icosphere代码到C后出现栈溢出(0xC000001D)的原因
问题背景
参考生成icosphere的文章将C#代码移植到C语言后,运行出现错误:Process returned -1073741795 (0xC000001D) execution time : 8.057 s Press any key to continue.,相关代码片段如下:
#include <stdio.h> #include <math.h> #include <stdbool.h> #include <stdint.h> typedef struct Point3D{ double x; double y; double z; } point3D; typedef struct Triangleindices{ int v1; int v2; int v3; } triangles; typedef struct MeshGeometry3D{ point3D *positions; int *triangle_indices; } mesh_geometry; typedef struct IcosphereCreator{ mesh_geometry geometry; int index; int *cache; } icosphere; int add_vertex(icosphere* creator, point3D p){ double length = sqrt(p.x * p.x + p.y * p.y + p.z * p.z); creator->geometry.positions[creator->index].x = p.x / length; creator->geometry.positions[creator->index].y = p.y / length; creator->geometry.positions[creator->index].z = p.z / length; return creator->index++; } int get_middle_point(icosphere* creator, int p1, int p2){ bool first_is_smaller = p1 < p2; int64_t smaller_index = first_is_smaller ? p1 : p2; int64_t greater_index = first_is_smaller ? p2 : p1; int64_t key = (smaller_index << 32) + greater_index; if (creator->cache[key] != 0) { return creator->cache[key]; } point3D point1 = creator->geometry.positions[p1]; point3D point2 = creator->geometry.positions[p2]; point3D middle; middle.x = (point1.x + point2.x) / 2.0; middle.y = (point1.y + point2.y) / 2.0; middle.z = (point1.z + point2.z) / 2.0; int i = add_vertex(creator, middle); return i; } mesh_geometry create_icosphere(icosphere* creator, int subdivide){ int max_triangles = 20 * (1 << (2 * subdivide)); long long unsigned int array_size = max_triangles * sizeof(triangles); creator->geometry = (mesh_geometry){0}; mesh_geometry result = (mesh_geometry){0}; creator->index = 0; point3D p1 = {-1, (1.0 + sqrt(5.0)) / 2.0, 0}; point3D p2 = {1, (1.0 + sqrt(5.0)) / 2.0, 0}; point3D p3 = {-1, -(1.0 + sqrt(5.0)) / 2.0, 0}; point3D p4 = {1, -(1.0 + sqrt(5.0)) / 2.0, 0}; point3D p5 = {0, -1, (1.0 + sqrt(5.0)) / 2.0}; point3D p6 = {0, 1, (1.0 + sqrt(5.0)) / 2.0}; point3D p7 = {0, -1, -(1.0 + sqrt(5.0)) / 2.0}; point3D p8 = {0, 1, -(1.0 + sqrt(5.0)) / 2.0}; point3D p9 = {(1.0 + sqrt(5.0)) / 2.0, 0, -1}; point3D p10 = {(1.0 + sqrt(5.0)) / 2.0, 0, 1}; point3D p11 = {(1.0 + sqrt(5.0)) / 2.0, 0 -1}; point3D p12 = {(1.0 + sqrt(5.0)) / 2.0, 0, 1}; add_vertex(creator, p1); add_vertex(creator, p2); add_vertex(creator, p3); add_vertex(creator, p4); add_vertex(creator, p5); add_vertex(creator, p6); add_vertex(creator, p7); add_vertex(creator, p8); add_vertex(creator, p9); add_vertex(creator, p10); add_vertex(creator, p11); add_vertex(creator, p12); triangles faces[] = { {0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11}, {1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8}, {3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9}, {4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1} }; for (int i = 0; i < subdivide; i++) { triangles new_faces[array_size]; int new_faces_index = 0; for (int j = 0; j < 20; j++) { triangles tri = faces[j]; int a = get_middle_point(creator, tri.v1, tri.v2); int b = get_middle_point(creator, tri.v2, tri.v3); int c = get_middle_point(creator, tri.v3, tri.v1); new_faces[new_faces_index++] = (triangles){tri.v1, a, c}; new_faces[new_faces_index++] = (triangles){tri.v2, b, a}; new_faces[new_faces_index++] = (triangles){tri.v3, c, b}; new_faces[new_faces_index++] = (triangles){a, b, c}; } for (int j = 0; j < new_faces_index; j++) { faces[j] = new_faces[j]; } for (int i = 0; i < 20; i++) { triangles tri = faces[i]; result.triangle_indices[i * 3] = tri.v1; result.triangle_indices[i * 3 + 1] = tri.v2; result.triangle_indices[i * 3 + 2] = tri.v3; } } return result; } int main(void){ icosphere creator; creator.index = -1; int subdivision_level = 3; creator.geometry = create_icosphere(&creator, subdivision_level); for (int i = 0; i < creator.index; i++) { printf("Vertex %d: (%f, %f, %f)\n", i, creator.geometry.positions[i].x, creator.geometry.positions[i].y, creator.geometry.positions[i].z); } for (int i = 0; i < creator.index; i += 3) { printf("Triangle %d: %d, %d, %d\n", i / 3, creator.geometry.triangle_indices[i], creator.geometry.triangle_indices[i + 1], creator.geometry.triangle_indices[i + 2]); } int count = creator.geometry.triangle_indices; return 0; }
栈溢出错误原因分析
错误码0xC000001D对应栈溢出,核心问题出在栈内存滥用和未初始化指针的非法访问,具体如下:
1. 栈上分配超大可变长度数组(VLA)
在create_icosphere的细分循环中,直接在栈上声明了triangles new_faces[array_size];:
triangles new_faces[array_size];
当细分等级为3时,max_triangles = 20 * (1 << (2*3)) = 1280,array_size = 1280 * sizeof(triangles)(每个triangles占12字节,总大小约15KB)。虽然这个数值看起来不大,但栈的默认空间通常只有1-8MB,且细分等级每提升1,数组大小会翻4倍(比如等级4时达到64KB),直接耗尽栈空间。
C语言中栈内存有限,这种动态大小的数组绝对不能放在栈上,必须改用堆内存(malloc/free)分配。
2. 未初始化指针的非法内存访问
icosphere结构体中的cache指针从未分配内存,直接在get_middle_point中访问creator->cache[key]会访问随机非法内存地址,可能直接触发崩溃,或覆盖栈上其他数据破坏栈完整性。mesh_geometry中的positions和triangle_indices都是野指针,add_vertex中直接写入creator->geometry.positions[creator->index]会随机覆盖内存(包括栈内存),最终引发栈溢出。
3. 加剧内存问题的其他错误
- 循环变量重定义:细分循环的外层变量
i和内层的for (int i = 0; i < 20; i++)重名,会导致逻辑混乱,可能错误修改循环计数器,引发更多内存越界。 - 顶点定义错误:
p11 = {(1.0 + sqrt(5.0)) / 2.0, 0 -1};缺少逗号,应为{(1.0 + sqrt(5.0)) / 2.0, 0, -1};,会导致顶点数据错误,间接引发后续内存访问异常。 - 类型错误赋值:main函数中
int count = creator.geometry.triangle_indices;将指针类型赋值给int,属于类型错误,可能导致后续非法内存访问。
内容的提问来源于stack exchange,提问作者user1194385
相关产品推荐
相关产品推荐

