views:

429

answers:

9

Hi

I have a segmentation fault in the code below, but after I changed it to pointer to pointer, it is fine. Could anybody give me any reason?

void memory(int * p, int size) {
    try {
        p = (int *) malloc(size*sizeof(int));
    } catch( exception& e) {
        cout<<e.what()<<endl;   
    }
}

it does not work in the main function as blow

int *p = 0;
memory(p, 10);

for(int i = 0 ; i < 10; i++)
    p[i] = i;

however, it works like this .

void memory(int ** p, int size) {               `//pointer to pointer`
    try{
        *p = (int *)    malloc(size*sizeof(int));
    } catch( exception& e) {
        cout<<e.what()<<endl;   
    }
}

int main()
{
    int *p = 0;
    memory(&p, 10);       //get the address of the pointer

    for(int i = 0 ; i < 10; i++)
        p[i] = i;

    for(int i = 0 ; i < 10; i++)
        cout<<*(p+i)<<"  ";

    return 0;
}
+26  A: 

Because you're wanting to get a pointer value back from the operations done in the function. malloc allocates memory and gives you an address for that memory.

In your first example, you store that address in the local argument variable p, but since it's just the argument, that doesn't make it back to the main program, because C/C++ are pass-by-value by default - even for pointers.

Main      Function      malloc

  p         p            allocated
+---+     +---+         
| 0 |     | 0 |           A
+---+     +---+

becomes...

  p         p            allocated
+---+     +---+         
| 0 |     | ------------> A
+---+     +---+

and thus when main reads p, it gets 0, not A.

In your working code, you follow the pointer passed to an address, and that address gives you the location of the pointer variable in the main program. You update the pointer value at that address, which the main program can then look up the value of to use as its memory location - thus passing the address returned by malloc back to the main program for use.

Main      Function      malloc

  p         p            allocated    
+---+     +---+         
| 0 |<------- |           A
|   |     |   |
+---+     +---+

becomes...

  p         p            allocated    
+---+     +---+         
|   |<------- |           
| ----------------------> A
+---+     +---+

and thus when main reads p, it gets A.

Amber
+1 for the ASCII art. 8v)
Fred Larson
ASCII art can honestly be fun sometimes...
Amber
damnit... i was going to make nice pointer diagrams... not any more
Polaris878
+6  A: 

A pointer stores the address at which the data is stored. Passing a pointer to a function means giving it the address of the data. However, here you have no address for the data until calling malloc. So instead you need to pass the address of the pointer (i.e. pointer to pointer). This allows memory to take the address of the pointer p and set p to point to the area of memory it allocates for the data.

Arkku
Much clearer than Dav's, though it seems you're both saying the same thing. You both get an up-vote. :)
Dustin
+1  A: 

The first example does not work because the pointer parameter is not the pointer in main, it just holds the same value.

James Morris
A: 

you dont need to use a pointer to pointer but a referenced pointer ie a * & not just *

yan bellavance
+2  A: 

In C, you have only pass-by-value. So your function memory() gets it own local-only copy of p. malloc inside memory() assigns only to the copy of p that is local to the function. When memory() returns to main(), the copy of p from main is unchanged. In C++, you solve this by using pass-by-reference, like this:

void memory(int*& p, int size)

In C, you use double pointers to achieve similar results.

kbyrd
UncleBens
Dustin
kbyrd
+2  A: 

In your first call to memory:

void memory(int * p, int size)

Realize that you are passing a VALUE to memory(), not an address. Hence, you are passing the value of '0' to memory(). The variable p is just a copy of whatever you pass in... in contains the same value but does NOT point to the same address...

In your second function, you are passing the ADDRESS of your argument... so instead, p points to the address of your variable, instead of just being a copy of your variable.

So, when you call malloc like so:

*p = (int *)    malloc(size*sizeof(int));

You are assigning malloc's return to the value of the variable that p points to.

Thus, your pointer is then valid outside of memory().

Polaris878
A: 

You need a pointer to pointer because you need to return the value of the newly allocated pointer.

There is three ways to return that value (2 if you use C):

  • use a pointer, here it is a pointer to pointer
  • use a reference, here it is a reference to pointer
  • use the return value of the function, so make memory return a int * instead of void

The third way has definitely my preference.

(and not, I won't admit you could also use a global, it's not a fourth way but an horror).

kriss
A: 

i corrected the code.. read the comment and all will be clear..

#include<iostream>
#include<conio.h>
#include<exception>

using namespace std;


void memory(int* p, int size) {               //pointer to pointer` not needed
    try{
        p = new int[size] ;
    } catch(bad_alloc &e) {
       cout<<e.what()<<endl;   
    }
}

int main()
{
    // int *p = 0;  wrong .. no memory assigned and then u are passing it to a function
    int *p;
    p = new int ;  // p = malloc( sizeof(int));
    /*before using a pointer always allocate it memory else
     you ll get frequent system crashes and BSODs*/
    memory(p, 10);       //get the address of the pointer

    for(int i = 0 ; i < 10; i++)
        p[i] = i;

    for(int i = 0 ; i < 10; i++)
        cout<<*(p+i)<<"  ";

    getch();    
    return 0;
}
sp3tsnaz
A: 

memory(p, 10); //get the address of the pointer

this just send the p value not the adress of the p. it sends (*p). if addrees of p 123 and its value 50 it send 50 to the function.

and at the memory function it makes a new pointer with new adress like 124 and it contains 50; and it will allocate the memory and write the start of the allocated memory to 124 not 123 so p at the main still contains 50. So you did nothing!. You can control this with this code.

     #include<iostream>
    #include<conio.h>
    #include<exception>

    using namespace std;


    void memory(int* p, int size) {               //*************pointer to pointer` is a must**********
        try{
            p = new int[size] ;
            p[0]=100;
        } catch(bad_alloc &e) {
           cout<<e.what()<<endl;   
        }
    }

    int main()
    {
         int *p = 0;  ******you can do you should do this*******
        p = new int ; 
/* p = malloc( sizeof(int)); // this just change the value inside of p it is unnecessary 
and you will lose a adress from memory :) and possibly it will be unsafe if you free p may, you just 
free one adress*/
        /*before using a pointer always allocate it memory else
         you ll get frequent system crashes and BSODs*/
        memory(p, 10);       //get the address of the pointer//you are getting nothing
        cout <<p[0];
        //we set p[0] to 100 but it will write a garbage value here. 
        //because the value inside of p didn't change at the memory function
        //we sent just the value inside of p.

        getch();    
        return 0;
    }
fenerista