1

I am trying to create a program that is capable of randomly generating a grapgh (matrix representation) and then understand if it is connected or not. To do so, I need to pass to the is_connected function a 2D boolean array, the graph, its number of nodes (size here), and two boolean arrays for the open and closed set, used to determine if the graph is or not connected.

I’m trying to pass all arrays by reference, and tried it in test program:

void set(bool* a){
    for(int i = 0; i< 7; i++){
        a[i] = true;
    }
}

int main() {
    const int size = 7;
    bool* a[size];
    return 0;
}

Now, this works, but if I try to do the same in my program it doesn't. Here is the main function:

#include <iostream>
#include <sstream>
#include <random>
using namespace std;


int main(){

    const int size = 7;
    bool connection = false;
    bool* c_set[size]; //pointer to a 1D array
    bool* o_set[size];
    bool** graph; //pointer to a 2D array of not set dimention

    graph = new bool*[size];

    for (int i = 0; i < size; i++){
        graph[i] = new bool [size];    
    }

    //filing the graph with edges
    for(int i = 0; i < size; i++){
        for(int j = i; j < size; j++){
        //undirected edges, so the matrix is symmetric
            if(i==j){graph[i][j] = false;}else{
                graph[i][j] = graph[j][i] = (prob() < 0.19);
            }
        }
    }

    print_graph(graph,size);

    connection = is_connected(c_set, o_set, graph, size);

    cout << "The graph is connected?\t" << connection;

    return 0;

}; 

And here are the functions I created

double prob(){
    const int range_from  = 0;
    const int range_to    = 1;
    std::random_device                  rand_dev;
    std::mt19937                        generator(rand_dev());
    std::uniform_int_distribution<int>  distr(range_from, range_to);
    return distr(generator);
}

bool is_connected(bool* c_set, bool* o_set, bool** graph, const int size){

    int old_size = 0, c_size = 0;

    //initialization
    for(int i = 0; i < size; i++){
        c_set[i] = false;
        o_set[i] = false;
    };

    o_set[0] = true;

    while(c_size < size){
        for(int i = 0; i < size; i++){
            old_size = c_size;
            //check which new nodes are reachable
            for (int j = 0; j < size; j++){
                o_set[j] = o_set[j] || graph[i][j];
            }            
            //adding nodes to the closed set
            if (o_set[i]&&(c_set[i]==false)){
                c_set[i] = true;
                c_size++;
            }
            if (old_size == c_size){
                return false;
            }
        }
    }

    if(c_size == size){
        return true;
    }
    return true;
}

void print_graph(bool** graph, const int size){
    for(int i = 0; i < size; i++){
        for(int j = 0; j < size; j++){
            cout << graph[i][j] << "\t";
        }
        cout << "\n";
    }
}

The compiler error I receive is:

argument of type "bool **" is incompatible with parameter of type "bool *"

Referred to line for values c_set and o_set:
connection = is_connected(c_set, o_set, graph, size);

Can someone help in understanding why what I recollect is a 1D boolean array is seen as a 2D array?

7
  • 3
    bool* cset[size] is an array of pointers to bool. You expect it to be an array of bool, which would be bool cset[size] or if dynamically allocated bool* cset = new bool[size] Commented Jul 5 at 11:31
  • 1
    void set(bool* a){ err this is not how we do arrays in C++ anymore. @Homer512 and even new delete should not be used anymore. std::span<bool> would be the correct C++ idiom to use. Normally I would say to use std::vector<bool> as container (but it is slow). So to allocate a boolean array use std::unique_ptr<bool[]> cset = std::make_unique<bool[]>(size). Commented Jul 5 at 11:42
  • 2
    Read the C++ core guidelines and take note of any of the guidelines that mention "array", "raw pointer" and "new" or "delete" Commented Jul 5 at 11:43
  • 2
    drop all this pointers and raw arrays and write actual c++. There is std::array and std::vector Commented Jul 5 at 11:49
  • I’m trying to pass all arrays by reference, and tried it in test program: -- That program does not pass arrays by reference. A reference in C++ has a specific meaning -- it does not mean "pointer" or "address". You are passing by value, and the value just happens to be a pointer. Commented Jul 5 at 11:50

1 Answer 1

1

What's the issue?

There is a misunderstanding here:

    bool* c_set[size]; //pointer to a 1D array
    bool* o_set[size];

Indeed, these are not pointer to 1D array, but a 1D array of bool pointers. When used in the argument of is_connected() the array of bool pointers is decayed to a pointer to bool pointers, i.e. bool**. This is indeed not a what the parameter expects.

How to correct it easily?

A quick fix is to correct your definitions, to what you really wanted. The code then compiles and seems to provide some reasonable output (I have not reviewed the code, so no guarantee that there are no other issues):

bool c_set[size]; // 1D array that will decay to a pointer
bool o_set[size];

Further improvement you should consider

A better approach would be to avoid native arrays as much as possible , and prefer either std::array if the constant size is really a feature here, or a std:vector to allow for dynamic sizes. You can then without surprises pass these objects by reference and no longer have to worry about array decay and pointers, and sizes. Most of all, it would avoid error-prone manual array memory allocation.

Here a quick and dirty rewrite of your code (some more tests and review are necessary) for an online demo: https://ideone.com/BlxvVR

Note: another significant benefit of the vector here is that you MAY benefit from a space optimisation of vector<bool> that the standard library can offer (if your compiler maker/library provider uses it). The library implementer could for example chose to use implement a bool in the vector as a single bit. But this only matters if you'd had very large graphs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.