Free array pointed to by a pointer within a struct in C - c

I have a stack implemented in dynamic array. Below are some of my functions. When I call stk_reset function, it seems that the stack is not freed completely.
Here is my struct. It is a requirement that I have to have a pointer inside struct pointing to the dynamic array
typedef struct stack {
char *items;
int arrSize;
int top;
} StackStruct;
void stack_create(StackStruct *s) {
char *arr = malloc(sizeof(char)*2);
if (arr == NULL) {
printf("Insufficient memory to initialize stack.\n");
return;
}
s->arrSize = 2;
s->items = arr;
s->top = -1;
}
How do I deallocate each element of the array holding the stack? I used this statement free((s->items)++) with a for loop, but it did not work.
void stk_reset(StackStruct *s) {
int i;
for (i = 0; i <= s->arrSize; i++)
free((s->items)++);
free(s->items);
s->items = NULL;
s->top = -1;
s->arrSize = 0;
}

You can only call free on the pointer returned to you by malloc and you can only free the whole block, not individual bytes.

You want one (1) call to free per call to malloc. Here you've only allocated one item with room for two characters. To free it, it's pretty straight-forward. Here is what is called a "Safe" release (or free).
if (s->items != NULL) {
free(s->items);
s->items = NULL; // Reset to be safe.
}
Though to use this, you will need to make sure you initialize your value to NULL before you try to use it: s->items = NULL;.
No other free calls are required, and certainly not in a loop when you only had one malloc.

Related

Regarding free function in c

May I know that if I free something in C programming language and I declare it as pointer before, it would just free out the memory but the pointer is still there or the pointer data type will also be destroyed as the code below. Also, may I know that if I want to free up my memory in this situation, why would I use free(list) in the end instead of using free(tmp)? Below is my code:
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 *sizeof(int));
if (list==NULL){
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
int *tmp = malloc(4 * sizeof(int));
if (tmp==NULL){
free(list);
return 1;
}
for (int i = 0; i < 3; i++){
tmp[i] = list[i];
}
tmp[3] = 4;
free(list);
list = tmp;
for (int i = 0; i < 4; i++){
printf("%i\n", list[i]);
}
free(list);
}
Calling free does not affect the pointer or its contents, just what the pointer pointed to. But the value in that pointer should no longer be considered valid.
The part about your specific use of free was addressed in the comments.
In these declarations
int *list = malloc(3 *sizeof(int));
int *tmp = malloc(4 * sizeof(int));
you declared two pointers list and tmp that has automatic storage duration. The pointers themselves point to dynamically allocated arrays that (the memory occupied by the arrays) should be freed using the function free to avoid memory leaks.
After calling the function free the pointers will have invalid values.
What the program is doing is at first it allocated dynamically an integer array with three elements and the address of the allocated memory is assigned to the pointer list.
int *list = malloc(3 *sizeof(int));
Then the program tries to reallocate the array by means at first of allocating dynamically a new array with four elements
int *tmp = malloc(4 * sizeof(int));
If the allocation was successful then the old array is freed
free(list);
and the address of the new array is assigned again to the pointer list.
list = tmp;
That is now the two pointers list and tmp point to the same dynamically allocated array. You can use either pointer to free the allocated memory but logically it is better to use the pointer list because the program simulates reallocation an array initially pointed to by the pointer list.

a bug in malloc which used to copy array elements

