Defining 2D irregular array with malloc - arrays

I have this practice question:
Define a 2D irregular array with malloc of ints where the out dim = 4 and the inner = 10,11,12,13. (hint: use a for loop)
So, I realized that I could write a 2D irregular array with malloc of ints like this:
int (*array)[20] = malloc((sizeof *array) * 10);
That would be for a 10x20 array I believe with amlloc.
I'm just not sure how I would use a for loop to change the inner dimension from 10 to 11 to 12 to 13. Any help would be appreciated thanks!
int j;
for (int k = 0; k < 4; k++ )
{
for ( j = 10; j < 14; j++ )
{
int (*array)[4] = malloc((sizeof *array) * j)
}
}
By the way, is that close to correct?

Does this help?
If so, please edit http://en.wikibooks.org/wiki/C_Programming/Common_practices#Dynamic_multidimensional_arrays to make it easier for the next student to understand.
#include <stdio.h>
#include <stdlib.h>
const int rows = 20;
int main(void) {
int **some_data;
// first, allocate a (column) Iliffe vector.
some_data = malloc( (sizeof(*some_data)) * rows);
int i=0;
for(i = 0; i < rows; i++){
// next, allocate each row.
// For no good reason, make each row a different size.
int columns = i+10;
some_data[i] = malloc( (sizeof(**some_data)) * columns);
};
some_data[3][13] = 9;
printf( "%d\n", some_data[3][13]);
return 0;
}
If you are viewing this through one of the locked-down systems that seem to be inexplicably popular nowadays, you may find it convenient to run the above code in some online C compilers such as http://ideone.com/ or http://codepad.org/ or http://www.compileonline.com/compile_c_online.php .

Related

Quadruple pointer and memcpy() in C

