Why is my pointer not null after free? - c

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 &.

Related

Comparing pointer value passed into a function by address with null resulting in reversed result

I am well aware that there are many similar questions, but have not yet find the one that solves this. So I will also thank anyone that could point me to the duplicate.
Say I have a function that takes a void pointer and modify the value inside:
int func(void *head)
{
if (head == NULL){
printf("is null\n");
/* do sth with the value */
}
else{
printf("not null\n");
/* do sth with the value */
}
return 1;
}
And I passed a NULL pointer by address into it:
void *setList = NULL;
func(&setList);
It would give me not null, which is not what I want. (if passing by value it works well)
What was I missing? How could I judge if it's a NULL pointer when passed by address?
Thanks.
In this declaration
void *setList = NULL;
you declared the variable setList that occupies a memory. So the address of the variable itself is not equal to NULL. It is the value of the variable that is stored in the allocated for the variable memory that is equal to NULL.
In this call
func(&setList);
the type of the argument expression is void **.
Within the function declared like
int func(void *head);
you have at first cast the pointer head to the type void **.
For example
void **p = ( void ** )head;
and then in the if statement you need to dereference the pointer p like
if ( *p == NULL )
//...
Here is a demonstrative program.
#include <stdio.h>
int func( void *head )
{
void **p = ( void ** )head;
if ( *p == NULL )
{
puts( "p is a null pointer" );
}
else
{
puts( "p is not a null pointer" );
}
return 1;
}
int main(void)
{
void *setList = NULL;
func( &setList );
int x = 10;
setList = &x;
func( &setList );
return 0;
}
Its output is
p is a null pointer
p is not a null pointer
As for your original code then a question arises why is not the function declared like
int func(void **head);
if you are going to pass a pointer to pointer?
void *setList = NULL;
you create the variable setlist having the type of pointer to void and initialize it to NULL.
func(&setList);
you pass the address of the variable setList not the value of it. The variable is the valid object and its address is by definition not NULL.

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

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).

C free(): invalid pointer allocated in other function

