How to convert from 1D array to 2D array using malloc - c++

I'm trying to convert the a 1D array to a 2D array

If you want to allocate an actual 2D array, not an array of pointers, the syntax gets a little tricky:
int X = 16, Y = 8;
char (*pt)[X][Y] = malloc(X*Y);
Above, pt is a pointer to an X by Y array of chars. Because it's a pointer, accessing its elements requires an asterisk and parentheses, too:
for (int i = 0 ; i != X ; i++) {
for (int j = 0 ; j != Y ; j++) {
(*pt)[i][j] = (char)(i*X+j);
}
}
Of course you need to free the pointer once you are done using the array:
free(pt);

You need to allocate each row of the matrix separately:
unsigned char** index;
index = malloc(X * sizeof(unsigned char*)); // Allocate an array of pointers
for(int i = 0; i < X; i++)
index[i] = malloc(Y * sizeof(unsigned char)) // Allocate each row
Refer also to this answer on malloc pointer casting.

unsigned char **index;
index = (unsigned char**)malloc( X*Y );
is wrong. index is an unsigned char**. You need to malloc two times to get a 2D array. If you want to allocate X rows, each with Y columns, use
unsigned char **index;
index = (unsigned char**)malloc( X * sizeof(unsigned char*) ); //Allocating number of rows
for(int i=0 ; i<X ; i++ )
{
index[i] = (unsigned char*)malloc( Y * sizeof(unsigned char)); // Allocate each column
}
You should check if malloc does not fail. You should also free everything after its use to avoid a memory leak.

After your edit, it appears you are using C++.
In C++, you should prefer std::vector< std::vector< unsigned char > > for dynamic 2d array.
std::vector< std::vector< unsigned char > > index(X, std::vector<unsigned char>(Y));
Now you can use it as index[i][j] and it will be automatically cleaned, so need to free/delete explicitly.
Live demo here
Still if you want to allocate c-compliant arrays in conventional way, use
unsigned char** index;
try {
index = new int*[X];
for(int i = 0; i < X; ++i)
index[i] = new int[Y];
} catch(...) {...}
For delete also you need to delete each element individually.
Old answer
unsigned char **index;
index = malloc(X * sizeof *index);
if(!index) fail();
for(xi = 0; xi < X; ++xi) {
index[xi] = malloc(Y * sizeof **index);
if(!index[xi]) free_and_fail();
}
You first allocate space for X pointers and then in all X pointers you allocate one array.
While freeing the memory, you need to free each row individually:
if(index) for(xi = Y-1; xi >= 0; --xi) { /* xi is signed */
free(index[xi];
}
free(index);
index = NULL;

Related

Creating memory space for multi-dimensional array

I am studying c++ and found this in the book
array_ptr = new int[3][5][4];
This is used to allocate memory to a multi dimensional array using new. It also states while first dimension can be a variable whose value is supplied at runtime, others must be constant.
I tried to run this code
int *p = new int[3][5][6];
But it is showing an error.
Can someone elaborate.
Here is what you want:
int (*p)[5][6] = new int[3][5][6];
Since C++11 you can ask the compiler to decuce the type of p for you:
auto p = new int[3][5][6];
You don't need anything special to delete such array:
delete [] p;
Logic behind the choice of the type is simple:
In this line: int *p = new int[10] you're creating an array of 10 ints and you use pointer to int to store the address.
In general case, if you're allocating an array of N Ts (where N is the size and T is the type), you use pointer to T to store the address.
Same rule can be applied to multidimensional arrays, because they are in fact nested 1D arrays.
When you try to allocate multidimensional array: p = new int[4][5][6], you're creating an array of 4 arrays of 5 arrays of 6 ints. Thus you need a pointer to array of 5 arrays of 6 ints, which is int (*p)[5][6].
In other words, int [3][4][5] can be viewed as 1D array of size 3. It consists of other arrays of type int [4][5]. Each of these arrays has size 4 and consists of other arrays of type int [5], which in turn contain 5 ints.
P.S. Authors of other answers seem to favor using int *** and allocating memory for each nested array separately. Doing so may seem smart, but in fact it's much slower and dangerous (if you mess up your memory management). The only advantage of that trick is that it provides the convenient interface we all used to (p[z][y][x]).
But there is a much better solution: int *p = new int[x_sz * y_sz * z_sz];. You would need to convert 3D indices to 1D index (p[x + x_sz * (y + z * y_sz)] instead of p[z][y][x]) for it to work, but in my opinion it's still more convenient (and definitely faster).
Of course, in real code, you should use std::vector to store such array and write your own wrapper class, which would compute the index automatically.
A 3d array is not the same as a pointer to int, and you can't make them the same.
If you need dynamic allocation, you can use special class std::vector (best choose), std::array, or write next code:
int ***p = new int**[3];
for (int i = 0; i < 3; ++i) {
p[i] = new int*[5];
for (int j = 0; j < 5; ++j) {
p[i][j] = new int[6];
}
}
In order to create dynamic 3d array you have to use pointer to pointer to pointer)
const int xSize = 3;
const int ySize = 5;
const int zSize = 4;
int*** p = nullptr;
// creating array of pointers to pointers
p = new int** [xSize]
// for each pointer to pointers, create array of pointers
for( int i = 0; i < xSize; ++i )
p[ i ] = new int* [ySize];
// now we have 2d array of pointers, for each of them allocate array
for( int i = 0; i < xSize; ++i )
for( int j = 0; j < ySize; ++j )
p[ i ][ j ] = new int [zSize];
But is much more better to use vectors
vector<vector<vector<int> > > v3d;
v3d.resize( 3 );
for( int i = 0; i < xSize; ++i )
v3d[ i ].resize( ySize );
for( int i = 0; i < xSize; ++i )
for( int j = 0; j < ySize; ++j )
v3d[ i ][ j ].resize( zSize );

