dynamic memory created inside a function [duplicate] - c

This question already has answers here:
C Programming: malloc() inside another function
(9 answers)
Closed 5 years ago.
I would like to know the technical reason(in terms of memory) why this piece of code will not work:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(ptr);
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
void fun(int* ptr)
{
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
}
Why will this not work? I thought that the heap(more importantly the addresses) is common to all the function's variables in the stack .
Also, why would this work.
If i comment the memory allocation inside the function fun and uncomment the one in main . It works fine.

In C, everything is passed by value.
What you are passing to fun() is a copy of the pointer you have in main().
That means the copy of ptr is aimed at the allocated memory, and that memory set to 115.
The ptr in main() still points at an undefined location because it has never been assigned.
Try passing a pointer to the pointer, so that within fun() you have access to the pointer itself:
#include <stdio.h>
#include <stdlib.h>
int* fun(int**); // <<-- CHANGE
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(&ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int** another_ptr) // <<-- CHANGE
{
*another_ptr = (int*)malloc(sizeof(int)); // <<-- CHANGE
**another_ptr = 115; // <<-- CHANGE
return *another_ptr;
}
The other option would be to make fun() actually return the updated pointer (as advertised), and assign this to ptr:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
ptr = fun(ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int* another_ptr)
{
another_ptr = (int*)malloc(sizeof(int));
*another_ptr = 115;
return another_ptr; // <<-- CHANGE
}
Edit: I renamed the variable in fun() to make it clear that it is different from the one you use in main(). Same name doesn't mean anything here.

The fun() function parameter is a copy of the variable you passed into fun(). So when you do:
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
you only change that copy. You should change the function signature:
int* fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and change how you call it accordingly.

You are confused about several things here, but one easy way of writing the function is:
int * fun()
{
int * ptr = (int*)malloc(sizeof(int));
* ptr = 115;
return ptr;
}
You are now responsible for freeing the memory, so in main():
int * ip = fun();
printf( "%d", * ip );
free( ip );
The alternative is to pass the address of apointer (a pointer to a pointer) to the function:
void fun( int ** pp )
{
* pp = (int*)malloc(sizeof(int));
** pp = 115;
}
then your code in main() looks like:
int * ip;
fun( & ip );
printf( "%d", * ip );
free( ip );
I think you can see that the first function is simpler to use.

You need to pass the address of the pointer in main if you want to change it:
fun(&ptr);
(and change fun appropriately, of course)
At the moment, it's changing the local variable ptr inside the function, and of course that change doesn't magically appear anywhere else.

