You have to consider the C way to layout a multidimensional array.
In C all data is serialized in memory following the reverse order of the dimensions.
I.e. an array int a[2][3] consider the first dimension as row and the last as column, looking to the memory layout yopu'll find 2 series of the corresponding 3 column values.
The basic concept is that C knows only arrays of arrays, so a[2][3] is an array of 2 arrays of 3 elements sequentially stored.
This means that for arrays having all the same dimensions, but not the first, can be copied sequencially. That is your case.
On practiical side try this code:
void print_matrix(int *m, int rows, int cols)
{
for (int r=0; r<rows; ++r)
{
for (int c=0; c<cols; ++c)
printf("%.2i ", *(m+(r*cols)+c));
printf("\n");
}
}
int main(int argc, char *argv[])
{
int a[4][4] = {{1,2,3,4},{11,12,13,14}, {21,22,23,24}, {31, 32, 33, 34}};
int b[2][4] = {{41,42,43,44}, {51, 52, 53, 54}};
printf("Matrix a:\n");
print_matrix((int *)a, 4, 4);
printf("Matrix b:\n");
print_matrix((int *)b, 2, 4);
int *c = malloc((4*4+2*4) * sizeof(int));
memcpy(c, a, 4*4*sizeof(int));
memcpy(c+4*4, b, 4*2*sizeof(int));
printf("Full Matrix:\n");
print_matrix((int *)c, 6, 4);
return 0;
}
It shows how the array layout is done, and how to mix matrices having all dimensions equal, but not necessary the first.
To concatenate matrices having different dimensions requires some more considerations:
find the larger one, pad space for missing element, ... But this is another story. ;-)
P.s. I used the matrix address as a pointer to int to emphasize the memory layout.
I suppose that who use the code is confortable with the pointer arithmetic...