SyncMaster
SyncMaster

Reputation: 9936

How to use memset or fill_n to initialize a dynamic two dimensional array in C++

I have a 2D array created dynamically.

int **abc = new int*[rows];

for (uint32_t i = 0; i < rows; i++)
{
    abc[i] = new int[cols];
}

I want to fill the array with some value (say 1). I can loop over each item and do it.

But is there a simpler way. I am trying to use memset and std::fill_n as mentioned in this post.

std::fill_n(abc, rows * cols, 1);
memset(abc, 1, rows * cols * sizeof(int));

Using memset crashes my program. Using fill_n gives a compile error.

invalid conversion from 'int' to 'int*' [-fpermissive]

What am I doing wrong here ?

Upvotes: 6

Views: 2795

Answers (4)

VolkerK
VolkerK

Reputation: 96159

Since you've already got good, workable answers to solve your problem, I want to add just two pointers left and right from the standard path ;-)

a) is just a link to the documentation of Boost.MultiArray

and b) is something I don't recommend you use, but it might help you to understand what you've initially tried. And since your profile shows visual studio tags, you might come in contact with something like this in the win32 api. If that is the case the documentation usually tells you not to use free()/LocalFree()/... on the elements and the "outer" pointer-pointer but to use a specialized function.
(note: I'm not trying to make this code look pretty or clever; it's a mishmash of c and a little c++-ish junk ;-))

const std::size_t rows = 3, cols =4; 

int main()
{   
    std::size_t x,y;
    // allocate memory for 0...rows-1 int* pointers _and_ cols*rows ints
    int **abc = (int**)malloc( (rows*sizeof(int*)) + cols*rows*sizeof(int) );

    // the memory behind abc is large enough to hold the pointers for abc[0...rows-1]
    // + the actual data when accessing abc[0...rows-1][0....cols-1]
    int* data = (int*)((abc+rows));
    // data now points to the memory right after the int*-pointer array
    // i.e. &(abc[0][0]) and data should point to the same location when we're done:
    // make abc[0] point to the first row (<-> data+(cols*0)), abc[1] point the second row (<-> data+(cols*1).... 
    for(y=0;y<rows; y++) {
        abc[y] = &(data[y*cols]);
    }

    // now you can use abc almost like a stack 2d array
    for(y=0; y<rows; y++) {
        for (x=0; x<cols; x++) {
            abc[y][x] = 127;
        }
    }

    // and -since the memory block is continuos- you can also (with care) use memset
    memset(&abc[0][0], 1, sizeof(int)*rows*cols);

    // and with equal care ....
    std::fill_n( &(abc[0][0]), rows*cols, 127);

    // and get rid of the whole thing with just one call to free
    free(abc);

    return 0;
}

Upvotes: 1

Rama
Rama

Reputation: 3305

Just use with * inside the loop you already have:

for (uint32_t i = 0; i < rows; i++)
{
    abc[i] = new int[cols];
    std::fill_n(*(abc+i), cols, sizeof(int));
}

fill_n don't know where the memory maps the new int array, so you must be carefully coding that way.

I recommend to read: A proper way to create a matrix in c++

Upvotes: 2

Barry
Barry

Reputation: 303097

You could just use vector:

std::vector<std::vector<int>> abc(rows, std::vector<int>(cols, 1));

You cannot use std::fill_n or memset on abc directly, it simply will not work. You can only use either on the sub-arrays:

int **abc = new int*[rows];

for (uint32_t i = 0; i < rows; i++)
{
    abc[i] = new int[cols];
    std::fill_n(abc[i], cols, 1);
}

Or make the whole thing single-dimensional:

int *abc = new int[rows * cols];
std::fill_n(abc, rows*cols, 1);

Or I guess you could use std::generate_n in combination with std::fill_n, but this just seems confusing:

int **abc = new int*[rows];
std::generate_n(abc, rows, [cols]{
    int* row = new int[cols];
    std::fill_n(row, cols, 1);
    return row;
});

Upvotes: 6

Logicrat
Logicrat

Reputation: 4468

I think that your main problem here is that you don't have an array of int values. You have an array of pointers to ints.

You probably should start with int* abc = new int[rows * cols]; and work from there, if I understand what you are trying to achieve here.

Upvotes: 3

Related Questions