0

Want to construct a Graph with adjacency list, but getting seg-fault when I add elements to vector<vector<int>>. adj.size() prints 5 which tells it has allocated memory, why the seg-fault in addEdge() method?

 #define V 5

    struct Edge {
        int src, dst;
    };

    void addEdge(vector<vector<int>> &adj, int u, int v)
    {
        adj[u].push_back(v);
    }

    void constructGraph(vector<vector<int>> &adj, vector<Edge> &edges)
    {

        for(Edge e : edges)
        {
            addEdge(adj, e.src, e.dst);
        }
    }

    int main()
    {
       vector<vector<int>> adj(V);

       vector<Edge> edges =
        {
            { 0, 1 }, { 1, 2 }, { 2, 0 }, { 2, 1 },
            { 3, 2 }, { 4, 5 }, { 5, 4 }
        };

        constructGraph(adj, edges);

       return 0;
    }

bolov
  • 72,283
  • 15
  • 145
  • 224
a k
  • 531
  • 5
  • 15
  • 4
    5 is out of bounds on a vector of size 5. I think you meant `#define V 6`? – ggorlen Sep 14 '19 at 04:15
  • 1
    if you had used `.at()` it would tell you something like `terminate called after throwing an instance of 'std::out_of_range'` – Andreas DM Sep 14 '19 at 06:28
  • @Andreas DM yes, just learnt that using .at() is always safer and is recommended over using [ ], the c programmer in me had to learn it the hard way. – a k Sep 14 '19 at 22:41

2 Answers2

3
void addEdge(vector<vector<int>> &adj, int u, int v)
{
    adj[u].push_back(v);
}

is incorrect. The operator[]() for a vector ASSUMES the supplied index is valid. If u is not valid, the behaviour is undefined.

In your code, the vector passed has five elements, and the last edge in main()

vector<Edge> edges =
    {
        { 0, 1 }, { 1, 2 }, { 2, 0 }, { 2, 1 },
        { 3, 2 }, { 4, 5 }, { 5, 4 }               // note the last pair here
    };

will cause addEdge() to be called with u having a value of 5. That is one past the end.

While #define V 6 will fix the problem, it doesn't protect addEdge() from being passed a bad value of u. Instead I would implement addEdge() so it protects itself from bad data as follows.

void addEdge(vector<vector<int>> &adj, int u, int v)
{
    if (u < 0) return;                   // handle negative u
    if (u >= adj.size()) adj.resize(u+1);  //   resize if needed
    adj[u].push_back(v);
} 

An even better approach would be to avoid using supplied data - such as the data in edges in your main() - as array indices at all.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

Solved. Thanks for the guidance provided here, read up more on this and learnt that c++ language has protection built into it for these kinds of issues. Using .at() method protects the programmer from out-ob-bounds accesses.

void addEdge(vector<vector<int>> &adj, int u, int v)
{
    adj.at(u).push_back(v);
}

if you use adj.at(u) instead of adj[u], program exits little gracefully

terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 5) >= this->size() (which is 5)
Aborted (core dumped)
a k
  • 531
  • 5
  • 15