2010-04-12 17 views
16

que tienen un fallo de segmentación en el código de abajo, pero después de lo cambié a puntero a puntero, que está muy bien. ¿Alguien podría darme alguna razón?por qué se necesita puntero a puntero a asignar memoria en función de

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

que no funciona en la función principal como golpe embargo

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

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

, funciona así.

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; 
} 
+7

Como malloc nunca se arrojará, los intentos de bloques no tienen sentido. –

+0

Esos bloques try no son válidos si esto es C. ¿Es esto realmente C++? Si es así, las etiquetas deben cambiar. –

+0

@Fred, la pregunta también es relevante para ambos C, aunque el fragmento es C++ como usted indicó. Agregué la etiqueta C++ – hhafez

Respuesta

50

Debido a que usted está queriendo obtener un valor de puntero posterior de las operaciones realizadas en la función. malloc asigna memoria y le da una dirección para esa memoria.

En su primer ejemplo, almacena esa dirección en la variable de argumento local p, pero dado que es solo el argumento, eso no vuelve al programa principal, porque C/C++ es pass-by-value de forma predeterminada, incluso para punteros.

Main  Function  malloc 

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

becomes... 

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

y por lo tanto cuando se lee p principal, se pone 0, no A.

En su código de trabajo, se sigue el puntero pasado a una dirección, y que la dirección le da la ubicación de la variable puntero en el programa principal. Actualizar el valor del puntero en esa dirección, que el programa principal, se puede buscar el valor de utilizar como su ubicación en la memoria - pasando así la dirección devuelta por malloc volver al programa principal para su uso.

Main  Function  malloc 

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

becomes... 

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

y por lo tanto cuando se lee principal p, se obtiene A.

+13

+1 para el arte ASCII. 8v) –

+2

Arte ASCII honestamente puede ser divertido a veces ... – Amber

+0

maldita sea ... iba a hacer buenos diagramas de puntero ... no más – Polaris878

7

A puntero almacena la dirección en la que se almacenan los datos. Pasando un puntero a una función significa darle la dirección de los datos . Sin embargo, aquí no tiene dirección para los datos hasta que llame al malloc. Así que en lugar que necesita para pasar la dirección de el puntero (es decir puntero a puntero). Esto permite memory a tomar la dirección del puntero p y establecer p para apuntar a la zona de la memoria se asigna para los datos.

+0

Mucho más claro que el de Dav, aunque parece que ambos están diciendo lo mismo. Ambos obtienen un voto positivo. :) – Dustin

1

El primer ejemplo no funciona debido a que el parámetro de puntero no es el puntero en el principal, que sólo tiene el mismo valor.

0

usted no necesita usar un puntero a puntero, sino un puntero de referencia es decir, un * * & no sólo

3

En C, que tienen sólo pasan por valor. De modo que su memoria de funciones() obtiene su propia copia local de p. malloc inside memory() asigna solo a la copia de p que es local para la función. Cuando memory() vuelve a main(), la copia de p de main no cambia. En C++, a resolver esto mediante el paso por referencia, así:

void memory(int*& p, int size)

en C, se utiliza dobles punteros para lograr resultados similares.

+1

Debería ser '* &'. (Leer desde la derecha. Esta es una de las razones por las que pondría el espacio al revés: 'int * & p' (' int * 'es el tipo al que está haciendo referencia) :) – UncleBens

+0

¿No sería así? be 'int * &' para denotar una referencia a un puntero a un int? La muestra del código es 'int & *', que es un puntero a una referencia a un int, que anula el propósito de una referencia si está pasando un puntero a una referencia. ¿O tal vez estoy malinterpretando ...? – Dustin

+0

@UncleBens, Dustin: Eso fue un error tipográfico, buen truco. También moví el espacio & * al lado del tipo. – kbyrd

2

En su primera llamada a la memoria:

void memory(int * p, int size) 

cuenta de que estás pasando un VALOR a la memoria(), no una dirección. Por lo tanto, está pasando el valor de '0' a la memoria(). La variable p es sólo una copia de todo lo que pasa en ... en contiene el mismo valor, pero hace NO apuntan a la misma dirección ...

En su segunda función, que están pasando el DIRECCIÓN de su argumento ... así que en su lugar, p apunta a la dirección de su variable, en lugar de ser solo una copia de su variable.

Por lo tanto, cuando se llama a malloc así:

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

está asignando el retorno de malloc al valor de la variable que p puntos a.

Por lo tanto, su puntero es válido fuera de la memoria().

0

Necesita un puntero al puntero porque debe devolver el valor del puntero recién asignado.

Hay tres maneras de devolver ese valor (2 si se utiliza C):

  • utilizar un puntero, aquí está un puntero a puntero
  • utilizar una referencia, aquí se trata de una referencia a
  • puntero
  • utilizar el valor de retorno de la función, por lo que la memoria devuelve un int * en lugar de vacío

la tercera vía ha definitivamente mi preferencia.

(y no, no voy a admitir que también puedas usar un global, no es una cuarta forma, sino un horror).

-1

corregí el código .. leer el comentario y todo estará claro ..

#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; 
} 
0

memoria (p, 10); // obtener la dirección del puntero

esto simplemente envíe el valor p no la dirección de la p. envía (* p). si addrees de p 123 y su valor 50 envía 50 a la función.

y en la función de memoria crea un nuevo puntero con nueva dirección como 124 y contiene 50; y asignará la memoria y escribirá el inicio de la memoria asignada en 124, no en 123, así que p en la principal todavía contiene 50. ¡Así que no hizo nada !. Puedes controlar esto con este código.

 #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; 
    } 
Cuestiones relacionadas