c free() works when I call but not in my function - c

I am learning C and I am playing with malloc and free. But for some reason when I use free() in the main everything works but when I put it in my function it does not
#include <stdlib.h>
#include <stdio.h>
struct st {
int number;
};
void del(struct st *s) {
if (s == NULL) return;
free(s); s = NULL;
}
int main() {
struct st *s;
s = (struct st *)malloc(sizeof(struct st));
s->number = 4;
printf("The value is: %d", s->number);
del(s);
// free(s); s= NULL;
if(s == NULL) printf("\nThe struct is removed from memory\n");
else printf("\nThe value is: %d\n", s->number);
return 0;
}
This echo:
The value is: 4
The value is: 0
But if I do:
// del(s);
free(s); s= NULL;
it works

You are passing the pointer to your function, which means it only has access to the local copy of this pointer. So your free(s) will free only this local copy. If you want to free a variable, that is outside of the scope of the function from which you call free, you need to gain access to it by derefering again (passing a pointer to this pointer).
void del(struct st **s) {
if (*s == NULL) return;
free(*s);
*s = NULL;
}
should work fine.
Edit: call the function by del(&s);

Your del function frees the allocated memory and assigns NULL to the local copy of the variable. However, the local copy is not the same copy as that at the call-site (even if both point to the same allocated object, that has been freed).
You then end up doing what's called "use after free()", which is (probably) not actively harmful in this specific case, but can be a crash bug in the general case (and possibly a vector for code injection and exploits).
Either re-write del to take a pointer to a pointer and pass &s in, or have del return "the new value" and do s = del(s).

Related

if i execute this program, Im getting "Failed to Free". But Inside FREE function, it was deallocate the memory properly only

#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
typedef struct
{
int a ;
char b;
char c[50];
}TEST;
void *allocate(int count,int size);
void FREE(TEST *ptr);
int _tmain(int argc, _TCHAR* argv[])
{
TEST *test = NULL ;
void *ptr = NULL ;
ptr = allocate(2,sizeof(TEST));
test = (TEST *)ptr;
test->a = 1;
test->b = 'A';
strcpy(test->c,"siva");
FREE(test);
if(test != NULL) //here Im getting issues, test remains pointing address
printf("\n Failed to free");
else
printf("\n Free Success");
return 0;
}
void *allocate(int count,int size)
{
void *ptr;
ptr = calloc(count,size); // here allocated successfully
return ptr;
}
void FREE(TEST *ptr)
{
free(ptr);
ptr = NULL ; // Deallocated Successfully
}
In this code, i just called one allocation function to allocate memory dynamically, after that i called FREE function to free that memory, both functions working properly only. but inside main function after called the free function, why still test pointer pointing to the memory?
It's because the variable ptr inside the FREE function is a local variable, changing it will only change the local variable, nothing outside of the function will be modified.
What you need to do is to pass the variable by reference, which is not supported by C. C only have passing by value. But reference argument-passing can be emulated using pointers. So you need to pass a pointer to the pointer:
void FREE(TEST **ptr);
Call this using the address-of operator &:
FREE(&test);
and inside the function use the dereference operator * to access the original pointer variable.

Storing void pointers in a struct

