在 for 循环中出现分段错误

问题描述 投票:0回答:1

我读了一篇关于我的项目的球体创建的文章,可以在这里找到,并决定尝试将其移植到我正在使用的语言c。我选择了二十面体方法,从二十面体开始,然后从那里细分。问题是我遇到了段错误,但当我尝试细分它时就会发生这种情况。但是如果我保持原样并且不尝试细分,代码编译得很好,没有错误。

#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include <stdint.h>

struct Point
{
    double x;
    double y;
    double z;
};

struct Triangle
{
    int v1;
    int v2;
    int v3;
};

// normalizes a vertex and then adds it to an array
int add_vertex(struct Point verts[], struct Point point)
{
    double length = (point.x * point.x) + (point.y * point.y) + (point.z * point.z);

    int index = 0;
    
    verts[index].x = point.x / length;
    verts[index].y = point.y / length;
    verts[index].z = point.z / length;
    
    return index++;
}

// gets the middle of a triangle face but checks to make sure that no duplicate vertices are created
int get_middle_point(int p1, int p2, struct Triangle inds[], struct Point verts[], int cache[])
{
    // check to see if the middle point is already calculated
    uint64_t key = (p1 < p2) ? (p1, p2) : (p2, p1);

    if (cache[key] != 0)
    {
        return cache[key];
    }

    // it isn't so calculate it
    struct Point point1 = verts[p1];
    struct Point point2 = verts[p2];
    struct Point 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;

    // add middle vertex to unit sphere
    int i = add_vertex(verts, middle);
    return i;
}

// creates icosphere by subdividing icosahedron
void create_icosphere(int recursion_level, struct Point verts[], struct Triangle inds[])
{
    // cache middle points
    int middle_point_cache[1000];

    // golden ratio
    float t = 1 + sqrt(5) * 0.5;

    // icosahedron cartisean coordinates from wikipedia
    add_vertex(verts, (struct Point){-1, t, 0});
    add_vertex(verts, (struct Point){1, t, 0});
    add_vertex(verts, (struct Point){-1, -t, 0});
    add_vertex(verts, (struct Point){1, -t, 0});

    add_vertex(verts, (struct Point){0, -1, t});
    add_vertex(verts, (struct Point){0, 1, t});
    add_vertex(verts, (struct Point){0, -1, -t});
    add_vertex(verts, (struct Point){0, 1, -t});

    add_vertex(verts, (struct Point){t, 0, -1});
    add_vertex(verts, (struct Point){t, 0, 1});
    add_vertex(verts, (struct Point){-t, 0, -1});
    add_vertex(verts, (struct Point){-t, 0, 1});

    // icosahedron indices

    // 5 faces around point 0
    inds[0] = (struct Triangle){0, 11, 5};
    inds[1] = (struct Triangle){0, 5, 1};
    inds[2] = (struct Triangle){0, 1, 7};
    inds[3] = (struct Triangle){0, 7, 10};
    inds[4] = (struct Triangle){0, 10, 11};

    // 5 adjacent faces
    inds[5] = (struct Triangle){1, 5, 9};
    inds[6] = (struct Triangle){5, 11, 4};
    inds[7] = (struct Triangle){11, 10, 2};
    inds[8] = (struct Triangle){10, 7, 6};
    inds[9] = (struct Triangle){7, 1, 8};

    // 5 faces around point 3
    inds[10] = (struct Triangle){3, 9, 4};
    inds[11] = (struct Triangle){3, 4, 2};
    inds[12] = (struct Triangle){3, 2, 6};
    inds[13] = (struct Triangle){3, 6, 8};
    inds[14] = (struct Triangle){3, 8, 9};

    // 5 adjacent faces
    inds[15] = (struct Triangle){4, 9, 5};
    inds[16] = (struct Triangle){2, 4, 11};
    inds[17] = (struct Triangle){6, 2, 10};
    inds[18] = (struct Triangle){8, 6, 7};
    inds[19] = (struct Triangle){9, 8, 1};

    // subdivide icosahedron
    for (int i = 0; i < recursion_level; i++)
    {
        // create new array for newly created triangle faces
        struct Triangle faces_2[1000];
        int faces_2_index = 0;
        for (int j = 0; j < 20; j++)
        {
            struct Triangle tri = inds[j];

            // get the centroid of each triangle face
            int a = get_middle_point(tri.v1, tri.v2, faces_2, verts, middle_point_cache);
            int b = get_middle_point(tri.v2, tri.v3, faces_2, verts, middle_point_cache);
            int c = get_middle_point(tri.v3, tri.v1, faces_2, verts, middle_point_cache);

            // add new faces to new faces array
            faces_2[faces_2_index++] = (struct Triangle){tri.v1, a, c};
            faces_2[faces_2_index++] = (struct Triangle){tri.v2, b, a};
            faces_2[faces_2_index++] = (struct Triangle){tri.v3, c, b};
            faces_2[faces_2_index++] = (struct Triangle){tri.v1, tri.v2, tri.v3};
        }

        // copy over contents from new array to indices
        for (int j = 0; j < faces_2_index; j++)
        {
            inds[j] = faces_2[j];
        }
    }
}

int main()
{
    // example usage. works with a subdivision level of 0 but anything higher causes a seg fault
    struct Point vertices[1000];
    struct Triangle indices[1000];
    create_icosphere(2, vertices, indices);
    printf("No errors\n");

    return 0;
}

我将问题缩小到细分循环或

get_middle_point
函数(在细分循环中调用)。但我不知道为什么会出现错误,也不知道如何解决它们。 这是我的编译器当前指向的 seg 错误的位置 error in nested subdivide loop位于细分循环内。

c segmentation-fault
1个回答
0
投票

在细分循环中,我创建了一个新数组

struct Triangle faces_2[20 * recursion_level];

但是稍后用

写出界
faces_2[faces_2_index++] = (struct Triangle){tri.v1, a, c};
faces_2[faces_2_index++] = (struct Triangle){tri.v2, b, a};        
faces_2[faces_2_index++] = (struct Triangle){tri.v3, c, b};
faces_2[faces_2_index++] = (struct Triangle){tri.v1, tri.v2, tri.v3};

所以为了解决我的问题,我只需要增加尺寸

struct Triangle faces_2[1000];

并且它有效。我暂时保留 1000 作为样本大小,但很快就会改变。

© www.soinside.com 2019 - 2024. All rights reserved.