I'm new in StackOverflow. I'm learning C pointer now.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int alloc(int* p){
p = (int*) malloc (sizeof(int));
if(!p){
puts("fail\n");
return 0;
}
*p = 4;
printf("%d\n",*p);
return 1;
}
int main(){
int* pointer;
if(!alloc(pointer)){
return -1;
}else{
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
I compile with: gcc -o main main.c
error: free(): invalid pointer: 0xb77ac000 ***
what's wrong with my code?
Arguments in C are always passed by value. So, when you call alloc(pointer), you just pass in whatever garbage value pointer contains. Inside the function, the assignment p = (int*)... only modifies the local variable/argument p. Instead, you need to pass the address of pointer into alloc, like so:
int alloc(int **p) {
*p = malloc(sizeof(int)); // side note - notice the lack of a cast
...
**p = 4; // <---- notice the double indirection here
printf("%d\n", **p); // <---- same here
return 1;
}
In main, you would call alloc like this:
if (!(alloc(&pointer))) {
....
Then, your code will work.
Everything in C is pass-by-value. This means that functions always operate on their own local copy of what you pass in to the function. Usually pointers are a good way to mimic a pass-by-reference scheme because a pointer and a copy of that pointer both contain the same memory address. In other words, a pointer and its copy both point to the same space.
In your code the issue is that the function alloc gets its own local copy of the pointer you're passing in. So when you do p = (int*) malloc (sizeof(int)); you're changing the value of p to be a new memory address, but the value of pointer in main remains unchanged.
You can get around this by passing a pointer-to-a-pointer, or by returning the new value of p.
You have two major problems in your code.
First, the alloc function creates a pointer via malloc, but never frees it, nor does it return the pointer to the calling function. This guarantees the memory the pointer addresses can never be freed up via the free command, and you now have memory leaks.
Second, the variable, int* pointer in main, is not being modified as you would think. In C, function arguments are "passed by value". You have two ways to address this problem:
Pass a pointer to the variable you want to modify (in your case, a pointer to a pointer to an int)
Have the function return the pointer to the function that called it.
Here are two implementations of my recommendations:
Approach 1
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p);
int alloc(int** p) {
if (!p) {
printf("Invalid argument\n");
return (-1);
}
if ((*p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (-1);
}
**p = 123;
printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
return 0;
}
int main(){
int* pointer;
if(alloc(&pointer) != 0){
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
return 0;
}
Sample Run for Approach 1
p:0xbfbea07c - *p:0x8656008 - **p:123
&pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
Approach 2
#include <stdio.h>
#include <stdlib.h>
int* alloc(void) {
int* p;
if ((p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (NULL);
}
*p = 123;
printf("p:%p - *p:%d\n", p, *p);
return p;
}
int main(){
int* pointer = alloc();
if(pointer == NULL) {
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
pointer = NULL;
return 0;
}
Sample Run for Approach 2
p:0x858e008 - *p:123
&pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
You are passing the pointer by value into your alloc function. Although that function takes a pointer to an int, that pointer itself cannot be modified by the function. If you make alloc accept **p, set *p = ..., and pass in &pointer from main, it should work.
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
*p = (int*) malloc (sizeof(int));
if(!*p){
puts("fail\n");
return 0;
}
**p = 4;
printf("%d\n",**p);
return 1;
}
int main() {
int* pointer;
if(!alloc(&pointer)){
return -1;
} else {
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
If you want a function to write to a non-array parameter of type T, you must pass a pointer to that parameter.
void func( T *ptr )
{
*ptr = new_value;
}
void foo ( void )
{
T var;
func( &var ); // writes new value to var
}
If T is a pointer type Q *, it would look like
void func( Q **ptr )
{
*ptr = new_pointer_value;
}
void foo ( void )
{
Q *var;
func( &var ); // writes new pointer value to var
}
If Q is a pointer type R *, you would get
void func( R ***ptr )
{
*ptr = new_pointer_to_pointer_value;
}
void foo ( void )
{
R **var;
func( &var ); // writes new pointer to pointer value to var
}
The pattern is the same in all three cases; you're passing the address of the variable var, so the formal parameter ptr has to have one more level of indirection than the actual parameter var.
One sylistic nit: instead of writing
p = (int *) malloc( sizeof (int) );
use
p = malloc( sizeof *p );
instead.
In C (as of the 1989 standard), you don't need to cast the result of malloc; void pointers can be assigned to other pointer types and vice versa without needing a cast (this is not true in C++, but if you're writing C++, you should be using the new operator instead of malloc anyway). Also, under the 1989 version of the language, using the cast would mask a bug if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. That hasn't been a problem since the 1999 version, though, so now it's more a matter of readability than anything else.
The type of the expression *p is int, so the result of sizeof *p is the same as the result of sizeof (int). This way, if you ever change the type of p, you don't have to modify the malloc call.
To allocate an array of values, you'd use something like
T *p = malloc( sizeof *p * NUM_ELEMENTS );
or, if you want everything to be zeroed out initially, use
T *p = calloc( sizeof *p, NUM_ELEMENTS );

Trying to rewrite realloc function in c

As practice, I'm trying to rewrite realloc function
void updateSize(void* p,int length)
{
free(p);
malloc(sizeof(p) * length);
}
int main(int argc,char* argv[])
{
int *y =malloc(sizeof(int)*3);
y = updateSize(y, 5);
}
But when I try to compile it, I get the following error:
void value not ignored as it ought to be.
What is the reason for this error, and how can i fix it?
OP is not returning a value from function nor copying data as needed.
// Function return value of `void` needs to be `void *`.
// `length` should be of type size_t
// The former length of `p` needs to be passed.
// Potential NULL pointers need testing.
void updateSize(void* p,int length) {
// Missing data copy.
// Allocate new memory and copy before freeing old
free(p);
// Returned value from malloc needs saving.
// No reason for 'sizeof()'
malloc(sizeof(p) * length);
}
// Recommend
void *updateSize2(void* p, size_t OldLength, size_t NewLength) {
void *p2 = malloc(NewLength);
if (p && p2) {
memcpy(p2, p, OldLength < NewLength ? OldLength : NewLength);
}
if (p2 || (NewLength == 0)) {
free(p); // Note A
}
return p2;
}
Note A: There is an interesting issue when NewLength == 0. Some malloc(0) implementations return NULL, others return a pointer to "no data". In the former, a NULL pointer does not always imply a failed malloc(). Now as #sharth rightly points out that free(p) should only be called on memory allocation failure, the if() used here is conditional on NewLength.

Why I've allocated a pointer memory in a function, but it's also NULL?

The code confused me.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void create_int(int *p)
{
p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
You are not passing the pointer value back from the function. Try:
void create_int(int **p) {
*p = (int *) malloc(sizeof(int));
}
int main() {
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
The variable p in the function create_int is a copy of the variable p in main. So any changes made to p in the called function does not get reflected in main.
To make the change get reflected in main you need to either:
Return the changed value:
int* create_int(int *p) {
p = malloc(sizeof(int));
// err checking
return p:
}
...
// in main:
p = create_int(p);
Or pass the address of p as:
void create_int(int **p) {
*p = malloc(sizeof(int));
// err checking
}
...
// in main:
create_int(&p);
You need a pointer to a pointer like this:
void create_int(int **p)
{
*p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
As folks have pointed out, it's failing since you're not actually changing the pointer that the caller has.
A different way to think about the code might be to notice that it's basically wrapping malloc(), i.e. it's doing a memory allocation but with intelligence added. In that case, why not make it have the same prototype (=call signature) as malloc()? That makes it clearer in the caller's context what's going on, and easier to use:
int * create_int(void)
{
return malloc(sizeof (int));
}
int main(void)
{
int *p = create_int();
assert(p != NULL);
return 0;
}
Also, in C you should never cast the return value of malloc() (see Do I cast the result of malloc?).
You need to send a pointer to a pointer to be able to assign a memory to it via a function
void create_int(int **p)
{
*p = (int*)malloc(sizeof_int));
}
int main()
{
int* p = NULL;
create_int(&p);
assert(p != NULL);
return 0;
}
Your code contains two pointers: one in the create_int function and another one in main. When you call create_int, a copy of the pointer in main is made and used, then eliminated when the create_int function returns.
So, any changes you did to the copy within create_int remain there and are not propagated back to main.
The only way to propagate changes between functions in C (aside from, obviously, returning new values) is to pass a pointer to the changed values. This way, while the pointer being passed will be copied, the value that it points to will be the same, so changes will apply.
Since you're trying to change a pointer, you need a pointer-to-pointer.
void create_int(int **pp)
{
// this changes the pointer that `p` points to.
*pp = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
// this sends a pointer to the pointer p in main
create_int(&p);
assert(p != NULL);
return 0;
}

Resources