For an assignment, I have to allocate a contiguous block of memory for a struct, but I'm first trying to do it with a 2D array of ints first and see if I understand it correctly. We had an example in the book that creates a block of memory for the pointer array (rows), and then initializes the cols and points the pointer to them. This example was:
int **CreateInt2D(size_t rows, size_t cols)
{
int **p, **p1, **end;
p = (int **)SafeMalloc(rows * sizeof(int *));
cols *= sizeof(int);
for (end = p + rows, p1 = p; p1 < end; ++p1)
*p1 = (int *)SafeMalloc(cols);
return(p);
}
void *SafeMalloc(size_t size)
{
void *vp;
if ((vp = malloc(size)) == NULL) {
fputs("Out of mem", stderr);
exit(EXIT_FAILURE);
}
return(vp);
}
I basically need to do what the above code does except make it one contiguous block of memory. The constraint is I'm only allowed to call malloc once, and then I have to use pointer math to know what to initialize the pointers to. So I thought I would initialize enough memory with something like:
int *createInt2D(size_t rows, size_t cols)
{
malloc(rows * sizeof(int *) + (row + cols) * sizeof(int));
}
But that doesn't seem quite right since I would think I would have to typecast the void * returned from malloc, but it's a combination of int and int*. So I'm not quite sure if I'm on the right track. Thoughts?
If you want a contiguous array, you should malloc(rows * cols * sizeof(int)).
Then you'd access arr[x, y] like:
arr[x * cols + y]
You are on the right track. The block returned by malloc is guaranteed to be aligned properly for either int * or int; you can use it for either. Typecasting isn't a one time operation.
If you are going to use array[row, col] addressing exclusively, you can get by without allocating extra space for the row pointers. If you would like to be able to use array[row] to get an int * column list, you'll have to include space for the column pointers in your allocation.
Hope that's enough to help with your exercise.
malloc((row * cols) * sizeof(int));
It's row*cols which is number of elements in the 2D array and not row+cols.
No need to multiply by the size of int *. That's only used to allocate the pointers for the rows. Same too with the sum of rows and cols. It's sufficient to allocate (rows * cols) * sizeof whatever structure is being allocated.
Related
In C++, we can change size of dynamically allocating arrays easily with std::vector. So I wondered if there is any way to change size of dynamically allocating arrays in C without using any other arrays or dynamically allocating arrays and delete the first one?
I have tried in using with arrays to copy the first one then deleting data which I don't want to use. Now I am hoping to use in another brainly way.
Like some people have suggested in the comments, any memory block allocated with malloc can be resized with realloc. Its internal logic will do the copying for you, if necessary. Note that realloc returns a NULL pointer if the resizing fails, so code like this will risk you a memory leak:
int data_length = 5;
int *data = malloc(data_length * sizeof(int));
...
data = realloc(data, data_length * 2 * sizeof(int));
You should instead do something like this:
int data_length = 5;
int *data = malloc(data_length * sizeof(int));
...
int new_data_length = data_length * 2;
int *new_data = realloc(data, new_data_length * sizeof(int));
if (new_data) {
data_length = new_data_length;
data = new_data;
}
Do the same when decreasing the size.
As title, I want to know how to initialize double pointer with sizeof a pointer.
For instance
int **p=malloc(sizeof *p * rows);
for(size_t i = 0; i < rows; i++){
p[i]=malloc(sizeof ? * cols);
}
What should I fill in ?.
Any help would be appreciated.
What should I fill in ?.
In general when you have
X = malloc(sizeof ? * NUMBER);
the ? is to be replaced with the type that X points to. That can simply written as *X.
So the line:
p[i]=malloc(sizeof ? * cols);
is to be:
p[i]=malloc(sizeof *p[i] * cols);
Notice that a 2D array can be created much simpler. All you need is
int (*p)[cols] = malloc(sizeof *p * rows);
Here p is a pointer to an array of cols int. Consequently sizeof *p will be the size of an array of cols int.
Using this VLA based technic means that you can allocate the 2D array using a single malloc. Besides making the code more simple (i.e. only 1 malloc) it also ensures that the whole 2D array is in consecutive memory which may give you better cache performance.
It looks like you want p to be an array that can hold pointers, and the number of pointers is rows. So you can allocate memory for p like this:
int ** p = malloc(sizeof(int *) * rows);
Now if you want p[i] to point to an array that holds cols ints, do this:
p[i] = malloc(sizeof(int) * cols);
int row = 5, col =5 ;
arr = (int **) malloc(sizeof(int*) * row);
for (int index=0; index<row; index++)
{
*(arr + index) = (int *) malloc(sizeof(int) * col);
}
I using this code to declare a double pointer array. How to use realloc to increase both the rows and columns, if needed ?
We don't know the number of inputs we are going to get :
void increase(int** arr)
{
*arr = (int *) realloc(*arr, 5 * sizeof (int));
}
I don't think that it's working. I need to reallocate both rows and columns.
I inserted the condition:
if(var % 5 == 4)
then call the function increase and reallocate but it doesn't seems to be working.
To make your code reusable for different data-type in C (int/double). You need to use the concept of generic data-type.
To use generic data-type, it might require you to implement data-type specific custom free function. For int and double you do not need to use custom specific free function; but free is not trivial if you are new to C.
To grow your data-structure, you need to define a function which grows the data-structure. Check this stack implementation from Stanford (Lecture: [4, 8)) https://www.youtube.com/playlist?list=PL9D558D49CA734A02
One advice.
Do not re-cast the output of malloc(). Not required!
Change:
arr = (int **) malloc(sizeof(int*) * row);
To:
arr = malloc(sizeof(int*) * row);
I am getting an error main.cpp…
Don't use the file name suffix .cpp for C programs - .cpp may cause gcc to compile the source code for another language.
I need to reallocate both rows and columns.
Since you don't pass dimensions to your increase() function, you apparently want it to increase the number of both rows and columns by 5. Since you used realloc(*arr, 5 * sizeof (int)), you apparently overlooked that the size passed to realloc() is not an increment, but rather the total size of the new memory space. Also, you should account for the possibility that the reallocation in increase() fails, and allow it to return an error indication. The following example returns the new (maybe moved) pointer or NULL in case of failure. As a bonus, this increase() function can also be used for the initial creation.
int row, col;
#include <malloc.h>
int **increase(int **arr)
{ // enlarge the "matrix" by 5 rows and 5 columns
int rownew = row+5, colnew = col+5;
arr = realloc(arr, rownew * sizeof *arr); // increase the rows
if (!arr) return NULL; // realloc error
do arr[row++] = NULL; while (row < rownew); // initialize new row pointers
for (rownew = 0; rownew < row; ++rownew)
{ // increase the columns in each row
int *newptr = realloc(arr[rownew], colnew * sizeof *newptr);
if (!newptr) return NULL; // realloc error
arr[rownew] = newptr;
}
col = colnew;
return arr;
}
main()
{
int **arr = increase(NULL); // create initial 5x5 "matrix"
int **newarr = increase(arr); // enlarge to new 10x10 "matrix"
if (newarr) arr = newarr;
else /* realloc error handling */;
}
Note that in something other than that toy example, we'd probably pass the dimensions as parameters rather than as globals.
I created a 2-D matrix using double pointer like that:
int** pt; pt = (int*) malloc(sizeof(int)*10);
I know that a pointer is freed like that
free(ptr);
How can we free the double pointer?
What if we print something and later freed that memory and exit the program? Does the final memory consist of that which we used or it will be same as initial?
Say you have a matrix mat
int** mat = malloc(10 * sizeof(int*));
for (int i=0; i<10; ++i) {
mat[i] = malloc(10 * sizeof(int));
}
then you can free each row of the matrix (assuming you have initialized each correctly beforehand):
for (int i=0; i<10; ++i) {
free(mat[i]);
}
then free the top-level pointer:
free(mat);
For your second question: if you allocate memory and use it, you will change that memory, which will not be "reverted" even if you free it (although you will not be able to access it reliably/portably any more).
Note: the top-level malloc is using sizeof(int*) as you are allocating pointer-to-ints, not ints -- the size of int* and int are not guaranteed to be the same.
If your matrix isn't "ragged", i.e. all rows have the same length, you might want to consider:
Accessing it manually, i.e. just treat it as a 1D array of values, and keep a separate width value. To access an element at (x,y) use mat[y * width + x].
If you really want the convenience of mat[y][x], you can improve it by doing a single call to malloc() that allocates both the pointer array and all the rows, then initializing the pointers to point at each row. This has the advantage that it can all be free:ed with a single free(mat); call.
The second approach would look something like this:
double ** matrix_new(size_t width, size_t height)
{
double **p = malloc(height * sizeof *p + width * height * sizeof **p);
double *e1 = (double *) (p + height);
size_t i;
for(i = 0; i < height; ++i)
p[i] = e1 + i * width;
return p;
}
Note: the above is un-tested, and production code should obviously check for failure before using p.
For the first question, I'll tell you the rule of thumb.
The number of times you call free() should be equal to the number of times you call malloc() + the number of times you call calloc().
So if you allocated in such a way that you made a pointer to pointers to ints, and then used malloc() on each pointer to ints, then you'll free "row" number of times, where each free() is for each pointer to ints.
And a final free() is called on the pointer to pointers to ints. That will balance out the malloc() + calloc() with free() calls.
I am generating contiguous 2d arrays using the method posted on here by Shawn Chin.[1][2] It works very well.
Briefly from his post:
char** allocate2Dchar(int count_x, int count_y) {
int i;
# allocate space for actual data
char *data = malloc(sizeof(char) * count_x * count_y);
# create array or pointers to first elem in each 2D row
char **ptr_array = malloc(sizeof(char*) * count_x);
for (i = 0; i < count_x; i++) {
ptr_array[i] = data + (i*count_y);
}
return ptr_array;
}
And the following free function:
void free2Dchar(char** ptr_array) {
if (!ptr_array) return;
if (ptr_array[0]) free(ptr_array[0]);
free(ptr_array);
}
It is not obvious to me how to create an equivalent reallocate function in either dimension, though I am only interested in realloc'ing the number of rows while maintaining continuity. Growing the number of columns would be interesting to understand but probably quite difficult. I haven't found any direct discussion of this issue anywhere other than to say, "it's hard!".[2]
Of course this is doable by a horrible brute force method, copying the data to a new 1D array (data, above) for storage, realloc'ing the 1D array, then freeing and regenerating the pointers (ptr_array) to the row elements for the new size. This, however, is pretty slow for row modifications, since it is necessary to at least double the memory requirement to copy out the data, and this is truly horribly bad for changing the number of columns.
This is an example of said method for changing the number of rows (it wouldn't work properly for changing the number of columns because the offsets for the pointers would be wrong for the data). I haven't fully tested this, but you get the idea ...
double **
reallocate_double_array (double **ptr_array, int count_row_old, int count_row_new, int count_col)
{
int i;
int old_size = count_row_old * count_col;
int new_size = count_row_new * count_col;
double *data = malloc (old_size * sizeof (double));
memcpy (&data[0], &ptr_array[0][0], old_size * sizeof (double));
data = realloc (data, new_size * sizeof (double));
free (ptr_array[0]);
free (ptr_array);
ptr_array = malloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}
Plus, this method requires you know the previous size, which is obnoxious!
Any thoughts greatly appreciated.
[1] How can I allocate a 2D array using double pointers?
[2] http://www.eng.cam.ac.uk/help/tpl/languages/C/teaching_C/node52.html
The first malloc and the memcpy are unnecessary, because you have easy access to the original data array at ptr_array[0]. You don't need to know the old size, because realloc should recall how much it allocated at the address and move the correct ammount of data.
Something like this should work.
double **
reallocate_double_array (double **ptr_array, int count_row_new, int count_col)
{
int i;
int new_size = count_row_new * count_col;
double *data = ptr_array[0];
data = realloc (data, new_size * sizeof (double));
free (ptr_array);
ptr_array = calloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}