The program seg faults once it reaches this line of code (the code is in Graph.cpp in the function set_array.)
adjList[adjList.size()].push_back(Edge(vertex, 0));
Basically, I want this line to be called every time i need to make the vector longer to fit more linked lists, as the structure is an vector of linked lists. Here is the .h file that declares the vector of linked lists and its contents. Every node will contain a vertex and a weight. (The node class is known as class Edge.)
#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED
//class MinPriority;
#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;
class Graph
{
public:
Graph();
~Graph();
void set_Edge(string targetVertex, string vertex, int weight);
void set_array(string vertex);
void print_Test();
friend class MinPriority;
private:
class Edge
{
public:
Edge(string vertex, int weight)
{m_vertex = vertex; m_weight = weight;}
~Edge(){}
string m_vertex;
int m_weight;
};
vector< list<Edge> > adjList; //declaration of the array of linked lists
};
#endif // GRAPH_H_INCLUDED
here is what I want adjList[adjList.size()].push_back(Edge(vertex, 0)); to do; basically every time I want to insert a new vertex into the graph, I will call this. It seg faults as soon as I try to put the first item in the tree. Ill call to insert 'A' with a weight of '0' and it will immediately seg fault. By the way, I am trying to make an adjacency list where i use adjList[adjList.size()].push_back(Edge(vertex, 0)); to add a new (unused) vertex into the graph. Lets pretend this is passed into the function...
A B C D
After doing this, the vector's length should increase by 4. But of course it instead seg faults at that line (it tells me in GDB). I'm very new to using wierd data structures like this so any help would be very appreciated.
Try
adjList[adjList.size()-1]
The arrays are indexed 0..(size-1).
For instance, the indices of a 4 element array are 0, 1, 2 and 3.
If there is a possibility that the array is empty, you can add logic to prevent any access at all --
if (adjList[adjList.size() > 0) ...
Try to cast your array index :
adjList[int(adjList.size())]
Or try with 0 ?
EDIT : It seems you have to manually enter the lists before pushing Edge elements in it.
// Creation of independant lists
list<Edge> Eg, Ec;
Edge h("AB", 0);
Edge f("CD", 0);
adjList.push_back(Eg);
adjList[adjList.size()-1].push_back(h);
adjList.push_back(Ec);
adjList[adjList.size()-1].push_back(f);
// Return 2
cout << adjList.size();
I haven't found another way yet. But i'm no c++ expert.
Related
I am implementing a path planning algorithm using graphs. In my implementation I have structures Node and Edge. One of the members of Node is a list of edges. I have a weird problem that came up in my code when I used a pointer to a node in an array, I've managed to isolate it below:
int main()
{
// Node node_array[5]; // If I use this array, the program works fine.
Node* node_array=(Node*)calloc(5, sizeof(Node) ); // This causes a problem
Node* pointer_to_node=&(node_array[0]);
pointer_to_node->id=0;
cout << "Did it work?" << "\n";//.
cout << pointer_to_node->id << "\n"; // This works fine
cout << (*pointer_to_node).id << "\n"; // This works fine
Node bla=*pointer_to_node; //This crashes the program. But if I remove the list of edges from Node, then it works fine.
cout << "Yes it worked!" << "\n"; // Something is breaking if I don't reach this.
}
The program crashes (exists without printing "Yes it worked!") when I try to dereference pointer_to_node. There are three things I've noticed.
-If I define a Node, form a pointer and then dereference it, there is no problem.
-If I create an array of nodes using Node node_array[5];, the program works fine.
-If I remove the list of edges member from Node, everything works fine.
I know there are probably many easier ways to implement something like this, but I'm curious to know what exactly am I breaking here to make the program crash. I'm new to c++ and Stack Overflow, so any feedback is appreciated.
Here is the rest of the code above main()
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include <iostream>
#include <list>
using namespace std;
struct Node; // NOTE: we'll define this in detail later, but we need it now
struct Edge;
// this is a basic graph node
struct Node
{
int id;
list<Edge> edges; // these are edges from {nodes which this node can be accessed}
};
//basic edge data stucture
struct Edge
{
Node* startNode; // the edge starts at this node
Node* endNode; // the edge goes to this node
double edgeCost; // going along the edge cost this much
};
Your Node contains a list. This is a C++ class with its own non-trivial state.
The difference between Node node_array[5]; and calloc(5, sizeof(Node) ) is that the first one will actually call the constructors properly. The code bombs when trying to copy this badly initialized list somewhere else. If you want a dynamic allocation, use new Node[5] instead.
I have a list that hold an array of lists.
I have 2 object types "Flight" and "People" The other one is "Management". I created a list that holds a list of people for each Flight object made. I'm trying to make a list of lists that holds lists of people assigned to each Flight.
But I can only add 1 list to the list of list at location 0. Anything beyond that is a segmentation fault.
This is my Flight Class;
class Flight {
public:
int maxPeople;
int currentPos = -1;
int flightNo;
People list[50]; // list of people
public:
Passenger *list;
Flight();
Flight(int maxPassenger, int flightNo);
void addPeople(Passenger passenger);
};
class Management {
public:
const int maxFlights=20;
public:
Management();
addFlight(Flight flight);
};
This is my implementation of the prototypes:
//Global Variables
int currentPos1=-1; //
Flight *list2[20]; //list of list
//Constructor
Flight::Flight(int maxPeople2, int flightNo2) {
maxPeople = maxPeople2;
list = new People[maxPassenger]; //List means List of Passengers
flightNo = flightNo2;
Management::Management() {};
//Addflight
void Management::addFlight(Flight flight) {
currentPos1++;
*list2[currentPos1] = flight;
}
//Main
int main(void) {
Flight f1 (25, 333);
Flight f2 (25, 444);
a.addFlight(f1); // works
a.addFlight(f2); //Segfault
}
I am incrementing the currentPos1 everytime I add. And the list of lists (*list[20]) has 20 spots assigned. I can't figure out why it'll try to access a location out of that 20 that doesn't exist and causing segmentation fault.
Any Help would be very appreciated.
You don't initialize or allocate storage for any of the pointers in list2 anywhere. It's random that the first call to addFlight() doesn't segfault. This code
*list2[currentPos1]
ends up dereferencing a random memory location. If you change it to this:
list2[currentPos1] = &flight;
Well that's about as bad, because flight is a function parameter that's going to go away as soon as addFlight() returns.
Why are you using pointers and native arrays? Don't do that. Use std::vector.
Change list2 to
std::vector< Flight > list2;
and in addFlight()
list2[currentPos1] = flight;
i changed function addFlight() in Management as follows and it worked(atleast in my complier which didnt have complete code)
list2[currentPos1]=& flight;
which origiinally was
*list2[currentPos1]=flight;
I'm trying to create a node class that contains a vector of pointers. Here's my code:
node.h:
#ifndef NODE_H
#define NODE_H
class node
{
public:
vector<node*> next;
void add_arc(node & a)
string some_string;
#endif
node.cpp:
void node::add_arc(node & a)
{
node *b = &a;
next.push_back(b); //only copyies nodes
}
main.cpp:
int main()
{
vector<node> nodes;
node a;
node b;
node c;
a.somestring = "a";
b.somestring = "b";
c.somestring = "c";
a.add_arc(b); //a should point to b
a.add_arc(c); //a should point to c
nodes.push_back(a);
nodes.push_back(b);
nodes.push_back(c);
cout << nodes[0].next.size() << endl; // prints "2", works fine
cout << nodes[0].next[0]->some_string << endl; //empty
}
I thought it would be as easy as just overloading push_back:
void push_back(vertex * pointer)
{
next.push_back(pointer);
}
But I think I really need a copy constructor, or some other method to make this work. How would I go about doing this for a vector of pointers?
Edit: I guess I didn't explain it well. Look at the answers in this question:
Segmentation fault when accessing a pointer's member function in a vector
Making 'a' a reference did not work for me
It works...
Your code generates as expected the correct output (see online demo):
2
b
...However this design is not future proof
However this result is related somehow to luck, because in your code snippet:
the nodes in the nodes vector are copies of the original object including all their pointers
the local objects a, b, c to which these pointers point still exist
However in more complex code, you'd quickly end up with dangling pointers.
Imagine:
Bad example 1: you create a graph, keeping all the nodes directly in a vector of nodes. You then add the first arcs between the nodes. As soon as you'll add a new node to the vector, reallocation might occur and you'd risk to see all your next pointers invalidated.
Bad example 2: you initialise a graph like you did, but in a function called by main. In this case, as soon as you return from this function, all the local nodes get destroyed and the vector's node will point to objects that do no longer exist. UB guaranteed !
How to improve ?
Your design fails to recognize that the nodes all belong to the same graph.
There is a quick and dirty way out: always create the node from the free store, and store them in a vector<node*>.
vector<node*> nodes;
node *a = new node("a"); // Imagine a node constructor
node *b = new node("b");
a->add_arc(b); //change signature, to accept a pointer
nodes.push_back(a);
nodes.push_back(b);
There's a better approach: improve further the previous approach, but use shared_ptr<node*> to make sure that nodes that are no longer referenced (neither by a vector of nodes, nor by an arc) are destroyed automatically.
There's an even better approach: encapsulate the nodes in a class representing a graph. In this case, you could consider using a vector<nodes> and replace the pointers in next, by indexes of the target nodes in the vector. No pointer, but perfect copy of graphs will be much easier. And no more memory management hassle.
class node // just to give the general idea
{
public:
vector<int> next; // not usable without the graph
void add_arc(int a)
string id;
};
class graph {
vector<node> nodes;
public:
void add_node (node a);
void add_arc (string from, string to);
node& operator[] (size_t i);
...
};
I am writing a c++ program to code for dijkstra's algorithm. Here is the code.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
class vertex;
class node
{
public:
int value;
//bool exp=false;
char c;
};
class edge
{
public:
vertex* head;
vertex* tail;
int length;
edge(vertex*h,vertex* t, int l)
{
head=h;
tail=t;
length=l;
}
};
class vertex:public node
{
public:
vector<edge*> a;
vertex& operator|(vertex &p)
{
int l;
cout<<"Give the length of edge "<<this->c<<p.c<<endl;
cin>>l;
edge q(&p,this,l);
a.push_back(&q);
}
vertex(char a)
{
c=a;
}
};
int main()
{
vertex e('e');
vertex d('d');
vertex b('b');
vertex c('c');
vertex a('a');
vertex s('s');
s.value=1;
a.value=2;
b.value=3;
c.value=4;
d.value=5;
e.value=6;
s|a;
s|b;
a|c;
b|c;
b|d;
c|d;
c|e;
d|e;
cout<<"4";
map <char ,int >A;
vector<edge*>::iterator minin;
vector<edge*>::iterator j;
int min=0;
vector<vertex*> X;
X.push_back(&s);
A['s']=0;
vector<vertex*>::iterator i=X.begin();
for(; i<X.end(); i++)
{
cout<<"1";
j=((*i)->a).begin();
for(; j<((*i)->a).end(); j++)
{
cout<<"2";
if((*j)->length+A[((*j)->tail)->c]>min)
{
cout<<"3";
minin=j;
min=(*j)->length+A[((*j)->tail)->c];
}
}
}
X.push_back((*minin)->head);
A[((*minin)->tail)->c]=min;
cout<<((*minin)->head)->value;
}
The program returns a segmentation fault. I have used various cout statements to check where the fault occured but nothing is printed in console. However, I am able to input the edge length in the console but after giving the input it directly gives segmentation fault.
In
a.push_back(&q);
you are storing the address of a local object, which will cease to exist once the function terminates.
Why are you creating a class to keep your vertices/nodes?. I think you should use plain integers from 0 to N - 1 to avoid get things more complicated. If vertices are identified by a string or something else, you could use a hash/map data structure to transform the keys to an integer. That will help you to avoid moving complex vertex structures and using pointers.
The Edge class seems fine because the Dijkstra's algorithms needs all that data to work (start, end vertices, and the weight/cost of the path).
Having said that, the algorithm could be implemented using a binary heap data structure to prioritize the edge selection. You could also use a priority queue (http://en.cppreference.com/w/cpp/container/priority_queue) if you don't want to implement a binary heap.
Finally, I would use a Edge vector to iterate over the adjacent vertices of every vertex.
To represent a Graph in adjacency-list style, I'm using a vector containing pointers to a list of adjacent.
class Graph
{
public:
Graph(int V)
{
vector<list<int> *> vertices(V);
}
// Member functions for Graph class
void addEdge();
void print();
void type(string);
private:
vector<list<int> *> vertices;
};
Getting the number of vertices from the user in main function-> passing it to the constructor, it all works, meaning the vector is being initialized of the desired size! But right after the program comes back from the header file to the main function, Things change! as in tracing the value of vertices: the size is somehow being reset somewhere that I don' know of!!!
int size;
cout << "Enter the number of vertices in the Graph: ";
cin >> size;
Graph g(size);
Immona need help with this, what could possibly go wrong?!
You're creating a temporary vector (local variable) in your constructor :
Graph(int V)
{
vector<list<int> *> vertices(V);
}
You need to initialize your member variable instead :
Graph(int V) : vertices(V) {}
Also, I would suggest using std::unique_ptr<list<int>> instead of raw pointers if you really need to use pointers, else simply store plain std::list<int>.