Reputation: 8718
I have two structs pointers to pointers
typedef struct Square {
...
...
}Square;
Square **s1; //Representing 2D array of say, 100*100
Square **s2; //Representing 2D array of say, 200*200
Both are allocated on the heap using malloc()
.
I have s1
initialized with certain values and s2
initialized completely with the default values.
Basically I need to resize s1
to the size of s2
while maintaining its (s1
) values, and the 'added' values would be just as they were in s2
- the default value.
I wrote this question memcpy() from smaller array to larger one but apparently I'm confusing between arrays and pointers/
My question is, how to implement this resizing of s1
to the size of s2
. I don't have to keep the original pointer. I can copy s1
to s2
and return s2
if that's a better way
I hope I explained what I'm after properly.
Thanks!
Upvotes: 0
Views: 5444
Reputation: 5687
You've allocated your 2-D matrix on the heap, and you're using a Square**
to access it. This means that you've: (1) allocated the space for each element in one or more calls to malloc
, and (2) allocated the space for all of the row pointers in a call to malloc
. How to proceed depends quite a lot of how you've allocated the array.
Below, I use assert
to stress that each malloc/realloc can return NULL (indicating that it could not complete the request). You'll probably want to handle these cases properly.
You allocated the s1
matrix like this:
Square** s1 = malloc(M1*sizeof(s1[0]));
for (size_t i=0; i < M1; i++)
s1[i] = malloc(N1*sizeof(s1[i][0]));
In this case, you have to handle each row separately:
/* M1 and N1 set to size of s1 (M1 x N1) */
/* M2 and N2 set to size of s2 (M2 x N2) */
/* First, reallocate the pointers to each row */
Square** tmpRows = realloc(s1, M2*sizeof(*tmpRows));
assert( (tmpRows != NULL) && "Out of memory reallocating rows" );
s1 = tmpRows;
/* Now, reallocate each row */
for (size_t i=0; i < M1; i++) {
Square* tmpVals = realloc(s1[i], N2*sizeof(tmpVals[0]));
assert( (tmpVals != NULL) && "Out of memory reallocating row" );
/* copy elements of s2 into new column */
memcpy(tmpVals+N1, s2[i]+N1, (N2-N1)*sizeof(s1[i][0]));
s1[i] = tmpVals;
}
/* Now, allocate each new row of s1 and copy the additional rows of s2 into s1 */
for (size_t i=M1; i < M2; i++) {
s1[i] = malloc( N2 * sizeof(s1[i][0]) );
assert( (s1[i] != NULL) && "Out of memory allocating new row" );
memcpy(s1[i], s2[i], N2*sizeof(s1[i][0]));
}
In this case, you allocated all of the rows in one big chunk, and then assigned pointers to the beginning of each row. Like this:
Square** s1 = malloc(M1*sizeof(s1[0]));
s1[0] = malloc( M1*N1*sizeof(s1[0][0]) );
for(size_t i=1; i < M1; i++)
s1[i] = s1[i-1] + N1;
To resize the array (and initialize its new elements with those of s2), you should do the following:
/* M1 and N1 set to size of s1 (M1 x N1) */
/* M2 and N2 set to size of s2 (M2 x N2) */
/* Make a new copy of the elements of s1. Linear layout of a 200x200
* matrix will be different than the linear layout of a 100x100 matrix.
* Making a new copy makes it easier to initialize its values.
*/
Square* new_mat = malloc( M2*N2*sizeof(new_mat[0]) );
assert( (new_mat != NULL) && "Out of memory allocating new matrix" );
/* Initialize with values of s2. Assumption: s2 is also allocated
* as a contiguous array...
*/
memcpy(new_mat, s2[0], M2*N2*sizeof(s2[0][0]));
/* Now, reallocate the rows */
Square** tmpRows = realloc(s1, M2*sizeof(s1[0]));
assert( (tmpRows != NULL) && "Out of memory reallocating rows" );
s1 = tmpRows;
/* Copy data from old rows into new rows... */
for (size_t i=0; i < M1; i++) {
/* rows of s1 still point to old_mat data, copy it into new_mat.
* Each row in new_mat starts at (new_mat + N2*i)
*/
memcpy( new_mat + N2*i, s1[i], N1*sizeof(s1[i][0]) );
}
/* Free old memory and assign new row pointers... */
free(s1[0]);
s1[0] = new_mat;
for (size_t i=1; i < M2; i++)
s1[i] = s1[i-1] + N2;
Upvotes: 1
Reputation: 17988
You can try something like this:
typedef struct {
//
} Square;
Square** s1; // 100x100, needs to resize and be like s2.
Square** s2; // 200x200
void resize_s1()
{
// resize the outer array
s1 = realloc(s1, sizeof(Square*)*200);
memset(s1 + 100, 0, 100*sizeof(Square*)); // we initialize the newly allocated pointers to NULL
for(int i = 0; i < 200; ++i)
{
// resize the inner array. Since we initialized the last
// 100 pointers to null, realloc will just behave like
// malloc for them.
s1[i] = realloc(s1[i], 200*sizeof(Square));
// ... and copy the new values in! You can omit this step,
// but anything outside of the original bounds of s1 will
// be uninitialized. All your pointers will be valid though.
if(i >= 100)
memcpy(s1[i] + 100, s2[i] + 100, 100*sizeof(Square));
}
}
As a word of warning - I'm playing very fast and loose with realloc here. Read its man page for more details, but if you ever hit low memory conditions, bad things can happen.
Upvotes: 1
Reputation: 7789
Two dimensional arrays are laid out in memory sequentially: row1 row2 row3 etc.
memcpy does a linear copy from one memory location to another.
So to achieve what you need:
a) Create a new array
Square **s3 = malloc(sizeof(s2));
b) Copy s2 into it
c) Copy stuff from s1, row by row into new
for(r = 0; r < NROWS_S1; r++)
memcpy(s3[r], s1[r], sizeof(Square) * NCOLS_S1);
http://www.fredosaurus.com/notes-cpp/arrayptr/23two-dim-array-memory-layout.html
Upvotes: 1