You're passing the ptr by value to fun. fun will recieve a copy of ptr which will be modified. You need to pass ptr as int**.
void fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and call it with:
fun(&ptr);
(I also removed the return value from fun since it wasn't used)

The variable int* ptr is passed by value to the function fun. So the value assigned to ptr inside the function using ptr = (int*)malloc(sizeof(int)); will not be reflected outside the function. So when you do a = *ptr; in main() you are trying to use an un-initialized pointer. If you want to to reflect the changes done to ptr outside the function then you need to change the signature of fun to fun(int** ptr) and do *ptr = (int*)malloc(sizeof(int));

Remember that if you want a function to modify the value of an argument, you must pass a pointer to that argument. This applies to pointer values; if you want a function to modify a pointer value (not what the pointer points to), you must pass a pointer to that pointer:
void fun (int **ptr)
{
/**
* Do not cast the result of malloc() unless you are
* working with a *very* old compiler (pre-C89).
* Doing so will supress a valuable warning if you
* forget to include stdlib.h or otherwise don't have
* a prototype for malloc in scope.
*
* Also, use the sizeof operator on the item you're
* allocating, rather than a type expression; if you
* change the base type of ptr (say from int to long),
* then you don't have to change all the corresponding
* malloc() calls as well.
*
* type of ptr = int **
* type of *ptr = int *
* type of **ptr = int
*/
*ptr = malloc(sizeof **ptr);
*ptr = 115;
}
int main(void)
{
int *p;
fun(&p);
printf("Integer value stored at %p is %d\n", (void *) p, *p);
return 0;
}
BTW, you have a type mismatch in your example; your initial declaration of fun returns an int *, but the definition returns void.

Related

Pointer is "passed by value"?

After calling f() on ptr, I expect it to point to a single byte with value of A.
But instead ptr is copied by value and it is only available in the f function(?)
What am I doing wrong?
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
Thanks!
Yes, it's passed by value. If you want the changes you make to the pointer to be visible at the call site, you need to pass a pointer to the pointer.
Example:
#include <stdlib.h>
#include <stdio.h>
void f(char **ptr) { // pointer to the pointer
*ptr = malloc(1);
if(*ptr) // precaution if malloc should fail
**ptr = 'A';
}
int main(void) {
char *ptr;
f(&ptr); // take the address of `ptr`
if(ptr) // precaution again
printf("%c\n", *ptr); // now fine
free(ptr); // without this, you have a memory leak
}
Or, f() could simply return the pointer.
Form the habit of testing return values.
#include <stdio.h>
#include <stdlib.h>
char *f(void) {
char *ptr = malloc(1);
if( ptr != NULL )
*ptr = 'A';
return ptr;
}
int main() {
char *ptr = f();
if( ptr != NULL )
printf( "%c\n", *ptr );
free( ptr );
}
You might even be able to save some code if you write main() like this:
int main() {
char *ptr;
if( ( ptr = f() ) != NULL )
printf( "%c\n", *ptr ), free( ptr ), ptr = NULL;
/* more code that will see ptr as NULL */
}
And, that leads to this (being inefficient but valid):
int main() {
for( char *ptr = f(); ptr; free( ptr ), ptr = NULL )
printf( "%c\n", *ptr );
}
You are passing the pointer ptr to the function f() by value.
This essentially means that the pointer variable you passed to f() will be copied locally inside f().
Any changes made to the local copy will only affect the local copy and not the original variable you passed to f().
When a variable is passed by value, it's copy can be referenced by whatever the function argument is called.
In your case, the pointer you pass to f() has been copied inside f() and the local copy can be referenced by ptr, since that is the argument name in:
void f(char *ptr)
Now you know how pass by value works you may now understand why your code is erroneous.
In the code:
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
You modify a local copy of what you passed into f() called ptr. And since it is local, it has something called automatic storage duration.
Automatic storage duration essentially means that after the function ends, all local variables will cease to exist and the memory they occupy will be freed. This means your code actually causes a memory leak because the pointer to the memory you allocated is lost.
Solution:
In order to achieve what you want and to modify the pointer called ptr declared in main() you must pass the address of the pointer you want to modify.
This would look like this:
void f(char **ptr)
{
*ptr = malloc(sizeof(char));
if (*ptr == NULL)
{
fprintf(stderr, "malloc fail");
return;
}
**ptr = 'A';
}
int main()
{
char *ptr;
f(&ptr);
printf("%c\n", *ptr);
return 0;
}
Output:
A
Function parameters are its local variables. Changing a local variable has no effect on the argument expression.
You can imagine the function definition and its call the following way
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
void f( /*char* p */ ) {
char *p = ptr;
p = (char*) malloc(1);
*p = 'A';
}
That is the function parameter p (I renamed it to distinguish the parameter and argument in the function call) is initialized by the value of the argument expression and within the function the local variable p that occupies its own extent of memory is changed.
To change the original pointer you need to pass it to the function by reference. In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you get a direct access to the original object.
So the function in your program should be defined the following way
void f(char **ptr) {
*ptr = (char*) malloc(1);
**ptr = 'A';
}
and called like
f( &ptr );
you are passing a address of ptr so this will be copied to the funktion f(),
a smiple solution can be: you make the f(...) return a char* and used in the main: ptr = f(ptr);
Alternatively, you can allocate the memory for ptr where you declare it:
void f(char* ptr) {
*ptr = 'A';
}
int main() {
char* ptr = malloc(1);
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
free(ptr);
}

Memory of two variables are colliding when used malloc

I'm trying to learn the memory allocation in C using malloc and increasing the size of allocated array using realloc inside a function. I came across this. when I use single variable the code is working well. But when I allocate memory for second variable, it gives me weird output.
Code is below:
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
# define N 3
void padd(int *a){
int sizes = 10*sizeof(int);
a = (void *)realloc(a,sizes);
a[0] = 10;
printf("inside func= %d \n",a[0]);
}
int main()
{
int *d;
int *pA;
int size = N*sizeof(int);
pA = (void *)malloc(size);
//d = (int *)malloc(size);
padd(pA);
printf("outside func= %d",pA[0]);
}
it gives me output:
inside func= 10
outside func= 10
but if I uncomment the //d = (int *)malloc(size); line, It gives me
inside func= 10
outside func= -1368048824
as output.
What might be wrong here?
If realloc can’t extend a buffer in place, it will allocate a new buffer, copy the contents of the old buffer to it, free the old buffer, and return the address of the new buffer (or NULL if it cannot satisfy the request); thus, the value of a can change in padd. However, that change is only applied to the formal parameter a - the actual parameter pA is not affected.
Based on the behavior, it looks like that if you allocate d, it’s allocated immediately after pA such that pA can’t be extended in place, so realloc is creating a new buffer and deallocating the old one, and the old buffer is overwritten before the printf statement in main.
You’ll want to write padd such that any changes to a are reflected in pA - either return the (potentially new) value of a or pass a pointer to pA:
void padd( int **a )
{
size_t sizes = 10 * sizeof (int); // see note 1
int *tmp = realloc( *a, sizes ); // see note 2
if ( tmp )
{
*a = tmp;
(*a)[0] = 10;
printf( "Inside func, (*a)[0] = %d\n", (*a)[0] );
}
else
{
printf ( "Inside func, realloc failed!\n" );
}
}
and you’d call it as
padd( &pA );
Note 1: sizeof has type size_t, not int.
Note 2: Since realloc can potentially return NULL, always assign the result to a temporary value and check it before assigning back to the original variable, otherwise you run the risk of losing access to memory you’ve already allocated. Also, the cast to void * is unnecessary and confusing since you’re assigning the result to an int * variable. Unless you’re compiling this code as C++ or under an ancient K&R C compiler, just leave the cast off completely - otherwise, your cast has to match the type of the thing you’re assigning to, which in this case is int *.
You should either get the new pointer back from padd:
int * padd(int * a){
int sizes = 10*sizeof(int);
a = (void *)realloc(a,sizes);
a[0] = 10;
printf("inside func= %d \n",a[0]);
return a;
}
//...
int main()
{
//...
pA = padd(pA);
//...
}
Or pass a pointer to the pointer:
void padd(int **pA){
int *a = *pA;
int sizes = 10*sizeof(int);
a = (void *)realloc(a,sizes);
a[0] = 10;
printf("inside func= %d \n",a[0]);
*pA = a;
}
//...
int main()
{
//...
padd(&pA);
//...
}
The both your programs have undefined behavior.
The function parameter a
void padd(int *a)
is a local variable of the function that is initialized by the value of the pointer pA used as a function argument in the function call
padd(pA);
You can imagine the function definition and its call the following way
padd(pA);
//...
void padd( /* int *a */ ){
int *a = pA;
int sizes = 10*sizeof(int);
a = (void *)realloc(a,sizes);
a[0] = 10;
printf("inside func= %d \n",a[0]);
}
So as it is seen changing the local variable a within the function padd does not influence on the value stored in the pointer pA because the function deals with a copy of the value of the pointer pA.
To change the original pointer pA within the function you need to pass it to the function by reference.
In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you will get a direct access to the object.
The function should be declared and defined the following way
int padd( int **a ){
int sizes = 10*sizeof(int);
int *tmp = realloc( *a, size );
int success = tmp != NULL;
if ( success )
{
*a = tmp;
( *a )[0] = 10;
// or **a = 10;
printf("inside func= %d \n", ( *a )[0] );
}
return success;
}
And the function can be called like
if ( padd( &pA () ) printf("outside func= %d",pA[0]);
Pay attention to that to call realloc you should use an intermediate variable because in general the function can return a null pointer. So reassigning the original pointer with a null pointer results in the original value of the pointer will be lost.
Also you should free all the dynamically allocated memory when it is not needed any more
free( pA );

Pointer manipulation inside function

Let's say I have a pointer pointing to memory
0x10000000
I want to add to it so it traverses down memory, for example:
0x10000000 + 5 = 0x10000005
How would I do this inside a function? How would I pass in the address that the pointer points to, and inside the function add 5 to it, then after the function's complete, I can use that value?
You have two options:
The function can return the updated pointer.
char *f(char *ptr) {
ptr += 5;
return ptr;
}
The caller then does:
char *p = some_initialization;
p = f(p);
The function argument can be a pointer to a pointer, which it indirects through:
void f(char **ptr_ptr) {
*ptr += 5;
}
The caller then does:
char *p = some_initialization;
f(&p);
Basically, like what everyone else as said you have to pass the pointer by reference(that is a pointer to a pointer aka double pointer) to the function.
#include<stdio.h>
void IncrementAddress(void **addr)
{
int offset=5;//give what ever value you want
*addr = *addr + offset;
printf("%d\n",*addr);
}
int main()
{
char x;// or any other data type like int x or float x etc.
void *ptr=NULL;
ptr = &x;
printf("%d\n",ptr);
IncrementAddress(&ptr);
printf("%d\n",ptr);
return 0;
}

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

Returning a pointer from a function

This is in reference to this question: Why is a pointer to pointer needed to allocate memory in this function?
The answer to the question explained why this didn't work:
void three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
}
void main()
{
int *p = 0;
three(p);
printf("%d", *p);
}
... but this works:
void three(int ** p)
{
*p = (int *) malloc(sizeof(int));
**p = 3;
}
void main()
{
int *p = 0;
three(&p);
printf("%d", *p);
}
This also works, by returning a pointer from the function. Why is that?
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
return p;
}
void main()
{
int *p = 0;
p = three(p);
printf("%d", *p);
}
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
Because here you're returning a copy of the pointer p and this pointer now points to valid memory, which contains the value 3.
You originally passed in a copy of your p as an argument, so you're not changing the one you passed in, but a copy. Then you return that copy, and assign it.
From the comment, which is a very valid point, this will also work just as well:
int* three()
{
//no need to pass anything in. Just return it.
int * p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
They're completely different (and if you truly understand why the first works, you'd see there's no connection).
By returning, you're not attempting to modify the already existing pointer from inside the function. You're just returning a new pointer, and assigning its value outside.
Look at it as a question of scope.
In main() you have a pointer p.
int *p = 0;
p in main is set to NULL. When you make a call to the three function passing it p:
three(p);
You are passing a pointer to NULL. What happens to it is outside the scope of main(). main() does not know, nor does it care what happens. main() only cares about its copy of p, which at this point is still set to NULL.
Unless I reassign p within the scope of main() (including handing off the address of p), p is still just a pointer pointing to NULL.
If I give you this code:
void main()
{
int *p = 0;
funcX(p);
printf("%d",*p);
}
You can tell me definitively what is going to happen (Segmentation fault) without ever knowing what funcX() does because we're passing a copy of the pointer to this function, but a copy doesn't affect the original.
But if I give you this code:
void main()
{
int *p = 0;
funcX(&p);
printf("%d",*p);
}
You can't tell me what will happen unless you know what funcX() is doing.
That make sense?

Resources