This code is meant to copy an int array with count elements to a newly applied memory area in the heap.
int copy(int *array ,int count){
int i;
int *myarray = (int*)malloc(count*sizeof(int));
if (myarray == NULL)
return -1;
for(int i = 0;i<count;i++)
{
myarray[i]=array[i];
}
return count;
i think maybe it forgets to use free() after using the malloc() function to free the memory but this code is meant to copy array element in the memory.so whether i am right ? If no, what is the really bug?
This function leaks memory.
myarray contains a pointer to allocated memory which contains a copy of the data in array. However, this pointer is not used in any way when the function returns so the pointer to the allocated memory is lost.
The function should return a pointer to this memory so that it can be used.
int *copy(int *array ,int count){
int i;
int *myarray = malloc(count*sizeof(int));
if (myarray == NULL)
return -1;
for(int i = 0;i<count;i++)
{
myarray[i]=array[i];
}
return myarray;
}
Note that it will be the responsibility of the calling function to free the memory when it is done with it.
Your copy function functions allocates memory and then copies the elements of the array to that newly allocated memory. So far so good, but then you simply throw away the pointer to that newly allocated memory.
It's like copying a letter by hand, putting the copy into a safe, closing the safe with the key and then throw the key away. Now the copy of the letter is in the safe, but you can't access it any more.
You probably want something like this:
...
int *copy(int *array, int count) // return a pointer to int, not an int
{
int *myarray = malloc(count*sizeof(int)); // (int*) cast is not needed
if (myarray == NULL)
return NULL; // return NULL if malloc fails
for(int i = 0; i < count; i++)
{
myarray[i] = array[i];
}
return myarray; // return pointer to newly allocated memory
}
...
int source[] = {1,2,3,4,5};
int *destination = copy(source, 5);
if (destination == NULL)
{
// handle error
}
// now destination points the the copy of the array
for (int i = 0; i < 5; i++)
{
printf("%d\n", destination[i]);
}
...
free(destination); // free allocated memory when you're done with it
...

How to avoid valgrind (or other memcheck tools) misreporting when I initialize a struct which contain a dynamic array?

I want to initialize a struct which contains a dynamic array, I wrote all this stuff in a function. And there is another function for cleaning this struct, theoretically, there will be no memory leaks. However, when I run the program with valgrind, it report that there was memory leaks when at the entry or init function.
Firstly, I wrote this init function with malloc to allocate memory for this struct. It report memory leak.
Then, I change malloc to realloc(NULL, ...) to avoid this misreport but I failed.
I don't know what the standard way in C is to implement this function.
#include <stdlib.h>
typedef enum
{
RUN_SUCCESS,
/*Failure*/
RUN_FAILURE
} RunStat;
typedef struct
{
char *elements;
size_t top;
size_t size;
} Stack;
RunStat init_stack(Stack *stack)
{
stack->elements = (char *)realloc(NULL, 100 * sizeof(char));
stack->size = 100;
stack->top = 0;
return RUN_SUCCESS;
}
RunStat free_stack(Stack *stack)
{
free(stack->elements);
stack->elements = NULL;
stack->size = 0;
stack->top = 0;
return RUN_SUCCESS;
}
int main ()
{
Stack stack;
init_stack(&stack);
free_stack(&stack);
return EXIT_SUCCESS;
}
Every memory here is under my control, I want to make this struct initialized without any memory leak warning. And I want to know the standard way to do that.

freeing a structure array allocated with double pointer

Here is basically what I'm trying to do:
free memory that was allocated in a different scope using double pointers.
The following code is incomplete but fully describes what I'm trying to perform.
so here is my function to read the buffer (C pseudo code)
char *read_buffer(char *buf, myStruct **arr, int nbElm)
{
buf = malloc(...);
...//many things done (use of the read(),close()... functions
...//but not referencing any of the buffer to my structure
...
*arr = (myStruct *) = malloc(sizeof(myStruct) * nbElm);
return (buf);
}
Here is the kind of function I use between my memory allocation and my freeing attempt:
void using_struct(myStruct *ar, int nbElm)
{
int i;
i = 0;
while (i < nbElm)
{
// Here I use my struct with no problems
// I can even retrieve its datas in the main scope
// not memory is allocated to it.
}
}
my main function :
int main(void)
{
char *buf;
myStruct *arStruct;
int nbElm = 4;
buf = read_buffer(buf, &arStruct, nbElm);
using_struct(arStruct, nbElm);
free(buf);
buf = NULL;
free(arStruct);
while(1)
{;}
return (1);
}
The only problem is either I place my while loop before or after my free function, I can't see any memory change using top
on my terminal.
Is this normal?
Thanks in advance,
You always must have exactly same number of calls to free as a calls to malloc.
myStruct **arr;
*arr = malloc(sizeof(myStruct) * nbElm);
This means you need single call to free first nbElm structs:
free(arr);

Allocating memory to my stack dynamically (only if needed)

I need to allocate memory to an array inside my struct, this array has no defined size at the beginning when i define the struct:
typedef struct stacks {
int size; // Stores the size of my -values- array
int sp; //points to the top of the stack, my stackpointer
int *values;
} STACKS;
So, to initialize my struct i wrote this function, that allocates (using calloc?) memory to my array, and i put inside SIZE variable, the new size of my array .
#define MAXIMUM 10
int initStacks(STACKS *s){
s->values = calloc(MAXIMUM,sizeof(int));
s->size = MAXIMUM;
s->sp = 0;
return 0;
}
Now, if i want to push something to the top of the stack (LIFO) i use this:
int pushs(STACKS *s, int x){
if (s->sp==s->size) {
realloc(s->values, MAXIMUM * sizeof(int));
s->size*=2;
}
s->values[s->sp]=x;
s->sp++;
}
Is this the correct way of doing this?
Is realloc working as it should in my function?
Thank you very much for your help!
EDIT:
would this make more sense? This way, i really don't need to declare the value of the array, being that defined with #define maximum 10
typedef struct stacks {
int size; // guarda o tamanho do array valores
int sp;
int *values;
} STACKS;
int initStacks(STACKS *s){
s->values = calloc(1,sizeof(int));
s->size = 1;
s->sp = 0;
return 0;
}
int isEmptys(STACKS *s){
return((s->sp)==0);
}
int pushs(STACKS *s, int x){
s->size++;
realloc(s->values, s->size * sizeof(int));
s->values[s->sp]=x;
s->sp++;
}
Assuming you have an original size factor (the name capacity would be as-appropriate, if not more so), your original code lacks several things:
Compares the size against a constant, rather than the current sp against the stack current size.
Does not save nor test the return result of realloc
Does not actually double the allocation (you're missing the 2x in the realloc expression.
Declares an int return result, but no such return exists.
Has no way of communicating back to the caller the push result (success or not). That missing return result would be ideal for this, btw.
Addressing all of these:
int pushs(STACKS *s, int x)
{
if (s->sp == s->size)
{
void *pv = realloc(s->values, 2 * s->size * sizeof *(s->values));
if (pv != NULL)
{
s->values = pv;
s->size *= 2;
}
else
{
fprintf(stderr, "Failed to resize stack\n");
return -1;
}
}
s->values[s->sp++] = x;
return 0;
}
Untested, but hopefully close enough.
Best of luck
Although not directly an answer to the actual question, but more to the general problem, I post this as it does not fit into a comment.
If you expect excessive push/pop operations and memory usage, the following might be an alternative:
typedef struct SubStack_s {
struct SubStack_s *prev;
int data[ENTRIES_PER_SEGMENT];
} SubStack;
typedef struct {
SubStack *tos; // init to NULL
size_t sp; // init to 0
} Stack;
The basic idea is to push elements onto each substack until full (as you already do). If the current one is full, you alloc a new one, chain them (new->prev = old) and continue with the new one (storing new to Stack.tos)
Pop works similar, free'ing each substack once it is not used anymore.
That concept is called "fragmented stack". It is much more efficient than the realloc-approach (it avoids copying) and does not fragment RAM as all block are of equal size. Oh, and it allows to have pointers into the stack, which the realloc-varaint does not, because the address of the stack can change.

Resources