Swap a pointer to the allocated memory with a common pointer

I want to swap two lines in a matrix. My matrix is an allocated solid block of memory.
I have an array of pointers that point to the rows of the matrix. The first pointer points to this big allocated block. And other pointers point to different parts or this block.
If I swap any two rows, except the first, it's OK. But I have problems with the first row.
I guess that's because the pointer to the first row is different from other. But what is the main difference?
#include <iostream>
int** allocateMatrix(int rows, int cols) {
// allocating array of pointers (rows)
int** matrix = new int*[rows];
// allocating one solid block for the whole matrix
matrix[0] = new int[rows*cols];
// setting the pointers for rows
for ( int i = 1; i < rows; ++i ) {
matrix[i] = matrix[i-1] + cols;
}
// fill the matrix with consecutive numbers
int k = 1;
for ( int i = 0; i < rows; ++i ) {
for ( int j = 0; j < cols; ++j ) {
matrix[i][j] = k;
k += 1;
}
}
return matrix;
}
void freeMatrix(int** matrix) {
delete[] matrix[0];
delete[] matrix;
}
int main() {
int n = 3;
int m = 3;
int** matrix = allocateMatrix(n, m);
// swap the first and the second line
int* tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
// print matrix (it is printing ok)
for ( int i = 0; i < n; ++i ) {
for ( int j = 0; j < m; ++j ) {
std::cout << matrix[i][j] << ' ';
}
std::cout << std::endl;
}
// problem is here
freeMatrix(matrix);
return 0;
}
The main difference is that the first pointer was returned by new[]. Deleting that pointer will deallocate the entire memory block, but deleting any other pointer in the array will have undefined behaviour.
You could store the pointer which you get from new[] separately, and have a duplicate "weak" pointer to the first row that you keep in the array of row pointers.
Your code won't work if you swap first (0) and second (1) rows because you are using matrix[0] to delete the memory allocation.
You need to somehow "keep" the original allocation, e.g.
int *origalloc;
...
origalloc = matrix[0] = new int[rows*cols];
...
delete[] origalloc; // Instead of malloc[0];
What you pass to delete or delete [] must the the same pointer-value as what you get back from the new or new []. Anything else is undefined behaviour.

2D pointer pointing 2D array in C

How to make a 2d pointer like **check point a 2d array like
mycheck[][]?
How to convert a 1d like check[16], to 2d array like mycheck[4][4]?
My attempt
float (*mycheck)[4] = (float (*)[4]) check;
But if second time I want to use mycheck again for some other 1d array, how can I do? My attempt:
float (*mycheck)[4] = (float (*)[4]) other1darray;
this will definitely give a re-declaration error.
The answer to the first question is that you cannot do that. All you can do is allocate some memory and copy the data over.
The answer to the second question is very simple
mycheck = (float (*)[4]) other1darray;
You only have to declare variables once, after that just use the variable name.
Array a[] decays to a pointer to the first element when you drop the []. This does not happen recursively, in other words, it doesn't work for a[][].
Secondly, you can't assign arrays in C. You can ONLY initialize them. You will have to set each member yourself.
You can create a 2D array in C like this.
Use a typedef to make it easier.
typedef int **matrix;
matrix create2Darray(int row, int col)
{
int idx;
matrix m = malloc(row * sizeof(int*));
for (idx = 0; idx < row; ++idx)
{
m[idx] = malloc(col * sizeof(int));
}
return m;
}
And then call this in another function;
matrix check = create2Darray(2, 2);
To assign a 1D array to a 2D array you can assign the pointers to the right position in the array. An example below. It also show how to create a 2D array dynamically, but I commented it out, since it is not needed for the example.
#include <stdio.h>
#include <stdlib.h>
int main()
{
float **matrix;
float *array;
array = (float *) malloc(16 * sizeof(float));
for (size_t idx = 0; idx != 16; ++idx)
{
array[idx] = idx;
}
matrix = (float **) malloc(4 * sizeof(float *));
for (size_t idx = 0; idx != 4; ++idx)
{
// matrix[idx] = malloc(4 * sizeof(int));
matrix[idx] = &array[idx * 4];
}
for (size_t row = 0; row != 4; ++row)
{
for (size_t col = 0; col != 4; ++col)
{
printf("%.1f ", matrix[row][col]);
}
printf("\n");
}
}
Note: this makes the 1D array and 2D array point to the same memory. If you change something in the 1D it also changes in the 2D and vice-versa. If you don't want this, first copy the array.

