访问存储在矢量中的指针的值

Accessing value of pointer stored in vector

本文关键字:指针 存储 访问      更新时间:2023-10-16

我正在尝试创建一个三角形网格来编写有限元分析的代码。我知道已经编写了软件来做到这一点,但这是为类项目准备的。

我正在尝试做的是将该区域划分为均匀分布的节点(网格点)。每个节点都有 6 个三角形连接到它,需要在计算中使用。为了方便起见,我创建了两个结构,一个用于节点,一个用于三角形。

下面,我有一个我试图在我的代码中实现的内容的最小工作示例。但是,此代码在将 x,y 值分配给顶点的行上收到分段错误。在 gdb 中生成的错误指出:

With using vectors (as per the minimum working example)
----------------------------
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400f90 in std::vector<Node*, std::allocator<Node*> >::operator[] (this=0x0, __n=0)
at /usr/include/c++/4.8/bits/stl_vector.h:771
771           { return *(this->_M_impl._M_start + __n); }
// Running backtrace
(gdb) bt
#0  0x0000000000400f90 in std::vector<Node*, std::allocator<Node*> >::operator[] (this=0x0, __n=0)
at /usr/include/c++/4.8/bits/stl_vector.h:771
#1  0x0000000000400a87 in main () at minimumexample.cpp:28
----------------------------

我不知道如何弄清楚这一点。如果我使用数组代替向量,则会产生类似的错误,所以我认为这只是向量类的问题吗?

With arrays instead of vectors
----------------------------
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400929 in main () at minimumexample.cpp:28
28        MyGrid[0].Triangles[0]->vertex[0]->x = 0;
// Running backtrace
(gdb) bt
#0  0x0000000000400929 in main () at minimumexample.cpp:28
----------------------------

下面是我正在尝试做的事情的最小工作示例。我不确定为什么我会收到越界错误,因为我根本没有看到我在向量中越界的位置。

#include <iostream>
#include <vector>
using namespace std;
struct Triangle;
struct Node
{
double x; 
double y;
vector<Triangle*> Triangles;  
Node() : Triangles(6) {}
};
struct Triangle
{
vector<Node*> vertex;
Triangle() : vertex(3) {} // 3 vertices per triangle
};
int main()
{
int size = 10;
vector<Node> MyGrid(size);
double spacing = .25;
// The below code should create 3 vertices of the triangle with the
// three vertices of the triangle (x,y) defined as locations (0,0) for the 
// first vertex, (1,0) for the second vertex, and (1,1) for the third.
MyGrid[0].Triangles[0]->vertex[0]->x = 0; // Line 28: Error here
MyGrid[0].Triangles[0]->vertex[0]->y = 0;
MyGrid[0].Triangles[0]->vertex[1]->x = 1;
MyGrid[0].Triangles[0]->vertex[1]->y = 0;
MyGrid[0].Triangles[0]->vertex[2]->x = 1;
MyGrid[0].Triangles[0]->vertex[2]->y = 1;
return 0;
}

对于遇到此问题的任何其他人,这是代码的工作版本:

#include <iostream>
#include <vector>
using namespace std;
struct Triangle;
struct Node
{
double x; 
double y;
Triangle *Triangles;  
};
struct Triangle
{
Node *vertex;
};
int main()
{
int size = 10;
vector<Node> MyGrid(size);
double spacing = .25;
// Allocate 6 Triangle objects into the variable Triangles
MyGrid[0].Triangles = new Triangle[6];
// Allocate 3 nodes for Triangles[0]'s vertex
MyGrid[0].Triangles[0].vertex = new Node[3];
MyGrid[0].Triangles[0].vertex[0].x = 0; 
MyGrid[0].Triangles[0].vertex[0].y = 0;
MyGrid[0].Triangles[0].vertex[1].x = 1;
MyGrid[0].Triangles[0].vertex[1].y = 0;
MyGrid[0].Triangles[0].vertex[2].x = 1;
MyGrid[0].Triangles[0].vertex[2].y = 1;
return 0;
}

Node::Node中,

vector<Triangle*> Triangles;  
Node() : Triangles(6) {}

您只需将Triangles初始化为大小6vector。这不会为您提供有效的内存位置 -Triangle*Triangles需要使用new进行分配。

通常,您不需要vector<Triangle*>。只需改用vector<Triangle>即可。

该程序的第二个版本避免了段错误,但没有解决 使用指针首先应该解决的问题。

首先,虽然这是你的问题附带的, 我强烈建议写Triangle* triangles(注意小写t)而不是Triangle* Triangles,因此triangles显然是一个变量名,而不是一个类名。

您现在遇到的问题是,如果您继续初始化 以这种方式MyGrid的其他元素,每个 应该位于顶点的三个Node对象 的网格三角形之一将创建 它自己的Triangle对象来覆盖那个三角形。你最终会得到 三个Triangle对象,你只需要一个,就不会有Triangle,所有三个正确的Node对象都链接到它。 此外,Node没有一个反对任何Node* vertex任何Triangle的数组都在原始vector<Node> MyGrid中, 而且它们都没有链接到任何Triangle(甚至是链接Triangle),更不用说它应该有的六个Triangle*指针了。

你所拥有的甚至不是网格的开始, 它注定是"岛屿"的集合,每个岛屿一个MyGrid的成员,每个人都与其他人完全隔离。

请注意,当您编写MyGrid[0].Triangles[0].vertex[0].x = 0时, 如果所有对象都正确相互连接,则MyGrid[0].Triangles[0].vertex[0]只是指向另一个Node的指针, 大概是MyGrid的成员(为什么要存储Node对象 其他任何地方?),所以做同样事情的更直接的方法会 是确定这是MyGrid的哪个成员,例如成员1, 并改为写MyGrid[1].x = 0

实际上,类似的东西MyGrid[1].setCoordinates(0,0)设置两者 同时使用 x 和 y 坐标将使程序更易于阅读 并且不太可能出错。

更好的策略可能是更改NodeTriangle的定义 回到以前的样子, 但这一次,在您创建Node对象的向量之后, 对于每个Node调用初始化其坐标的成员函数 (或初始化Node构造函数中的坐标,然后push_backvector<Node>); 然后开始创建Triangle对象。对于您创建的每个Triangle, 对于Triangle应连接到的每个Node, 您需要在该Nodetriangle列表中插入Triangle并且您需要将Node插入该Trianglevertex列表中。 由于您总是成对地完成这些作业,因此拥有一个单独的作业是值得的 同时执行这两项操作的函数调用。让事情变得更加方便和 不太容易出错,让成员函数调用该函数三次 的Triangle,需要三个Node*参数,每个参数对应一个NodeTriangle是连接到。

如果这还不够清楚,请尝试绘制一些Triangle的图表 对象和Node对象,用指针箭头连接它们 它们应该连接的方式。无论你写什么都必须 创建一个正确链接所有这些指针的数据结构。