First of all, I know triple and quadruple pointers are bad practice and are ugly, that's not the point of this question, I'm trying to understand how they work. I'm aware using a struct would be much better.
I am trying to write a function that does some memory operations using memmove() and memcpy() on triple and double pointers that are passed-by-reference (or the C version of that). My memmove() works fine, but the memcpy() yields a SIGSEGV. Here's a minimal example
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define UNDO_DEPTH 25
void boardSave(int ***board, int game_sz, int ****history) {
// Shift history to the right
memmove(*history + 1, *history, (UNDO_DEPTH - 1) * sizeof(**history));
// Copy board into history
for (int row = 0; row < game_sz; ++row) {
memcpy((*history)[0][row], (*board)[row], game_sz * sizeof((**board)[row]));
}
}
int main(){
// Game
int game_sz = 5;
// Allocate array for the board
int **board = calloc(game_sz, sizeof(int *));
for (int i = 0; i < game_sz; ++i) board[i] = calloc(game_sz, sizeof(int));
// Allocate array for the history
int ***history = calloc(UNDO_DEPTH, sizeof(int **));
for (int i = 0; i < UNDO_DEPTH; ++i) {
history[i] = calloc(game_sz, sizeof(int *));
for (int j = 0; j < game_sz; ++j) {
history[i][j] = calloc(game_sz, sizeof(int));
}
}
board[0][0] = 1;
boardSave(&board, game_sz, &history);
}
The objective of boardSave() here is to copy board onto history[0]. What am I doing wrong? Why is this causing a segmentation fault?
In the main function you make history point to an array of UNDO_DEPTH pointers, each of which points to a board that has its own allocation. Since memmove moves a contiguous memory blocks, you cannot move the content of all those boards with memmove.
However, you could move down the pointers in that history array, leaving the board allocations untouched.
Just doing a single memmove would require you to free memory of the last board shuffled off, and allocate memory for the new board. But you could recycle that memory by moving the last pointer to the start instead.
Now, there is no need to pass the addresses of board and history to the boardSave function. It just makes your code more complicated for no reason. The simpler version would be:
void boardSave(int **board, int game_sz, int ***history)
{
// Save the last board
int ** last_board = history[UNDO_DEPTH - 1];
// Shuffle down all the boards
memmove( &history[1], &history[0], (UNDO_DEPTH - 1) * sizeof history[0] );
// Put the old last board on the front
history[0] = last_board;
// Copy board into front of history
copy_board( game_sz, history[0], board );
}
// Put a prototype for this earlier in the code. I think it makes
// the boardSave function clearer to use a separate function for this
// operation, which you might end up using on its own anyway.
//
void copy_board( int game_sz, int **dest, int **src )
{
for(int row = 0; row < game_sz; ++row)
memcpy(dest[row], src[row], game_sz * sizeof dest[0][0]);
}
Personally I'd prefer to avoid memcpy in the last function and just write a simple loop that is obviously correct. The compiler will optimize it to use memcpy anyway, but without the possibility of making an error in the memcpy parameters:
for(int row = 0; row < game_sz; ++row)
for (int col = 0; col < game_sz; ++col)
dest[row][col] = src[row][col];
Similar comments would apply to the use of memmove actually.
I would also make some use of const in the function signatures, so that a compiler error is generated if I accidentally switched the "dest" and "src" arguments. But I left that out at this stage for simplicitly.
In main the call would now be:
boardSave(board, game_sz, history);
If you reeeeealy want to pass pointers for practice then I would "de-point" them at the start of the function:
void complicated_boardSave(int ***p_board, int game_sz, int ****p_history)
{
int *** history = *p_history;
int ** board = *p_board;
// rest of code the same
I understand you want to challenge pointers.
I wanted provide a solution that utilizes single pointer.
As a matter of fact, you don't need to use a pointer at all.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int game_sz = 5;
#define UNDO_DEPTH 25
void boardSave(int *board[game_sz], int game_sz, int *history[UNDO_DEPTH]
[game_sz])
{
int i,j,k;
for( i = 0; i < UNDO_DEPTH - 1; i++)
for( j = 0; j < game_sz; j ++ )
for( k = 0; j < game_sz; j ++ )
history[i+1][j][k] = history[i][j][k];
for( i = 0; i < game_sz - 1; i++)
for( j = 0; j < game_sz; j++ )
history[0][i][j] = board[i][j];
}
int
main(void)
{
int *board[game_sz];
int *history[UNDO_DEPTH][game_sz];
int i, j;
for (i = 0; i < game_sz; ++i)
board[i] = calloc(game_sz, sizeof(int));
board[0][0] = 1;
// Allocate array for the history
for ( i = 0; i < UNDO_DEPTH; ++i)
for ( j = 0; j < game_sz; ++j)
history[i][j] = calloc(game_sz, sizeof(int));
boardSave( board, game_sz, history);
return 0;
}

Make a 2D array in C with a variable

I have an integer variable x that I need to use to make two 2D arrays but I get an error of "cannot allocate an array of constant size 0". After doing some research I apparently need to use malloc but I have no idea how to apply it to my currently situation.
My two arrays I need:
int firMat[x][5];
int secMat[5][x];
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int x = 2;
int **firMat;//int firMat[x][5];
int **secMat;//secMat[5][x];
int i;
firMat = malloc(x * sizeof(int*));
for(i = 0; i< x; ++i)
firMat[i] = malloc(5 * sizeof(int));
secMat = malloc(5 * sizeof(int*));
for(i = 0; i< 5; ++i)
secMat[i] = malloc(x * sizeof(int));
//do stuff E.g. fir[2][1] = 21;
//release E.g.
//for(i = 0; i< x; ++i)
// free(firMat[i]);
//free(firMat);
return 0;
}
If you're using C99, this will work. It will create a "variable-length array", sadly VLAs have been reduced to "optional" in C11.
To use malloc for this, typically I'd abandon the double-array notation, and treat the memory as a flat one-dimensional array, then array[i][j] becomes ptr[ i*cols + j ].
Try to initialize x like in the example below
#define x 2 //outside the function
and then use x like this
int firMat[x][5];
int secMat[5][x];

How to malloc 2D arrays? [duplicate]