Allocate a multidimensional array without recursion

Suppose I have an arbitrary size array of integer values that specify the number of elements for each dimension (level) of the array to be allocated, how do I allocate the array without resorting to recursion? It's preferable to do it without recursion to avoid stack overflow.
So, for example, how to complete a function like this:
template <typename Type>
void* allocMulti (int numDim, int* numElementsPerDim)
{
// 'Type' if one-dimensional, should be 'void*' otherwise
void* multiArray = new Type[numElementsPerDim[0]];
// ...
return multiArray;
}
I'm looking for a general algorithm that would cover languages without direct memory access.
If the array is actually a matrix (e.g. length AxB and not a list of arrays of different lengths), then you could allocate a single array of length A*B instead of an array of length A where each position is a pointer to an array of length B.
This could also improve performance, as the memory is continuous (less paging).
You would have to access each cells using a[y * B + x] instead of a[y][x] though (assuming dim(a,0) = A and dim(a,1) = B.
My C++ my be a bit rusty, however, I believe this sort of approach may work:
T* AllocateMatrix(int dims, int[] dimLengths)
{
// Assert dims >= 1
int length = dims[0];
for (int d = 1; d < dims; d++)
length *= dims[d];
return new T[length];
}
*T AccessMatrix(T* matrix, int dims, int[] dimLengths, int[] pos)
{
// Assert dims >= 1
int p = pos[0];
for (int d = 1; d < dims; d++)
{
p = p * dimLengths[d] + pos[d];
}
return &matrix[p];
}
Here's an approach: Allocate the data values as a block, then all the rows of (int *) as a block, then the rows of (int **) as a block, etc.
a) Allocate all the data values as a block. If you have nDim dimensions in the array elementsPerDim, there are prod = product(elementsPerDim, nDim) data values (which you can easily calculate), so you need to allocate:
int prod = product(elementsPerDim, nDim);
int * intblock = calloc(prod, sizeof(int));
b) Allocate all the (int*). Their number is equal to the product of all the dimensions except the last one, so you can simply call your product() function with length nDim-1. So there are product(elementsPerDim, nDim-1) such values, each of size sizeof (int*). Let's allocate them:
int npointers = product(elementsPerDim, nDim-1);
int ** ptrblock = calloc(npointers, sizeof (int *));
Now you must initialize them to point into your block from the previous step. Each pointer gets a non-overlapping block of elementsPerDim[nDim-2] ints, like this:
int rowlength = elementsPerDim[nDim-2];
for (int i=0; i < npointers; i++)
ptrblock[i] = & intblock[i * rowlength]; /* a.k.a. intblock + i*rowlength */
c) Iterate step b backwards until you run out of dimensions. I.e., follow up step (b) with this loop:
void ** prev_block = (void **) ptrblock;
void ** curblock;
for (int d = nDim-2; d > 0; d--) {
int npointers = product(elementsPerDim, d);
curblock = calloc(npointers, sizeof (void **));
int rowlength = elementsPerDim[d-1];
for (int i=0; i < npointers; i++)
curblock[i] = & prev_block[i * rowlength];
prev_block = curblock; /* get ready for the next round */
}
When you're done, curblock will be an array of pointers pointing into the block of second-level pointers, and so on down to the block of ints. You can use normal array notation to dereference them:
ptrblock[3][2][15], etc.
I may have gotten an index off by one somewhere, but this should be the algorithm. You'll notice this is in C, and uses void ** instead of stacking the number of dereferences. You did say you were interested in the algorithm, not in type golf... (It should work as long as all pointers have the same size on your machine.)

Two-dimensional array initialization

CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;