I'm getting segmentation fault on code that is trying to initialize a struct of pointers to 0mq context and socket. The commented out code in the main method works, but it's only using local variables. I would like to initialize them and pass them around in a struct, but my google foo is failing me on how to do this properly.
#include "zhelpers.h"
#include <stdio.h>
#include <stdlib.h>
#include <zmq.h>
struct publisher{
void *handle;
void *context;
};
void init_publisher(struct publisher *p);
void destroy_publisher(struct publisher *p);
void publish(struct publisher *p,char *msg);
void init_publisher(struct publisher *p)
{
p = (struct publisher *)malloc(sizeof(struct publisher));
p->context = malloc(sizeof(void *));
p->handle = malloc(sizeof(void *));
void *context = zmq_ctx_new();
void *handle = zmq_socket(context,ZMQ_PUB);
zmq_bind(handle, "tcp://*:5556");
zmq_bind(handle, "ipc://feed.ipc");
p->context = context;
p->handle = handle;
}
void destroy_publisher(struct publisher *p)
{
zmq_close(p->handle);
zmq_ctx_destroy(p->context);
free(p->handle);
free(p->context);
free(p);
}
void publish(struct publisher *p,char *msg)
{
s_send(p->handle, msg);
}
int main(void)
{
/**
void *context = zmq_ctx_new();
void *publisher = zmq_socket(context, ZMQ_PUB);
int rc = zmq_bind(publisher, "tcp://*:5556");
assert(rc == 0);
rc = zmq_bind(publisher, "ipc://weather.ipc");
assert(rc == 0);
printf("Started Weather Server...\n");
srandom((unsigned) time (NULL));
int zipcode, temperature, relhumidity;
zipcode = randof(100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
char update[20];
sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity);
s_send(publisher, update);
zmq_close(publisher);
zmq_ctx_destroy(context);
*/
struct publisher *p;
init_publisher(p);
printf("Setup pub\n");
srandom((unsigned) time (NULL));
int zipcode, temperature, relhumidity;
zipcode = randof(100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
char update[20];
sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity);
publish(p,update);
printf("Published Message\n");
destroy_publisher(p);
printf("Destroyed publisher\n");
return 0;
}
There appears to be nothing in this code that would make it crash. (Assuming you know how all your zmq_... stuff works.)
It would have helped if you told us precisely where the error occurs, but my guess would be that the error occurs outside of this code.
You see, you are passing struct publisher *p to your init_publisher() function, but then you are allocating memory for p inside that method, (which makes passing p pointless,) and then you are not returning p. As a result, the code that calls init_publisher() probably expects p to be initialized, but it is not. The memory pointed by p is just allocated and leaked locally within your init_publisher() function.
So, instead of passing p, just have the function declare it and return it.
Alternatively, if the caller has already allocated p, then do not allocate it all over again from within init_publisher().
Please also note that the statements p->context = malloc(sizeof(void *)); are unnecessary and they are leaking small amounts of memory, because you proceed to overwrite these struct members.
The problem is that the passed pointer and the pointer you malloc()ed are not the same. The passed pointer contains the same address of your original pointer, presumably an invalid address, but the addresses of the poninters them selves are different because in c you can only pass a variable by value and hence, the pointer is copied.
That means that when you reassign p inside the function, the p from outside the function is unaltered. It would be different if it was allocated outside and you just use the function to access it's members.
You also don't need to malloc() every pointer you want to use, the thing is that it must point to a valid address before dereferencing it. When you want to request new uninitialized memory then you use malloc() otherwise you just make the pointer point to a valid address so that dereferencing it is defined, one example of using a pointer without malloc()ing it is
int *pointer;
int value;
value = 4;
pointer = &value; // Now `pointer' points to `value's` address
*pointer = 3;
printf("%d\n", value);
One way to write the function would be
int
init_publisher(struct publisher **pp)
{
struct publisher *p;
*pp = malloc(sizeof(struct publisher));
if (*pp == NULL)
return -1;
p = *pp;
p->context = zmq_ctx_new();
p->handle = zmq_socket(context,ZMQ_PUB);
if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */
{
zmq_bind(p->handle, "tcp://*:5556");
zmq_bind(p->handle, "ipc://feed.ipc");
}
return 0;
}
and then you could use it like this
struct publisher *p;
if (init_publisher(&p) != 0)
do_something_there_was_an_error();
/* Continue using `p' */
Note that the funcion is returning a value indicating whether allocations succeeded or not. Normally malloc() will not fail, but that doesn't mean that you should ignore the possible failure.
What I mean when I say if you allocate p first, is that if you instead do this
struct publisher *p;
p = malloc(sizeof(*p));
if (p == NULL)
return handle_error();
init_publisher(p);
then init_publisher() could be
void
init_publisher(struct publisher *pp)
{
void *context;
void *handle;
p->context = zmq_ctx_new();
p->handle = zmq_socket(context,ZMQ_PUB);
if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */
{
zmq_bind(p->handle, "tcp://*:5556");
zmq_bind(p->handle, "ipc://feed.ipc");
}
}
which is probably what you was trying to do.

Significance of double pointer and triple pointer in this code snippet