This question already has answers here:
Allocating 2-D array in C
(2 answers)
Closed 8 years ago.
I need to create a two dimensional array. Presently I created it as
int a[100][100]
but I need to allocate the memory dynamically using malloc in C language. I used the code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n=6, m=5, i, j;
int **a = malloc(n * sizeof(int *));
for(i = 0; i < m; i++)
a[i] = malloc(m * sizeof(int));
for( i = 1; i <= n; i++ )
{
for( j = 1; j <= m; j++ )
{
scanf("%d %d",&a[i][j]);
}
}
return 0;
}
but now while inputting the elements into the array it shows SEGMENTATION ERROR.
You say in the comments that n is the number of rows. So you need to allocate n rows each of length m. Therefore, the second for loop condition should be i < n. Also, you should check the return value of malloc for NULL in case it fails to allocate memory. I suggest the following change -
long long **a = malloc(n * sizeof(*a));
for(i = 0; i < n; i++)
a[i] = malloc(m * sizeof(*a[i]));
Please note that a multi-dimensional array is not a fundamentally new type. It's simply an array of elements where each element itself is an array (for a 2D array), an array of arrays (for a 3D) array and so on. If you are using C99, you can allocate your array cleanly and succinctly as
int nrow = 4; // number of rows
int ncol = 8; // number of columns
// define arr to be a pointer to an array of ncol ints, i.e.,
// arr is a pointer to an object of type (int[ncol])
int (*arr)[ncol] = malloc(sizeof(int[nrow][ncol]));
// check the result of malloc for NULL
if(arr == NULL) {
printf("malloc failed to allocate memory\n");
// handle it
}
// do stuff with arr
for(int i = 0; i < nrow; i++)
for(int j = 0; j < ncol; j++)
arr[i][j] = i + j;
// after you are done with arr
free(arr);
You should also go through this - How do I work with dynamic multi-dimensional arrays in C?
You have three errors: The first is that you allocate only 5 secondary arrays, but in the input you loop over 6 of them.
The second problem is that array indices are zero-based, i.e. the index start at zero and goes to the size minus one.
The third problem is that you scan for two numbers (why?), but you provide only one destination pointer to scanf.
you just need
long *a = malloc(100*100*sizeof(long));
if you want one single big block of memory.
if you want an array of long* pointers and then each array to be in a separate block of memory go like this:
long **a = malloc(100*sizeof(long*));
for (i=0; i<100; i++) {
a[i] = malloc(100*sizeof(long));
}
This creates 1 array of long* pointers, and then 1 array of 100 longs of each pointer, but I'm not sure now if you say a[10][15] for example if it would calculate position of the element as if its a continuous block. Check that out. :)
If you have C99 use Variable Length Array
#include <stdio.h>
#include <stdlib.h>
int main(void) {
unsigned rows, cols;
printf("Enter rows and columns: ");
fflush(stdout);
scanf("%u%u", &rows, &cols);
int (*a)[cols]; // pointer to VLA
a = malloc(rows * cols * sizeof a[0][0]);
if (a) {
for (unsigned r = 0; r < rows; r++) {
for (unsigned c = 0; c < cols; c++) {
a[r][c] = r*c;
}
}
printf("the element at [4, 2] is %d\n", a[4][2]);
free(a);
}
return 0;
}
Otherwise, you need to calculate the indexing manually.
There are many problems in your code
First, you need long long a[100][100] but you only allocate enough space for ints
a[i] = malloc(m * sizeof(int));
You're also accessing arrays out-of-bound. Indexes start from 0 to array_length-1.
Another problem is that you scanf 2 int values but only provide the address for 1.
scanf("%d %d",&a[i][j]);
You can allocate a 100-element array of pointers, each points to an array of another 100-element array but that's not good because it takes time to do 100 mallocs, and the resulting memory most probably isn't contiguous, which makes it cache unfriendly. There are also a small memory overhead too because the memory allocator must round it up to the nearest block size and this is most probably powers of 2, which may be large as you allocate more and more elements in the first dimension.
You should declare a 1D array of size 100*100 instead. This will be much faster and improve cache coherency. To get the element at a[i][j] just do a[i*WIDTH + j]
long long* a = malloc(WIDTH*HEIGHT*sizeof(long long));
for (i = 0; i < WIDTH*HEIGHT; i++)
{
scanf("%lld ",&a[i]);
}
for (i = 0; i < HEIGHT; i++)
{
for (j = 0; j < WIDTH; j++)
{
printf("%lld ", a[i*WIDTH + j]);
}
printf("\n");
}

Erros in dynamically allocated array in C

