简体   繁体   中英

How convert 2d vector to 1d array in C++?

I need to be able to do this without using C++ smart pointers. I tried the following

double* VecToArr(std::vector<std::vector<double>> vec) {
    double* newarr=new double(vec.size());
    for (int i=0; i<vec.size(); i++) {
        std::copy(vec[i].begin(), vec[i].end(), newarr);
        newarr += vec[i].size();
    }
    std::cout<<"inside \n";
    for (int i=0; i<vec.size(); i++) {
        std::cout<<newarr[i]<<"\n";
    }
    return newarr;
}

int main(){
    std::vector<double> x{1,2};
    std::vector<double> y{3,4};
    std::vector<std::vector<double>>vec;
    vec.push_back(x);
    vec.push_back(y);
    double *arr=VecToArr(vec);
    std::cout<<"outside \n";
    for (int i=0; i<4; i++) {
        std::cout<<arr[i]<<"\n";
    }
}

But inside the VecToArr , the output is:

inside
4.54e-322 2.18e-317 4.34e-311 4.24e-314

not 1 2 3 4 like I expected

And outside it, I get the same garbage values. Why is this?

Also, since I used new to create newarr inside VecToArr , where how do I delete it? In main.cpp , after I print out the values, do I just do delete arr[] ?

EDIT

When I change the function to:

double* VecToArr(std::vector<std::vector<double>> vec) {
    double* newarr=new double[vec.size()*vec[0].size()];
    for (int i=0; i<vec.size(); i++) {
        std::copy(vec[i].begin(), vec[i].end(), newarr);
        newarr += vec[i].size();
    }
    std::cout<<"inside \n";
    for (int i=0; i<vec.size(); i++) {
        std::cout<<newarr[i]<<"\n";
    }
    return newarr;
}

The output is now 3 4 (garbage) (garbage) instead of 1 2 3 4 .

The three main problems are as others have mentioned in the comments and a bit more. Firstly, you're using the wrong type of new expression, new double(...) simply allocates memory for a single double and initializes it with the value of what was provided. You probably want new double[...] to allocate an array of the doubles.

Secondly, the size provided to this new is incorrect, only representing the first dimension of the vector (when it needs to be a sum of all the nested vectors' sizes).

Finally, you're returning newarr , which has been modified by the for loop inside the function and ends up pointing to the memory after where the allocation took place, you'll likely want to make a temporary copy of it at the start and return that instead.

With all the changes the final correct function may look like this:

double* VecToArr(std::vector<std::vector<double>> vec) {
    std::size_t totalsize = 0;

    for (int i=0; i<vec.size(); i++) {
        totalsize += vec[i].size();
    }

    double* newarr=new double[totalsize];
    double* walkarr=newarr;

    for (int i=0; i<vec.size(); i++) {
        std::copy(vec[i].begin(), vec[i].end(), walkarr);
        walkarr += vec[i].size();
    }

    return newarr;
}

I'd also recommend passing the vector in by constant reference as currently it is being passed by value for (currently) no reason which may result in unnecessary overhead. Additionally, you should try to always use something like std::vector (or at least smart pointers) for allocation of memory rather than using new / delete directly (unless dealing with low level container implementation) as there is usually not much reason to at the expense of opening the program up to memory leaks.

Look at this piece of code:

double* newarr=new double[vec.size()];
for (int i=0; i<vec.size(); i++) {
    std::copy(vec[i].begin(), vec[i].end(), newarr);
    newarr += vec[i].size();
}

A simple math fells violated here. You allocate your newarr to be the size of vec . So far so good. Now, for each element in vec you increment the pointer by vec[i].size - effectively leading to the used size of SUM(vec[i].size()) . This is not right, you have undefined behavior in your program by accessing array outside of it's allocated bounds.

Please note, I also fixed a typo in your code - your original version of new double(vec.size()) allocated a single double, not an array of them.

There are issues with memory allocation, indexing and pointer arithmetic. I have pointed out those in your code.

#include <iostream>
#include <vector>

double* VecToArr(const std::vector<std::vector<double>>& vec) {
    double* newarr=new double[vec.size() * vec[0].size()]; // <-- you have 4 elements (also notice square brackets)
    double* newarr_ptr_copy = newarr;
    for (int i=0; i<vec.size(); i++) {
        std::copy(vec[i].begin(), vec[i].end(), newarr_ptr_copy);
        newarr_ptr_copy += vec[i].size(); // don't lose track of newarr
    }

    std::cout<<"inside \n";
    for (int i=0; i<vec.size(); i++) {
        std::cout<<newarr[i]<<"\n";
    }
    return newarr;
}

int main(){
    std::vector<double> x{1,2};
    std::vector<double> y{3,4};
    std::vector<std::vector<double>>vec;
    vec.push_back(x);
    vec.push_back(y);
    double *arr=VecToArr(vec);
    std::cout<<"outside \n";
    for (int i=0; i<4; i++) {
        std::cout<<arr[i]<<"\n";
    }
    delete [] arr; // make sure that you release the memory that you allocated
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM