tags:

views:

212

answers:

7

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.

+1  A: 

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.

Anon.
+3  A: 

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.

sharptooth
@sharptooth: Yes it will be a pass-by-value in the case where malloc is inside the fun(). But it would still be a pass-by-value if the malloc is made in main(). Could you please tell me why one would work and one wont ?
tomkaith13
Because in one, you initialize the pointer to point to the right memory, then copy the pointer, and set what the copy points to to 115. In the other, you copy the uninitialized pointer, initialize the copy to point to the right memory, and set what the copy points to to 115. The difference in the second case is that **the original pointer is still uninitialized**
Anon.
A: 

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)

Andreas Brinck
@Andreas:Yes it will be a pass-by-value in the case where malloc is inside the fun(). But it would still be a pass-by-value if the malloc is made in main(). Could you please tell me why one would work and one wont ?
tomkaith13
A: 

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

Naveen
+12  A: 

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.

DevSolar
@Devsolar: Yes it will be a pass-by-value in the case where malloc is inside the fun(). But it would still be a pass-by-value if the malloc is made in main(). Could you please tell me why one would work and one wont ?
tomkaith13
***Everything*** is pass by value! Re-read the first line.
Alex
In your code: Let's say you would initialize `ptr` in main(), to 0x12345678 or whatever. Your commented-out line calls `malloc()` and assign its return value to `ptr`, making it point to the memory location allocated by `malloc().` -- Your function `fun()`, in contrast, receives a **copy** of `ptr` (pointing to 0x12345678), calls `malloc()`, assigns its return value to the copy of `ptr`, and returns. (Erroneously without returning the `int*` as advertised.) After the function returns, you are again working on the *real* `ptr` - which still points to 0x12345678...
DevSolar
See also updated answer.
DevSolar
@DevSolar: Wow , I forgot completely abt the return statement. Sorry abt that ... And thanks a lot. I was hell-bent on finding the answer without using double pointers.
tomkaith13
+1  A: 

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.

anon
A: 

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.

John Bode