Again with the memory allocation...
I don't seem to understand why my call to free is not working on the array in the object. It makes sense to me, but I get a segmentation fault. All I would like is to free the min_array and the array in the stack in the minStackFree function. Does anyone understand why this could be happening?
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int * array;
int array_idx; // is 'top'
int * min_array;
int min_idx;
} MinStack;
MinStack * minStackCreate() {
MinStack * obj = malloc(sizeof(MinStack*));
//initialize the stacks
obj->array = malloc(10000*sizeof(int*));
obj->min_array = malloc(10000*sizeof(int*));
//initialize the index
obj->array_idx = -1;
obj->min_idx = -1;
}
void minStackFree(MinStack* obj) {
free(obj->min_array); // ************PROBLEM
free(obj->array); // ************PROBLEM
free(obj); // OK
}
It is not a matter of if malloc() will fail returning NULL, it is a matter of when. You must always validate EVERY allocation. Otherwise you risk Undefined Behavior (and likely a SegFault) if you fail to catch the allocation failure. A simple check is all that is needed, e.g.
#define ARRSZ 10000 /* if you need a constant, #define one (or more) */
MinStack *minStackCreate (void) {
MinStack *obj = malloc (sizeof *obj); /* use dereference pointer for typesize */
if (!obj) { /* validate EVERY allocation */
perror ("malloc-obj");
return NULL;
}
obj->array = malloc (ARRSZ * sizeof *obj->array); /* dereference pointer for typesize */
if (!obj->array) { /* validate EVERY allocation */
perror ("malloc-obj->array");
free (obj); /* free prior allocaitons */
return NULL;
}
obj->min_array = malloc (ARRSZ * sizeof *obj->min_array); /* ditto */
if (!obj->min_array) { /* ditto */
perror ("malloc-obj->min_array");
free (obj->array); /* free prior allocaitons */
free (obj);
return NULL;
}
//initialize the index
obj->array_idx = -1;
obj->min_idx = -1;
return obj; /* return allocated pointer */
}
As #chux-ReinstateMonica points out, with multiple allocations in your function, should an allocation fail, you must free the memory allocated in the function prior to the point of failure, before returning NULL to avoid a memory leak. Once NULL is returned, you would have no way to reach the allocations that occurred prior to the point of failure.
Don't use Magic-Numbers (e.g. 10000) in your code. If you need a constant, #define one, or use a global enum for the same purpose. That way if your needs change, you have one single location to update and the change is seen throughout your code.
Readability. The '*' dereference operator goes with the variable not the type. Why? Readability:
int* a, b, c;
most certainly does not declare 3-pointers to int, writing
int *a, b, c;
makes it abundantly clear that a single pointer to int and two integers are being declared.
Use the dereferenced pointer to set typesize. If you do that, you will never get the typesize wrong, e.g.
MinStack *obj = malloc (sizeof *obj);
and
obj->array = malloc (ARRSZ * sizeof *obj->array);
obj->min_array = malloc (ARRSZ * sizeof *obj->min_array);
While simple structs with the declaration in front of you may be easy to set the sizeof(type), when you are 1000 lines down in your code using complex types, things will not be so easy and it is easy to guess wrong.
With those changes, and returning obj on success or NULL on failure from minStackCreate() and the remainder compiles without warning.
It appears the issue was I needed to change:
MinStack * obj = malloc(sizeof(MinStack*));
//initialize the stacks
obj->array = malloc(10000*sizeof(int*));
obj->min_array = malloc(10000*sizeof(int*));
to
MinStack * obj = malloc(sizeof(MinStack));
//initialize the stacks
obj->array = malloc(10000*sizeof(int));
obj->min_array = malloc(10000*sizeof(int));
return obj;
Related
Building on what I learned here: Manipulating dynamic array through functions in C.
void test(int data[])
{
data[0] = 1;
}
int main(void)
{
int *data = malloc(4 * sizeof *data);
test(data);
return 0;
}
This works fine. However, I am also trying to using realloc in a function.
void increase(int data[])
{
data = realloc(data, 5 * sizeof *data);
}
This complies but the program crashes when run.
Question
How should I be using realloc in a function?
I understand that I should assign the result of realloc to a variable and check if it is NULL first. This is just a simplified example.
You want to modify the value of an int* (your array) so need to pass a pointer to it into your increase function:
void increase(int** data)
{
*data = realloc(*data, 5 * sizeof int);
}
Calling code would then look like:
int *data = malloc(4 * sizeof *data);
/* do stuff with data */
increase(&data);
/* more stuff */
free(data);
Keep in mind the difference between a pointer and an array.
An array is a chuck of memory in the stack, and that's all.If you have an array:
int arr[100];
Then arr is an address of memory, but also &arr is an adress of memory, and that address of memory is constant, not stored in any location.So you cannot say arr=NULL, since arr is not a variable that points to something.It's just a symbolic address: the address of where the array starts.Instead a pointer has it's own memory and can point to memory addresses.
It's enough that you change int[] to int*.
Also, variables are passed by copy so you need to pass an int** to the function.
About how using realloc, all the didactic examples include this:
Use realloc;
Check if it's NULL.In this case use perror and exit the program;
If it's not NULL use the memory allocated;
Free the memory when you don't need it anymore.
So that would be a nice example:
int* chuck= (int*) realloc (NULL, 10*sizeof(int)); // Acts like malloc,
// casting is optional but I'd suggest it for readability
assert(chuck);
for(unsigned int i=0; i<10; i++)
{
chunk[i]=i*10;
printf("%d",chunk[i]);
}
free(chunk);
Both code are very problematic, if you use the same pointer to send and receive from realloc, if it fails, you will lose your pointer to free it later.
you should do some thing like this :
{
...
...
more = realloc(area , size);
if( more == NULL )
free(area);
else
area=more;
...
...
}
I'm trying to write a function that uses realloc() to extend the array as pointed to within in instance of a struct, however I can't seem to get it to work.
The relevant part of my code is:
struct data_t {
int data_size;
uint16_t *data;
};
void extend_data(data_t container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
int len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
container->data_size++;
container->data[container->data_size-1] = value;
len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
Can anybody see what the problem is with this?
Edit
As R. Sahu points out, container is not a pointer in this function - when you said the code "wasn't working", I assumed you meant that you weren't growing your array, but what you've written here won't even compile.
Are you sure you've copied this code correctly? If so, does "not working" mean you're getting a compile-time error, a run-time error, or just unexpected output?
If you've copied the code as written, then the first thing you need to do is change the function prototype to
void extend_data(data_t *container, uint16_t value) {
and make sure you're passing a pointer to your data_t type, otherwise the update won't be reflected in calling code.
Original
In the line
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
sizeof(*(container->data)) evaluates to sizeof (uint16_t). container->data is a pointer to, not an array of, uint16_t; sizeof will give you the size of the pointer object, not the number of elements you've allocated. What you want to do is something like the following:
/**
* Don't assign the result of a realloc call back to the original
* pointer - if the call fails, realloc will return NULL and you'll
* lose the reference to your original buffer. Assign the result to
* a temporary, then after making sure the temporary is not NULL,
* assign that back to your original pointer.
*/
uint16_t *tmp = realloc(container-data, sizeof *container->data * (container->data_size + 1) );
if ( tmp )
{
/**
* Only add to container->data and update the value of container->data_size
* if the realloc call succeeded.
*/
container->data = tmp;
container->data[container->data_size++] = value;
}
You don't calculate the new size correctly. Consider this:
typedef struct {
size_t size;
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, NULL}
void int_array_resize(int_array *const array,
const size_t newsize)
{
if (!array) {
fprintf(stderr, "int_array_resize(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
if (!newsize) {
free(array->data);
array->data = 0;
array->size = 0;
} else
if (newsize != array->size) {
void *temp;
temp = realloc(array->data, newsize * sizeof array->data[0]);
if (!temp) {
fprintf(stderr, "int_array_resize(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = temp;
array->size = newsize;
}
}
/* int_array my_array = INT_ARRAY_INIT;
is equivalent to
int_array my_array;
int_array_init(&my_array);
*/
void int_array_init(int_array *const array)
{
if (array) {
array->size = 0;
array->data = NULL;
}
}
void int_array_free(int_array *const array)
{
if (array) {
free(array->data);
array->size = 0;
array->data = NULL;
}
}
The key point is newsize * sizeof array->data[0]. This is the number of chars needed for newsize elements of whatever type array->data[0] has. Both malloc() and realloc() take the size in chars.
If you initialize new structures of that type using int_array my_array = INT_ARRAY_INIT; you can just call int_array_resize() to resize it. (realloc(NULL, size) is equivalent to malloc(size); free(NULL) is safe and does nothing.)
The int_array_init() and int_array_free() are just helper functions to initialize and free such arrays.
Personally, whenever I have dynamically resized arrays, I keep both the allocated size (size) and the size used (used):
typedef struct {
size_t size; /* Number of elements allocated for */
size_t used; /* Number of elements used */
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, 0, NULL }
A function that ensures there are at least need elements that can be added is then particularly useful. To avoid unnecessary reallocations, the function implements a policy that calculates the new size to allocate for, as a balance between amount of memory "wasted" (allocated but not used) and number of potentially slow realloc() calls:
void int_array_need(int_array *const array,
const size_t need)
{
size_t size;
void *data;
if (!array) {
fprintf(stderr, "int_array_need(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
/* Large enough already? */
if (array->size >= array->used + need)
return;
/* Start with the minimum size. */
size = array->used + need;
/* Apply growth/reallocation policy. This is mine. */
if (size < 256)
size = (size | 15) + 1;
else
if (size < 2097152)
size = (3 * size) / 2;
else
size = (size | 1048575) + 1048577 - 8;
/* TODO: Verify (size * sizeof array->data[0]) does not overflow. */
data = realloc(array->data, size * sizeof array->data[0]);
if (!data) {
/* Fallback: Try minimum allocation. */
size = array->used + need;
data = realloc(array->data, size * sizeof array->data[0]);
}
if (!data) {
fprintf(stderr, "int_array_need(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = data;
array->size = size;
}
There are many opinions on what kind of reallocation policy you should use, but it really depends on the use case.
There are three things in the balance: number of realloc() calls, as they might be "slow"; memory fragmentation if different arrays are grown requiring many realloc() calls; and amount of memory allocated but not used.
My policy above tries to do many things at once. For small allocations (up to 256 elements), it rounds the size up to the next multiple of 16. That is my attempt at a good balance between memory used for small arrays, and not very many realloc() calls.
For larger allocations, 50% is added to the size. This reduces the number of realloc() calls, while keeping the allocated but unused/unneeded memory below 50%.
For really large allocations, when you have 221 elements or more, the size is rounded up to the next multiple of 220, less a few elements. This caps the number of allocated but unused elements to about 221, or two million elements.
(Why less a few elements? Because it does not harm on any systems, and on certain systems it may help a lot. Some systems, including x86-64 (64-bit Intel/AMD) on certain operating systems and configurations, support large ("huge") pages that can be more efficient in some ways than normal pages. If they are used to satisfy an allocation, I want to avoid the case where an extra large page is allocated just to cater for the few bytes the C library needs internally for the allocation metadata.)
It appears you aren't using sizeof correctly. In your struct you've defined a uint16_t pointer, not an array. The size of the uint16_t* data type is the size of a pointer on your system. You need to store the size of the allocated memory along with the pointer if you want to be able to accurately resize it. It appears you already have a field for this with data_size. Your example might be able to be fixed as,
// I was unsure of the typedef-ing happening with data_t so I made it more explicit in this example
typedef struct {
int data_size;
uint16_t* data;
} data_t;
void extend_data(data_t* container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
// CURRENT LENGTH OF DATA
int len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
uint16_t* tmp = realloc(container->data, (container->data_size + 1) * sizeof(uint16_t));
if (tmp) {
// realloc could fail and return false.
// If this is not handled it could overwrite the pointer in `container` and cause a memory leak
container->data = tmp;
container->data_size++;
container->data[container->data_size-1] = value;
} else {
// Handle allocation failure
}
len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
void extend_data(data_t container, ...
In your function container is not the pointer but the struct itself passed by the value so you cant use the -> operator.
The realloced memory will be lost as you work on the local copy of the passed strucure and it will be lost on the function return.
sizeof(*(container.data)) / sizeof(uint16_t)
it will be always 1 as the *(uint16_t *) / sizeof(uint16_t) is always one.
Why: data member is pointer to the uint16_t. *data has the type of uint16_t
sizeof is calculated during the compilation not the runtime and it does not return the ammount of memory allocated by the malloc.
Building on what I learned here: Manipulating dynamic array through functions in C.
void test(int data[])
{
data[0] = 1;
}
int main(void)
{
int *data = malloc(4 * sizeof *data);
test(data);
return 0;
}
This works fine. However, I am also trying to using realloc in a function.
void increase(int data[])
{
data = realloc(data, 5 * sizeof *data);
}
This complies but the program crashes when run.
Question
How should I be using realloc in a function?
I understand that I should assign the result of realloc to a variable and check if it is NULL first. This is just a simplified example.
You want to modify the value of an int* (your array) so need to pass a pointer to it into your increase function:
void increase(int** data)
{
*data = realloc(*data, 5 * sizeof int);
}
Calling code would then look like:
int *data = malloc(4 * sizeof *data);
/* do stuff with data */
increase(&data);
/* more stuff */
free(data);
Keep in mind the difference between a pointer and an array.
An array is a chuck of memory in the stack, and that's all.If you have an array:
int arr[100];
Then arr is an address of memory, but also &arr is an adress of memory, and that address of memory is constant, not stored in any location.So you cannot say arr=NULL, since arr is not a variable that points to something.It's just a symbolic address: the address of where the array starts.Instead a pointer has it's own memory and can point to memory addresses.
It's enough that you change int[] to int*.
Also, variables are passed by copy so you need to pass an int** to the function.
About how using realloc, all the didactic examples include this:
Use realloc;
Check if it's NULL.In this case use perror and exit the program;
If it's not NULL use the memory allocated;
Free the memory when you don't need it anymore.
So that would be a nice example:
int* chuck= (int*) realloc (NULL, 10*sizeof(int)); // Acts like malloc,
// casting is optional but I'd suggest it for readability
assert(chuck);
for(unsigned int i=0; i<10; i++)
{
chunk[i]=i*10;
printf("%d",chunk[i]);
}
free(chunk);
Both code are very problematic, if you use the same pointer to send and receive from realloc, if it fails, you will lose your pointer to free it later.
you should do some thing like this :
{
...
...
more = realloc(area , size);
if( more == NULL )
free(area);
else
area=more;
...
...
}
Just for fun (and for C programming practice) I wrote the following piece of code that does the following:
Acts as a tracking system for memory allocations
Frees all dynamically allocated memory with a function call
Here is the code:
typedef enum _OpMode {
OM_APPEND,
OM_DESTROY
} OP_MODE;
void refOp(void *ptr, OP_MODE mode) {
/* contains static array of pointers and provides an interface to that
array */
static void **references = NULL;
static int size = 0;
static int reset = 0;
if (reset) {
reset = 0;
references = NULL;
size = 0;
}
switch (mode) {
case OM_APPEND:
//add a pointer to reference array
references = (void**) realloc(references, sizeof(void*) * (size + 1));
references[size++] = ptr;
break;
case OM_DESTROY:
//free memory at all pointers kept in reference array
for (int i = 0; i < size; i++) {
free(references[i]);
references[i] = NULL;
}
free(references);
reset = 1;
break;
default:
printf("Invalid enum value '%d' passed as mode.\n", mode);
break;
}
}
void refDestroyAll() {
//Wrapper function
refOp(NULL, OM_DESTROY);
}
void *myAlloc(void* ptr, size_t size) {
/* Allocates memory and stores pointer copy in reference array */
void *tmp_ptr;
tmp_ptr = realloc(ptr, size);
refOp(tmp_ptr, OM_APPEND);
return tmp_ptr;
}
The idea is that one would use myAlloc() instead of malloc or realloc to dynamically allocate memory. And one would use refDestroyAll() to free all memory that was created with myAlloc().
I've done some testing, and it seems to be working, but I can't help feeling that I'm missing something important. Does this code actually work as intended, or am I leaking memory when I call refDestroyAll()?
You have a bug, that could cause a segmentation fault. realloc() could return the same pointer as it is given, in which case you would have added it twice to the array. When you call your free function, it would try and free the same pointer twice, resulting in a segmentation fault error.
Additionally, I don't understand why you have the reset parameter. Why not simply set references and size to 0 in the OM_DESTROY case? It is good practice to always set a pointer to NULL immediately after freeing it.
What is the right way to malloc memory ? And what is the difference between them ?
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
*my_cookie = malloc(sizeof(cookie_bank) * 1);
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
///
}
I'm trying to malloc array of cookie_bank structs function.
I'm assuming that you want the function to allocate memory for an array and passing the result via a pointer parameter. So, you want to write T * x = malloc(...), and assign the result to a pointer argument, *y = x:
cookie_bank * myarray;
parse_cookies(..., &myarray, ...);
/* now have myarray[0], myarray[1], ... */
So the correct invocation should be, all rolled into one line,
parse_cookies(..., cookie_bank ** y, ...)
{
*y = malloc(sizeof(cookie_bank) * NUMBER_OF_ELEMENTS);
}
Your second example is the most correct. You don't need the *1 obviously.
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
Your first example is also correct, although some compilers/flags will cause a complaint about the implicit cast from void*:
*my_cookie = malloc(sizeof(cookie_bank) * 1);
It you want to allocate more than one entry you'd generally use calloc() because it zeros the memory too:
*my_cookie = (cookie_bank*)calloc(sizeof(cookie_bank), 1);
your third example is just wrong:
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
This will overwrite the local my_cookie pointer, and the memory will be lost on function return.
I just would like to recommend you to read some C textbook. It seems to me that you do not have clear understanding on how pointers work in C language.
Anyway, here is some example to allocate memory with malloc.
#include <stdlib.h>
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
if (cookies_num == NULL || *cookies_num == 0) {
return;
}
if (my_cookie == NULL) {
my_cookie = (cookie_bank**)malloc(sizeof(cookie_bank*) * *cookies_num);
}
for (int i = 0; i < *cookies_num; i++) {
*my_cookie = (cookie_bank*)malloc(sizeof(cookie_bank));
my_cookie++;
}
}
Of course, this example does not cover any error handling. Basically, my_cookie is pointer to pointer which means my_cookie is just pointer to point memory location where it holds array of pointers. The first malloc allocate the memory using size of pointer and requested number of cookie structure. Then second malloc actually allocate memory for each structure.
The problem of this function is that it can easily cause memory leak unless using this very carefully.
Anyway, it is important to understand how C pointer works.