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.
Related
Example: my array contains integers {1,2,3,4}
I want to resize my array in order to contain {2,3,4} and when I do array[0] it should give me 2.
When you shrink an array with realloc(), you can remove space at the end of the array, but not at the beginning of the array. Therefore, to achieve the result you want, you'd have to copy the portion of the array you want to keep to its new position and then resize the array:
/* setup */
int *data = malloc(4 * sizeof(int)); // Error check omitted
for (int i = 0; i < 4; i++)
data[i] = i + 1;
/* setup complete */
/* Move elements before shrinking array */
memmove(&data[0], &data[1], 3 * sizeof(int)); // Safe move
int *new_data = realloc(data, 3 * sizeof(int));
if (new_data != 0)
data = new_data;
I'm not sure whether a 'shrinking' realloc() does ever return NULL (but the standard doesn't say it can't), so the code takes no chances. Many people would write data = realloc(data, 3 * sizeof(int)); and run the risk, and they'd get away with it almost all the time. Note that a 'growing' realloc() really can return NULL and you can then leak memory if you use the old_ptr = realloc(old_ptr, new_size) idiom.
Usually, a 'shrinking' realloc() will return the original pointer (unless you shrink it to zero size, when it may return NULL). A 'growing' realloc() can often change where the data is stored.
I'm using this code to dynamically create a 2d array:
char **FileTables;
int rows = 1000;
int i;
FileTables = (char**)malloc(rows * sizeof(char));
for (i = 0; i < rows; i++) {
FileTables[i] = (char*)malloc(256 * sizeof(char));
}
Problem is with 1000 rows, and there could be more, it takes a couple of seconds to allocate all the memory.
Is there any faster/better method to doing this?
EDIT:
Is there an advantage to using one of these methods over the other, besides the obvious simpler code?
char **FileTables;
int rows = 1000;
int i;
FileTables = malloc(rows * sizeof(char*));
FileTables[0] = malloc(rows * 256 * sizeof(char));
for (i = 0; i < rows; i++) {
FileTables[i] = FileTables[0] + i * 256;
}
And..
char (*FileTables)[256];
int rows = 1000;
FileTables = malloc(rows * sizeof(*FileTables));
(And yes, I fixed the unnecessary casting)
You could get away with just two allocations and some pointer arithmetic:
int rows = 1000;
int cols = 256;
char *data;
char **FileTables;
int i;
data = malloc(rows * cols);
FileTables = malloc(rows * sizeof(char*));
for (i = 0; i < rows; i++) {
FileTables[i] = data + i * cols;
}
Also note that I fixed a bug in malloc(rows * sizeof(char)) (the sizeof(char) should be sizeof(char*), since you're allocating an array of pointers to char).
As long as the number of columns is constant, or if you're using C99, you can get away with a single malloc without having to do ugly row/column addressing arithmetic yourself:
char (*FileTables)[256] = malloc(rows * sizeof *FileTables);
If the array is always of the size row × 256, then you might consider a one-dimensional array malloc(row * 256), and access it in strides:
char get(unsigned i, unsigned j, char * array) { return array[j + 256 * i]; }
void set(char value, unsigned i, unsigned j, char * array) { array[j + 256 * i] = value; }
This avoids multiple allocations and gives better memory locality. On top of that, you can pick row or column ordering to micro-optimize.
char **FileTables;
int rows = 1000;
int i;
FileTables = (char**)malloc(rows * sizeof(char *));
char *data = (char *)malloc(256 * 1000 * sizeof(char));
for (i = 0; i < rows; ++i) {
FileTables[i] = data;
data += 256 * sizeof(char);
}
Should be a better solution.
I don't believe you will get anywhere near seconds. Increasing the rows to 10 million is still under a second on my machine.
However if you want to minimise allocations, you only need one.
FileTables = (char**) malloc(rows * (sizeof(char *) + 256*sizeof(char)));
FileTables[0] = (char *) &FileTables[rows];
for (i = 1; i < rows; i++) {
FileTables[i] = FileTables[i-1] + 256 * sizeof (char);
}
free(FileTables);
A more efficient way to do this is to avoid the second level of indirection.
typedef char chars[256];
int main(int argc, char** argv) {
chars* FileTables;
int rows = 100000000;
int i;
FileTables = (chars*) malloc(rows * sizeof (chars));
free(FileTables);
return (EXIT_SUCCESS);
}
This avoid a pointer lookup as the C can calculate the rest.
First of all, are you sure it's the memory allocation that is the problem? allocating 1000 blocks of memory should generally not take a few seconds.
You could look into alternate malloc implementations if you have particular needs (e.g., google's tcmalloc if you are allocating memory in threads).
Otherwise, the real "slow" part of malloc is actually getting memory from the OS (with sbrk() or mmap()), and most malloc implementations will grab a big chunk at a time and give it back in smaller pieces, so there are not 1000 calls to allocate 1k each here, there are maybe 60 calls to allocate 16k. Running the program under strace or similar may give you an idea of how many slow system calls are really being made.. You could implement similar behavior yourself, by making a single call to allocate 256K and subdividing that up into smaller chunks. You could try allocating a big chunk of memory and then immediately free()-ing it and hope that the library malloc holds onto that memory and doesn't go back to the OS for more.
This really looks like premature optimization; because, you are asking for faster, but you haven't indicated how fast is fast enough. Still, if you really need to do it this way...
Tips to speed up allocation:
Do fewer allocations
Do smaller allocations
As you can see, if you need 10M allocated, these tips soon become conflicting. To determine the right balance between smaller and fewer allocations, on needs to do profiling.
Look to your memory block size and allocate whole pages of memory at once. It's an old hardware hack, but it does guarantee that you don't ask for multiple pages of continuous memory at once (which speeds up the selecting from the free page lists), and it also guarantees that you don't waste some cycles address space by asking for addresses already reserved by the block reservation subsystem of the memory manager.
If that doesn't get you the performance you need, then rewrite the code to not require allocation the way it's been presented.
Either way, it's not possible to guarantee optimum allocation speed without detailed knowledge of how the memory management subsystem on your computer is actually designed.
I'm new in c. I want to create array, and after it delete it, and then put another array into it. How can I do it?
If you are looking for a dynamic array in C they are fairly simple.
1) Declare a pointer to track the memory,
2) Allocate the memory,
3) Use the memory,
4) Free the memory.
int *ary; //declare the array pointer
int size = 20; //lets make it a size of 20 (20 slots)
//allocate the memory for the array
ary = (int*)calloc(size, sizeof(int));
//use the array
ary[0] = 5;
ary[1] = 10;
//...etc..
ary[19] = 500;
//free the memory associated with the dynamic array
free(ary);
//and you can re allocate some more memory and do it again
//maybe this time double the size?
ary = (int*)calloc(size * 2, sizeof(int));
Information on calloc() can be found here, the same thing can be accomplished with malloc() by instead using malloc(size * sizeof(int));
It sounds like you're asking whether you can re-use a pointer variable to point to different heap-allocated regions at different times. Yes you can:
void *p; /* only using void* for illustration */
p = malloc(...); /* allocate first array */
... /* use the array here */
free(p); /* free the first array */
p = malloc(...); /* allocate the second array */
... /* use the second array here */
free(p); /* free the second array */
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;
}
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.