#include<stdio.h>
#include<stdlib.h>
void add(char **p);
void print(char **p);
int cnt=0;
main()
{
int option;
char **p=NULL;
while(1)
{
printf("------MENU-----\n");
printf("1>input\n 2>print\n3>exit\n");
printf("enter ur choice\n");
scanf("%d",&option);getchar();
switch(option)
{
case 1: add(p);
break;
case 2: print(p);
break;
case 3: return;
default: printf("Invalid option\n");
}
}
}
void add(char **p)
{
int i;
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
if(p==NULL)
{
printf("Error: memory not available\n");
return;
}
p[cnt]=NULL;
p[cnt]=(char*)realloc(p[cnt],20*sizeof(char));
puts("enter a name");
gets(p[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
}
void print(char **p)
{
int i;
for(i=0;i<cnt;i++)
printf("p[%d]=%s\n",i,p[i]);
}
In the above code, I am making a database of names. For this I am using dynamic memory allocation. I am allocation memory for 2D-array using array of pointers method. When I am executing this program on gcc compiler, I am getting segmentation fault. I am not understanding why is it happening?Could you please tell me where the bug is?
In main, all you do is to assign p = NULL and then use this NULL pointer in print, which causes the segfault. Note that add(p) is equivalent to add(NULL) and does not change p.
Did you mean to pass an address with add(&p)? If so, you need to fiddle a bit with the number of *.
p in main is handed over to add by value. add modifies a local copy then, but not the original p.
Besides the terrible formatting and everything you need to hand a pointer to your main's p to add:
...
case 1: add(&p);
...
void add(char ***p)
{
int i;
*p = realloc(*p,(cnt+1)*sizeof(char*));
if(*p==NULL)
{
printf("Error: memory not available\n");
return;
}
(*p)[cnt]=NULL;
(*p)[cnt]=realloc((*p)[cnt],20*sizeof(char));
puts("enter a name");
gets((*p)[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
}
A copy of 2D pointer p is created in the add function, and updating this pointer will not be reflected in the main function.
A quick solution to this problem is to return the 2D pointer 'p' from the add function.
char** print(char **p)
{
....
....
return p;
}
Pass by reference. You need to pass the address of your pointer to make sure the changes in function add() is reflected in main(). Avoid using gets()
In this case
add(&p);
Accordingly your add() function definition should change to handle this.
Or the other way is for the add function to make the required allocations and return that address to your pointer
char **add();
Check the code below:
char **add(char **p)
{
int i;
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
if(p==NULL)
{
printf("Error: memory not available\n");
return;
}
p[cnt]=NULL;
p[cnt]=(char*)realloc(p[cnt],20*sizeof(char));
scanf("%s",p[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
return p;
}
So your call should be:
p = add(p);
Apart from the other things, I don't think anyone's mentioned the realloc trap of reallocation failure. Suppose this call
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
fails to allocate the new memory: what happens then? Yes, you will get NULL returned: but the memory which was allocated, and which pis pointing to, does not get free'd. Instant memory leak.
You must call realloc like this:
char* pTemp = realloc(p, cnt + 1);
if(pTemp != NULL)
{
p = pTemp; // Now safe to update p
}
else
{
// Error handling as required, possibly including freeing p
}
Yet another reason not to use realloc. It doesn't really by you very much over doing the buffer copies yourself IMHO.

Using pointers for string manipulation in c

Here I'm taking a sentence a checking if it is a palindrome or not.I'm doing this in the process of learning stacks.
Is there a way i can use pointers instead of char array 'sent' so that the number of input characters need not be constrained to 20 in the following code?
The code is working fine, but should there be any improvements in terms of performance or anything else?
is there anything important about pointers i should remember while using stacks, like initializing it to NULL?
Thanks
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
char data;
struct node *link;
}StackNode;
void insertData(StackNode **);
void push(StackNode **, char);
void checkData(StackNode **);
bool pop(StackNode **,char *);
char sent[20] = "";
void main()
{
StackNode *stackTop;
stackTop = NULL;
insertData(&stackTop);
checkData(&stackTop);
printf("\n");
return;
}
void insertData(StackNode **stackTop)
{
char c;
int len;
printf("Enter the Sentence\n");
while( ( ( c = getchar() ) != '\n'))
{
if( ( ( c>='a' &&c<='z') || (c>='A' && c<='Z')))
{
if((c>='A' && c<='Z'))
{
int rem;
rem = c-'A';
c='a' + rem;
}
push(stackTop,c);
len = strlen(sent);
sent[len++]=c;
sent[len]='\0';
}
}
printf("Letters are %s\n\n",sent);
}
void push(StackNode **stackTop,char c)
{
StackNode *pNew;
pNew = (StackNode*) malloc(sizeof(StackNode));
if(!pNew)
{
printf("Error 100:Out of memory\n");
exit(100);
}
pNew->data = c;
pNew->link = *stackTop;
*stackTop = pNew;
}
void checkData(StackNode **stackTop)
{
char c;
int i=0;
while(pop(stackTop,&c))
{
if( c !=sent[i++])
{
printf("Not palindrome");
return;
}
}
printf("Palindrome");
}
bool pop(StackNode **stackTop,char *c)
{
StackNode *pNew;
pNew = *stackTop;
if(pNew == NULL)
return false;
*c = pNew->data;
*stackTop = pNew->link;
printf("char poped %c\n",*c);
free(pNew);
return true;
}
As far as I know, there is no way to have an "infinite array" or an array with no limitations. However, if you use malloc you can produce a section of memory large enough that you won't need to worry about the limitations as much. I see that later on in the code you have used malloc, so I assume you know how it works. However, I would use something like this;
char * sent = malloc(sizeof(char) * 100);
if(sent == NULL){
printf("OUT OF MEMORY!");
return 1;
}
Where 100 is the buffer size you wish to have. I have used a size up to 10000 and had no problems at runtime, so that may be what you need.
In C, arrays are really pointers to statically allocated memory. It is pretty straightforward to create a pointer to an array, or any element in an array. For example, suppose we have you array char sent[20]. If we wanted to create a pointer that pointed to the exact same memory as sent, we can declare char *sentP = sent. We can now replace any use of sent with sentP. We can even create a pointer to the middle of sent: char *sentMidP = sent + 9. Now, sentMidP[0] is the same as sent[9] and sentMidP[-9] is the same as sent[0].
However, unlike sent, we can change where sentP and sentMidP point (think of sent as a constant pointer char * const, which you can't change). Thus, if you had another array char sent2[100]'. You can set the value ofsentPtosent2. What's cool about this is that you can do it *at runtime*, which effectively means that you can change the size ofsentP` depending on the size of your input.
However, there is no need to limit yourself to statically allocated input. C provides the malloc function (see here) to allocate memory at runtime. Thus, if you don't know the size of your sentence at compile time, but you will know it at runtime (say in a variable called sentenceLength), you can allocate `sentP' like the following.
char *sentP = malloc(sizeof(char) * (sentenceLength + 1)); // Plus one for the NUL termination byte in C strings
if (sentP == NULL) {
fprintf(stderr, "No more memory :(");
exit(EXIT_FAILURE);
}
Note how we now have to handle out-of-memory errors. In general, dynamic allocation introduces more overhead, because there is a possibility that we run out of memory, a requirement that we ensure we only access what was allocated, and a need to release the memory with free once we're done.
When you're done with the sentP pointer, be sure to free it with:
free(sentP);
That's it! You can use the sentP pointer we made in your code, and everything should work great. Good luck!

Why is my pointer not null after free?

void getFree(void *ptr)
{
if(ptr != NULL)
{
free(ptr);
ptr = NULL;
}
return;
}
int main()
{
char *a;
a=malloc(10);
getFree(a);
if(a==NULL)
printf("it is null");
else
printf("not null");
}
Why is the output of this program not NULL?
Because the pointer is copied by value to your function. You are assigning NULL to the local copy of the variable (ptr). This does not assign it to the original copy.
The memory will still be freed, so you can no longer safely access it, but your original pointer will not be NULL.
This the same as if you were passing an int to a function instead. You wouldn't expect the original int to be edited by that function, unless you were passing a pointer to it.
void setInt(int someValue) {
someValue = 5;
}
int main() {
int someOtherValue = 7;
setInt(someOtherValue);
printf("%i\n", someOtherValue); // You'd expect this to print 7, not 5...
return 0;
}
If you want to null the original pointer, you'll have to pass a pointer-to-pointer:
void getFree(void** ptr) {
/* Note we are dereferencing the outer pointer,
so we're directly editing the original pointer */
if (*ptr != NULL) {
/* The C standard guarantees that free() safely handles NULL,
but I'm leaving the NULL check to make the example more clear.
Remove the "if" check above, in your own code */
free(*ptr);
*ptr = NULL;
}
return;
}
int main() {
char *a;
a = malloc(10);
getFree(&a); /* Pass a pointer-to-pointer */
if (a == NULL) {
printf("it is null");
} else {
printf("not null");
}
return 0;
}
Because the getFree() function takes a copy of the pointer. ptr and c are both pointers, but they are different variables. It's the same reason why this function will output "6":
void Magic(int x)
{
x = 1;
}
void main()
{
int a = 6;
Magic(a);
printf("%d", a);
}
You are passing pointer a by value, so it is not modified by function. It's only a copy of pointer modified within function, the original variable value is not affected.
Update:
If you wanted to make your life easier by replacing freeing + nulling a variable with a single line of code, you need either a macro:
#define MYFREE(x) free(x); x = NULL;
or a function with pointer to pointer argument:
void myfree(void** pp) { free(*pp); *pp = NULL; }
Pointers are stored as integers somewhere in memory.
When you do a = malloc(10);, a has some value, say 0x1.
When you call getFree(a);, the function copies a into void *ptr.
Now a=0x1 and ptr=0x1.
When you do ptr=NULL, only ptr is changed to NULL, but a is still 0x1..
You are passing the pointer By value.. (By default C passes the argument by value) which means you are updating the copy only ..not the real location..for that you might need to use pointer to pointer in C
void getFree(void **ptr)
{
if(*ptr != NULL)
{
free(*ptr);
*ptr = NULL;
}
return;
}
The question has already been answered but if it helps, I can explain it graphically.
You are doing this --> the pointer is copied by value to your function so it points to the array
but instead you want this -->point to the original pointer
As Merlyn Morgan-Graham already said, the way to solve it is to add operators * and &.

Resources