I am trying to dynamically allocate a 2D array, put some values, and print output. However it seems that I am making mistake in getting input to program in atoi() function.
Basically when we assign a static 2D array, we declare it as say int a [3][3]. So 3*3 units if int, that much memory gets allocated. Is same thing holds for allocating dynamic array as well?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(int arg,char* argv)
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
int (*arr)[col] = malloc(sizeof (*arr)*rows);
int *ptr = &(arr[0][0]);
int ct=1;
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
arr[i][j]=ct;
ct++;
}
}
printf("printing array \n");
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
free(arr);
return (0);
}
Program crashes in runtime. Can someone comment?
Try to change the third line to:
int main(int arg,char **argv)
The common method to use dynamic matrices is to use a pointer to pointer to something, and then allocate both "dimensions" dynamically:
int **arr = malloc(sizeof(*arr) * rows);
for (int i = 0; i < rows; ++i)
arr[i] = malloc(sizeof(**arr) * col);
Remember that to free the matrix, you have to free all "rows" in a loop first.
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
You are defining rows and col twice.... that would never work!
With traditional C, you can only have the array[][] structure for multiple dimension arrays work with compile time constant values. Otherwise, the pointer arithmetic is not correct.
For dynamically sized multi dimensional arrays (those where rows and cols are determined at runtime), you need to do additional pointer arithmetic of this type:
int *a;
int rows=3;
int cols=4;
a = malloc(rows * cols * sizeof(int));
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
a[i*rows + j] = 1;
free(a);
Alternatively, you can use double indirection and have an array of pointers each pointing to a one dimensional array.
If you are using GCC or any C99 compiler, dynamic calculation of multiple dimension arrays is simplified by using variable length arrays:
// This is your code -- simplified
#include <stdio.h>
int main(int argc, const char * argv[])
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
// you can have a rough test of sanity by comparing rows * col * sizeof(int) < SIZE_MAX
int arr[rows][col]; // note the dynamic sizing of arr here
int ct=1;
for (int i=0;i<rows;i++)
for(int j=0;j<col;j++)
arr[i][j]=ct++;
printf("printing array \n");
for (int i=0;i<rows;i++)
{
for(int j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
return 0;
} // arr automatically freed off the stack
With a variable length array ("VLA"), dynamic multiple dimension arrays in C become far easier.
Compare:
void f1(int m, int n)
{
// dynamically declare an array of floats n by m size and fill with 1.0
float *a;
a = malloc(m * n * sizeof(float));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
a[i*n + j] = 1.0;
free(a);
}
With VLA you can write to do the same:
void f2(int m, int n)
{
// Use VLA to dynamically declare an array of floats n by m size and fill with 1.0
float a[m][n];
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
a[i][j] = 1.0;
}
Be aware that unlike malloc / free VLA's handling of requesting a size larger than what is available on the stack is not as easily detected as using malloc and testing for a NULL pointer. VLA's are essentially automatic variables and have similar ease and restrictions.
VLA's are better used for smaller data structures that would be on the stack anyway. Use the more robust malloc / free with appropriate detection of failure for larger data structures.
If you are not using a fairly recent vintage C compiler that supports C99 -- time to get one.

How do we allocate a 2-D array using One malloc statement

I have been asked in an interview how do i allocate a 2-D array and below was my solution to it.
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}
I thought I had done a good job but then he asked me to do it using one malloc() statement not two. I don't have any idea how to achieve it.
Can anyone suggest me some idea to do it in single malloc()?
Just compute the total amount of memory needed for both nrows row-pointers, and the actual data, add it all up, and do a single call:
int **array = malloc(nrows * sizeof *array + (nrows * (ncolumns * sizeof **array));
If you think this looks too complex, you can split it up and make it a bit self-documenting by naming the different terms of the size expression:
int **array; /* Declare this first so we can use it with sizeof. */
const size_t row_pointers_bytes = nrows * sizeof *array;
const size_t row_elements_bytes = ncolumns * sizeof **array;
array = malloc(row_pointers_bytes + nrows * row_elements_bytes);
You then need to go through and initialize the row pointers so that each row's pointer points at the first element for that particular row:
size_t i;
int * const data = array + nrows;
for(i = 0; i < nrows; i++)
array[i] = data + i * ncolumns;
Note that the resulting structure is subtly different from what you get if you do e.g. int array[nrows][ncolumns], because we have explicit row pointers, meaning that for an array allocated like this, there's no real requirement that all rows have the same number of columns.
It also means that an access like array[2][3] does something distinct from a similar-looking access into an actual 2d array. In this case, the innermost access happens first, and array[2] reads out a pointer from the 3rd element in array. That pointer is then treatet as the base of a (column) array, into which we index to get the fourth element.
In contrast, for something like
int array2[4][3];
which is a "packed" proper 2d array taking up just 12 integers' worth of space, an access like array[3][2] simply breaks down to adding an offset to the base address to get at the element.
int **array = malloc (nrows * sizeof(int *) + (nrows * (ncolumns * sizeof(int)));
This works because in C, arrays are just all the elements one after another as a bunch of bytes. There is no metadata or anything. malloc() does not know whether it is allocating for use as chars, ints or lines in an array.
Then, you have to initialize:
int *offs = &array[nrows]; /* same as int *offs = array + nrows; */
for (i = 0; i < nrows; i++, offs += ncolumns) {
array[i] = offs;
}
Here's another approach.
If you know the number of columns at compile time, you can do something like this:
#define COLS ... // integer value > 0
...
size_t rows;
int (*arr)[COLS];
... // get number of rows
arr = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < COLS; j++)
arr[i][j] = ...;
}
If you're working in C99, you can use a pointer to a VLA:
size_t rows, cols;
... // get rows and cols
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
arr[i][j] = ...;
}
How do we allocate a 2-D array using One malloc statement (?)
No answers, so far, allocate memory for a true 2D array.
int **array is a pointer to pointer to int. array is not a pointer to a 2D array.
int a[2][3] is an example of a true 2D array or array 2 of array 3 of int
To allocate memory for a true 2D array, with C99, use malloc() and save to a pointer to a variable-length array (VLA)
// Simply allocate and initialize in one line of code
int (*c)[nrows][ncolumns] = malloc(sizeof *c);
if (c == NULL) {
fprintf(stderr, "out of memory\n");
return;
}
// Use c
(*c)[1][2] = rand();
...
free(c);
Without VLA support, if the dimensions are constants, code can use
#define NROW 4
#define NCOL 5
int (*d)[NROW][NCOL] = malloc(sizeof *d);
You should be able to do this with (bit ugly with all the casting though):
int** array;
size_t pitch, ptrs, i;
char* base;
pitch = rows * sizeof(int);
ptrs = sizeof(int*) * rows;
array = (int**)malloc((columns * pitch) + ptrs);
base = (char*)array + ptrs;
for(i = 0; i < rows; i++)
{
array[i] = (int*)(base + (pitch * i));
}
I'm not a fan of this "array of pointers to array" to solve the multi dimension array paradigm. Always favored a single dimension array, at access the element with array[ row * cols + col]? No problems encapsulating everything in a class, and implementing a 'at' method.
If you insist on accessing the members of the array with this notation: Matrix[i][j], you can do a little C++ magic. #John solution tries to do it this way, but he requires the number of column to be known at compile time. With some C++ and overriding the operator[], you can get this completely:
class Row
{
private:
int* _p;
public:
Row( int* p ) { _p = p; }
int& operator[](int col) { return _p[col]; }
};
class Matrix
{
private:
int* _p;
int _cols;
public:
Matrix( int rows, int cols ) { _cols=cols; _p = (int*)malloc(rows*cols ); }
Row operator[](int row) { return _p + row*_cols; }
};
So now, you can use the Matrix object, for example to create a multiplication table:
Matrix mtrx(rows, cols);
for( i=0; i<rows; ++i ) {
for( j=0; j<rows; ++j ) {
mtrx[i][j] = i*j;
}
}
You should now that the optimizer is doing the right thing and there is no call function or any other kind of overhead. No constructor is called. As long as you don't move the Matrix between function, even the _cols variable isn't created. The statement mtrx[i][j] basically does mtrx[i*cols+j].
It can be done as follows:
#define NUM_ROWS 10
#define NUM_COLS 10
int main(int argc, char **argv)
{
char (*p)[NUM_COLS] = NULL;
p = malloc(NUM_ROWS * NUM_COLS);
memset(p, 81, NUM_ROWS * NUM_COLS);
p[2][3] = 'a';
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 0; j < NUM_COLS; j++) {
printf("%c\t", p[i][j]);
}
printf("\n");
}
} // end of main
You can allocate (row*column) * sizeof(int) bytes of memory using malloc.
Here is a code snippet to demonstrate.
int row = 3, col = 4;
int *arr = (int *)malloc(row * col * sizeof(int));
int i, j, count = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
*(arr + i*col + j) = ++count; //row major memory layout
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
printf("%d ", *(arr + i*col + j));

Resources