引用到全局数组时更改了 C++ 数组内容

c++ array content changed when refereing to global array

本文关键字:数组 C++ 全局 引用      更新时间:2023-10-16

我试图使用 openGl 编写 c++ 代码来渲染Sierpinski_gasket。我已经使用 typedef 定义了拖曳新数据类型,然后我创建了一个指向这些新数据类型之一的指针:

typedef GLfloat point2[2]; 
typedef point2 myTriangle[3];
myTriangle *triangle;

我编写了一个函数init,它取三个点,然后创建一个新myTriangle,然后将其分配给*triangle

void init(point2 p1, point2 p2, point2 p3){  
    myTriangle t;
    t[0][0] = p1[0];
    t[0][1] = p1[1];
    t[1][0] = p2[0];
    t[1][1] = p2[1];
    t[2][0] = p3[0];
    t[2][1] = p3[1];
    triangle = &t;    
}

这是我diplay函数:

void display(void){
    static point2 p = {1,1};
    int i;        
    //pick a random vertex    
    i = rand() % 3;  //i in the range 0 to 2
    p[0] = (p[0] + *triangle[i][0])/2;
    p[1] = (p[1] + *triangle[i][1])/2;
    cout << p[0] << ' , ' << p[1] << endl;
    //display new points
    glBegin(GL_POINTS);
        glVertex2fv(p);
    glEnd();                
}

问题是每次调用*triangledisplay的值都会发生变化。谁能告诉我为什么以及如何解决这个问题?

完整代码如下

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef GLfloat point2[2];
typedef point2 myTriangle[3];
myTriangle *triangle;
void init(point2 p1, point2 p2, point2 p3);
void display(void);
int main(int argc, char** argv) {
    //initialize the GLUT library
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL");
    //openGL Code
    glClearColor(0.0, 1.0, 0.0, 0.0 );
    glClear(GL_COLOR_BUFFER_BIT);
    glOrtho(-5.0, 15.0, -5, 15.0, -1.0, 1.0);
    glColor3f(1.0, 0.0, 0.0);
    glEnable(GL_POINT_SMOOTH);
    glPointSize(5);
    //triangle points
    point2 p1, p2, p3;
    p1[0] = 5.0;
    p1[1] = 0.0;    
    p2[0] = 10.0;
    p2[1] = 0.0;
    p3[0] = 7.5;
    p3[1] = 10.0;
    init(p1,p2,p3);
//    glBegin(GL_TRIANGLES);
//        glVertex2fv(p1);
//        glVertex2fv(p2);
//        glVertex2fv(p3);
//    glEnd();
    for(int j=0 ; j< 10000; j++){
        display();
    }
    glFlush();
    glutSwapBuffers();
    glutMainLoop();
    return 0;
}
void init(point2 p1, point2 p2, point2 p3){  
    myTriangle t;
    t[0][0] = p1[0];
    t[0][1] = p1[1];
    t[1][0] = p2[0];
    t[1][1] = p2[1];
    t[2][0] = p3[0];
    t[2][1] = p3[1];
    triangle = &t;    
}
void display(void){
    static point2 p = {1,1};
    int i;
    //pick a random vertex    
    i = rand() % 3;  //i in the range 0 to 2
    p[0] = (p[0] + *triangle[i][0])/2;
    p[1] = (p[1] + *triangle[i][1])/2;
    cout << p[0] << ' , ' << p[1] << endl;
    //display new points
    glBegin(GL_POINTS);
        glVertex2fv(p);
    glEnd();

}
void init(point2 p1, point2 p2, point2 p3){  
    myTriangle t;
    ..
    triangle = &t;
} // Life time of 't' ends here.

问题是triangle引用了导致未定义行为的局部变量。

您正在init函数中分配局部变量的地址。 当init返回时,您分配的地址不再有效,因为与该地址绑定的变量是本地变量。

void init(point2 p1, point2 p2, point2 p3)
{  
    myTriangle t;
    t[0][0] = p1[0];
    t[0][1] = p1[1];
    t[1][0] = p2[0];
    t[1][1] = p2[1];
    t[2][0] = p3[0];
    t[2][1] = p3[1];
    triangle = &t;    // <-- assigning address of local variable.  No good.
}

代码的问题在于,您没有一个活动myTriangle可供您分配给triangle指针。

您当前的代码triangle设置为一个myTriangle,一旦init函数返回,该就会消失,并且代码中的任何内容都表明triangle将指向的这个"活动"对象将存在在哪里。

所以实际上,你要求一个只有你能真正想出的解决方案。 我们可以建议一些事情,比如分配一个全局myTriangle,地址不会失效,或者在函数中使用new myTriangle来动态分配一个地址(这会导致其他问题),或者其他类似的答案。 但是,这是您必须做出的设计决策。

typedef GLfloat point2[2]; 
typedef GLfloat myTriangle[3][2]; // EDIT
myTriangle *triangle;

编译和运行正常,应该做你想做的事。

除了马赫什的回答,*triangle[i][0]可能没有做你想做的事。相当于*(triangle[i][0]).由于triangle指向单个三角形,因此如果i > 0,则为UB。你需要做(*triangle)[i][0]。这将首先取消引用指针。