I have an 2d array . The 1st dimension has fixed size and i dynamicly create the 2nd dimension. e.g
int **arr;
*arr=( int * ) malloc ( X * sizeof ( int )) // X is input from user
What i want to do is create 2nd dimension and write value at the end of it.
For example i create 2nd dimension for arr[0] using
arr[0]=( int * ) malloc ( 2 * sizeof ( int ))
and then i want to write value in this 2nd dimension but without knowing the index. A lot of programming languages has method array.push which push item at the end of the array without knowing index or length of the array. How can i achieve such result in C? Is it possible?
Short answer: NO. You need to know the last index of the memory allocated via a pointer. There is no way of knowing the memory allocated for a pointer, so you need to know the last index for each column. Applying sizeof on a pointer gives you the memory occupied by a pointer (most often 4 or 8 bytes), and not the memory allocated by the pointer. This is a fundamental difference between pointers and arrays. They are not the same, although arrays decay to pointers when passed as arguments to functions.
Assuming your 2D array has NROWS and NCOLS, what you need is:
arr = malloc(NROWS * sizeof(int*)); // allocate memory for first dim, i.e. for rows
then allocate memory for each row, e.g. for the 5-th row:
arr[5] = malloc(NCOLS * sizeof(int)); // allocate NCOLS for the 5-th row
In general you allocate memory for the second dimension in a loop:
for(size_t i = 0 ; i < NCOLS; ++i)
free(arr[i]);
Then don't forget to release the memory at the end, in reverse order:
for(size_t i = 0; i < NCOLS; ++i)
free(arr[i]); // release memory for cols
free(arr); // release memory for rows
However, I recommend you use a 1D array instead (in case the dimension is the same for each column), and map from 1D to 2D and viceversa. It's better this way since the data is stored contiguously (better data locality) and there are no cache misses.
If you switch to C++, then you can use the standard container std::vector, which "knows" its indexes, and you can add at the end via std::vector::push_back or std::vector::emplace_back member functions.
Related
Three questions in 1.
If I have a 2-D array -
int array_name[num_rows][num_columns]
So it consists of num_rows arrays -each of which is an array of size = num_columns. Its equivalent representation using an array of pointers is-
int* array_name[num_rows]
-so the index given by [num_rows] still shows the number of 1-D arrays - somewhere using malloc we can then specify the size of each of the 1-D arrays as num_columns. Is that right? I saw some texts telling
int* array_name[num_columns]
will the indices not get switched in this case ?
For a ID array I specify size dynamically as-
int *p;
p = (int*) malloc (size * sizeof(int))
For 2 D arrays do I specify the size of entire 2-D array or of one 1-D array in malloc -
int*p [row_count];
p = (int*) malloc (row_count * column_count * sizeof(int))
or
p = (int*) malloc (column_count * sizeof(int))
I think it should be the second since p is a pointer to a 1-D array and p+1 is a pointer to a 1-D array etc. Please clarify.
For ques 2 - what if p was defined as -
int **p; rather than
int * p[row_count]
How will the malloc be used then? I think it should be -
p = (int*) malloc (row_count * column_count * sizeof(int))
Please correct, confirm, improve.
Declaring :
int *array_name[num_rows];
or :
int *array_name[num_columns];
is the same thing. Only the name changes, but your variable is still referring to rows because C is a row major so you should name it row.
Here is how to allocate a 2D array :
int (*p)[column] = malloc (sizeof(int[row][column]);
An int ** can be allocated whereas int [][] is a temporary array defined only in the scope of your function.
Don't forget that a semicolon is needed at the end of nearly every line.
You should read this page for a more complete explanation of the subject
(and 2.)
If I have a 2-D array
int array_name[num_rows][num_columns];
So it consists of num_rows arrays -each of which is an array of size = num_columns.
If both num_rows and num_columns are known at compile time, that line declares an array of num_rows arrays of num_columns ints, which, yes, is commonly referred as a 2D array of int.
Since C99 (and optionally in C11) you can use two variables unknown at compile time and end up declaring a Variable-Length Array, instead.
Its equivalent representation using an array of pointers is
int* array_name[num_rows];
So the index given by [num_rows] still shows the number of 1-D arrays - somewhere using malloc we can then specify the size of each of the 1-D arrays as num_columns. Is that right?
Technically, now array_name is declared as an array of num_rows pointers to int, not arrays. To "complete" the "2D array", one should traverse the array and allocate memory for each row. Note that the rows could have different sizes.
Using this form:
int (*array_name)[num_columns];
// ^ ^ note the parenthesis
array_name = malloc(num_rows * sizeof *array_name);
Here, array_name is declared as a pointer to an array of num_columns ints and then the desired number of rows is allocated.
3.
what if p was defined as int **p;
The other answers show how to allocate memory in this case, but while it is widely used, it isn't always the best solution. See e.g.:
Correctly allocating multi-dimensional arrays
Does anyone know what the third line "Free(array)" does? array here is just the address of the first element of array(in other words, a pointer to the first element in the array of int * right)? Why do we need the third line to free the "columns" of the 2D array? I basically memorized/understand that a is a pointer to means a holds the address of ____. Is this phrase correct?
For example: int **a; int * b; int c; b = &c = 4;
a = &b; This is correct right? Thankyou!!!
Also, in general, double pointers are basically dynamically allocated arrays right?
"Finally, when it comes time to free one of these dynamically allocated multidimensional ``arrays,'' we must remember to free each of the chunks of memory that we've allocated. (Just freeing the top-level pointer, array, wouldn't cut it; if we did, all the second-level pointers would be lost but not freed, and would waste memory.) Here's what the code might look like:" http://www.eskimo.com/~scs/cclass/int/sx9b.html
for(i = 0; i < nrows; i++)
free(array[i]);
free(array);
Why do we need the third line to free the "columns" of the 2D array?
The number of deallocations should match up with the number of allocations.
If you look at the code at the start of the document:
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++) {
array[i] = malloc(ncolumns * sizeof(int));
}
you'll see that there is one malloc() for the array itself and one malloc() for each row.
The code that frees this is basically the same in reverse.
Also, in general, double pointers are basically dynamically allocated arrays right?
Not necessarily. Dynamically allocated arrays is one use for double pointers, but it's far from the only use.
Calls to malloc allocate memory on the heap, equal to the number of bytes specified by its argument, and returns the address of this block of memory. Your '2D array' is really a 1D array of int addresses, each pointing to a chunk of memory allocated by malloc. You need to free each of these chunks when you are done, making it available for others to use. But your 1D array is really just another malloc'd chunk of memory to hold these malloc'd addresses, and that needs to be freed also.
Also, when you use printf("%s", array) where array is an char *, the compiler sees the array as the address of array[0] but prints it right? I'm just curious if I'm understanding it right.
Yes, %s tells printf to go to whatever address you give it (an address of a char, aka a char*, let's say), and start reading and displaying whatever is in memory at that address, one character at a time until it finds a 'NULL character'. So in the case of a string, that is the expected behavior, since a string is just an array of chars, followed by the '\0' char.
I want to allot memory dynamically for a 2D array.
Is there any difference between these two ?
1)
array = (int**)malloc(size * sizeof(int*));
for (i = 0; i < size; i++) {
array[i] = (int *) malloc(size * sizeof(int));
}
2)
array = (int**)malloc(size *size* sizeof(int));
If yes, what is better to use and why ?
In the first case
array = (int**)malloc(size * sizeof(int*));
for (i = 0; i < size; i++) {
array[i] = (int *) malloc(size * sizeof(int));
}
you are allocating size extents of the size equal to size * sizeof( int ) That is you are allocating size one-dimensional arrays. Accordingly you are allocating size pointers that point to first elements of these one-dimensional arrays.
In the second case expression
(int**)malloc(size *size* sizeof(int))
means allocation of an extent of size * size of objects of type int and the returned pointer is interpretated as int **. So this expression has no sense independing on what is placed in the left side of the assignment. take into account that the size of pointer can be greater than the size of int.
You could write instead
int ( *array )[size] = ( int (*)[size] )malloc(size *size* sizeof(int));
In this case you are indeed allocating a two dimensional array provided that size is a constant expression.
Those two solutions are very different. The first will give you a vector of pointers to vectors. The second will give you a vector of the requested size. It all depends on your use case. Which do you want?
When it comes to releasing the memory, the first can only be freed by calling free for each pointer in the vector and then a final free on the vector itself. The second can be freed with a single call. Don't have that be your deciding reason to use one or the other. It all depends on your use case.
What is the type of the object you want to allocate? Is it an int **, an int *[] or an int[][]?
I want to allot memory dynamically for a 2 dimensional array.
Then just do
int (*arr)[size] = malloc(size * sizeof *arr);
Is there any difference between these two ?
Yes, they are wrong because of different errors. The first attempt does not allocate a 2D array, it allocates an array of pointers and then a bunch of arrays of ints. Hence the result will not necessarily be contiguous in memory (and anyway, a pointer-to-pointer is not the same thing as a two-dimensional array.)
The second piece of code does allocate a contiguous block of memory, but then you are treating it as if it was a pointer-to-pointer, which is still not the same thing.
Oh, and actually, both snippets have a common error: the act of casting the return value of malloc().
int **arrayPtr;
arrayPtr = malloc(sizeof(int) * rows *cols + sizeof(int *) * rows);
In the above code, we are trying to allocate a 2D array in a single malloc call.
malloc takes a number of bytes and allocates memory for that many bytes,
but in the above case, how does malloc know that first it has to allocate a array of pointers, each of which pointer points to a one-dimensional array?
How does malloc work internally in this particular case?
2D arrays aren't the same as arrays of pointers to arrays.
int **arrayPtr doesn't define a 2D array. 2D arrays look like this:
int array[2][3]
And a pointer to the first element of this array would look like:
int (*array)[3]
which you can point to a block of memory:
int (*array)[3] = malloc(sizeof(int)*5*3);
Note how that's indexed:
array[x] would expand to *(array+x), so "x arrays of 3 ints forward".
array[x][y] would expand to *( *(array+x) + y), so "then y ints forward".
There's no immediate array of pointers involved here, only one contignous block of memory.
If you'd have an array of arrays (not the same as 2D array, often done using int** ptr and a series of per-row mallocs), it would go like:
ptr[x] would expand to *(array+x), so "x pointers forward"
ptr[x][y] would expand to *( *(array+x) + y) = "y ints forward".
Mind the difference. Both are indexed with [x][y], but they are represented in a different way in memory and the indexing happens in a different manner.
how does malloc know that first it has to allocate a array of pointers, each of which pointer points to a one-dimensional array?
It doesn't; malloc simply allocates the number of bytes you specify, it has no working knowledge of how those bytes are structured into an aggregate data type.
If you're trying to dynamically allocate a multidimensional array, you have several choices.
If you're using a C99 or C2011 compiler that supports variable length arrays, you could simply declare the array as
int rows;
int cols;
...
rows = ...;
cols = ...;
...
int array[rows][cols];
There are a number of issues with VLAs, though; they don't work for very large arrays, they can't be declared at file scope, etc.
A secondary approach is to do something like the following:
int rows;
int cols;
...
rows = ...;
cols = ...;
...
int (*arrayPtr)[cols] = malloc(sizeof *arrayPtr * rows);
In this case, arrayPtr is declared as a pointer to an array of int with cols elements, so we're allocating rows arrays of cols elements each. Note that you can access each element simply by writing arrayPtr[i][j]; the rules of pointer arithmetic work the same way as for a regular 2D array.
If you aren't working with a C compiler that supports VLAs, you'll have to take a different approach.
You can allocate everything as a single chunk, but you'll have to access it as a 1-d array, computing the offsets like so:
int *arrayPtr = malloc(sizeof *arrayPtr * rows * cols);
...
arrayPtr[i * rows + j] = ...;
Or you can allocate it in two steps:
int **arrayPtr = malloc(sizeof *arrayPtr * rows);
if (arrayPtr)
{
int i;
for (i = 0; i < rows; i++)
{
arrayPtr[i] = malloc(sizeof *arrayPtr[i] * cols);
if (arrayPtr[i])
{
int j;
for (j = 0; j < cols; j++)
{
arrayPtr[i][j] = some_initial_value();
}
}
}
}
malloc() does not know that it needs to allocate an array of pointers to arrays. It simply returns a chunk of memory of the requested size. You can certainly do the allocation this way, but you'll need to initialize the first "row" (or last, or even a column instead of a row - however you want to do it) that are to be used as pointers so that they point to the appropriate area within that chunk.
It would be better and more efficient to just do:
int *arrayPtr = malloc(sizeof(int)*rows*cols);
The downside to that is that you have to calculate the proper index on every use, but you could write a simple helper function to do that. You wouldn't have the "convenience" of using [] to reference an element, but you could have e.g. element(arrayPtr, x, y).
I would re-direct your attention rather to question of "what does [] operator do?".
If you plan to access elements in your array via [] operator, then you need to realize that it can only do off-setting based on element's size, unless some array geometry info is supplied.
malloc does not have provisions for dimension info, calloc - explicitly 1D.
On the other hand, declared arrays (arr[3][4]) explicitly specify the dimensions to the compiler.
So to access dynamically alloc'ed multi-D arrays in a fashion arr[i][j], you in fact allocate the series of 1D-arrays of the target dimension size. You will need to loop to do that.
malloc returns plain pointer to heap memory, no information about geometry or data-type. Thus [][] won't work, you'll need to the offsetting manually.
So it's your call whether []-indexing is your priority, or the bulk allocation.
int **arrayPtr; does not point to a 2D array. It points to an array of pointers to int. If you want to create a 2D array, use:
int (*arrayPtr)[cols] = calloc(rows, sizeof *arrayPtr);
See this example:
int *array = malloc (10 * sizeof(int))
Is there a way to free only the first 3 blocks?
Or to have an array with negative indexes, or indexes that don't begin with 0?
You can't directly free the first 3 blocks. You can do something similar by reallocating the array smaller:
/* Shift array entries to the left 3 spaces. Note the use of memmove
* and not memcpy since the areas overlap.
*/
memmove(array, array + 3, 7);
/* Reallocate memory. realloc will "probably" just shrink the previously
* allocated memory block, but it's allowed to allocate a new block of
* memory and free the old one if it so desires.
*/
int *new_array = realloc(array, 7 * sizeof(int));
if (new_array == NULL) {
perror("realloc");
exit(1);
}
/* Now array has only 7 items. */
array = new_array;
As to the second part of your question, you can increment array so it points into the middle of your memory block. You could then use negative indices:
array += 3;
int first_int = array[-3];
/* When finished remember to decrement and free. */
free(array - 3);
The same idea works in the opposite direction as well. You can subtract from array to make the starting index greater than 0. But be careful: as #David Thornley points out, this is technically invalid according to the ISO C standard and may not work on all platforms.
You can't free part of an array - you can only free() a pointer that you got from malloc() and when you do that, you'll free all of the allocation you asked for.
As far as negative or non-zero-based indices, you can do whatever you want with the pointer when you get it back from malloc(). For example:
int *array = malloc(10 * sizeof(int));
array -= 2;
Makes an array that has valid indices 2-11. For negative indices:
int *array = malloc(10 * sizeof(int));
array += 10;
Now you can access this array like array[-1], array[-4], etc.
Be sure not to access memory outside your array. This sort of funny business is usually frowned upon in C programs and by C programmers.