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

Wavefront .obj文件加载后输出随机值,代码错误定位求助

问题分析与修复方案

让我来帮你找出代码里的问题——你看到随机值的核心原因是指针传递错误和局部变量内存失效,另外还有一些容易忽略的细节问题,下面一步步拆解:

关键错误点

1. 局部数组的悬空指针问题

你在loadobj函数里定义了float verticesout[24];,这是一个栈上的局部数组。当函数执行完毕返回时,栈上的局部变量会被系统回收,内存变得无效。而你写的vertices = verticesout;只是修改了函数内部的vertices指针副本,完全没有影响到main函数里传入的vertices数组。后续main里访问这个数组时,读取的是未初始化的内存,自然就是随机值。

2. 指针参数的传递逻辑错误

C语言里参数传递是值传递,即使你传入的是数组名(会退化为指针),函数内部修改的也只是这个指针的副本,不会改变原数组的地址。你需要直接往传入的指针指向的内存空间里写入数据,而不是重新给指针赋值。

3. 其他细节问题

  • 没有关闭打开的文件:fopen后没有调用fclose(file),会导致文件资源泄漏。
  • fscanf格式字符串里的\n多余:fscanf会自动跳过空白字符(包括换行),加\n反而可能导致读取异常。
  • 缺少数组越界检查:如果模型的顶点数量超过24个float(8个顶点),会导致数组越界,引发未定义行为。

修正后的代码

修改后的obj.h

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<cglm/cglm.h>

// 增加maxVertices参数,避免数组越界
int loadobj(const char* filename, float* vertices, float* normals, float* texturecoords, int maxVertices) {
    FILE* file = fopen(filename, "r");
    char lineheader[128];
    int res;
    int vertexCount = 0;
    vec3 vertex;

    if(file == NULL){
        printf("Failed to open file!");
        return 1;
    }

    while(1){
        res = fscanf(file, "%s", lineheader);
        if(res == EOF){
            break;
        }

        if(strcmp(lineheader, "v") == 0){
            // 读取顶点数据,检查读取是否成功
            if(fscanf(file, "%f %f %f", &vertex[0], &vertex[1], &vertex[2]) != 3) {
                printf("Error reading vertex data!\n");
                fclose(file);
                return 1;
            }

            // 检查是否超出数组容量
            if(vertexCount + 3 > maxVertices) {
                printf("Vertex buffer overflow! Increase buffer size.\n");
                fclose(file);
                return 1;
            }

            // 直接写入传入的vertices数组
            vertices[vertexCount] = vertex[0];
            vertices[vertexCount + 1] = vertex[1];
            vertices[vertexCount + 2] = vertex[2];
            vertexCount += 3;
        }
        // 后续可以添加处理vn(法线)、vt(纹理坐标)、f(面)的逻辑
        // 注意:当前代码仅读取原始顶点,未处理面索引,若模型用面存储,还需解析f指令重组顶点
    }

    fclose(file); // 关闭文件,释放资源
    return 0;
}

修改后的main.c

#include<stdio.h>
#include<stdlib.h>
#include<cglm/cglm.h>
#include"obj.h"

int main(){
    const int maxVertexElements = 24; // 对应8个顶点(每个顶点3个分量)
    float vertices[maxVertexElements];
    float normals[24];
    float texcoords[24];

    int result = loadobj("model.obj", vertices, normals, texcoords, maxVertexElements);
    if(result != 0) {
        return 1;
    }

    // 格式化输出,每个顶点占一行,更易读
    for(int i = 0; i < maxVertexElements; i++){
        printf("%f ", vertices[i]);
        if((i + 1) % 3 == 0) {
            printf("\n");
        }
    }
    printf("\n");

    return 0;
}

额外说明

当前修正后的代码仅读取了.obj文件里的原始顶点(v指令),如果你的模型是用**面索引(f指令)**存储的,还需要进一步解析f指令,根据索引把对应的顶点、法线、纹理坐标重新组织成渲染需要的连续顶点数据——这也是完整加载.obj文件的核心步骤,你可以后续补充这部分逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:38:13