por qué se necesita puntero a puntero para asignar memoria en función

Tengo un error de segmentación en el código a continuación, pero después de cambiarlo a puntero a puntero, está bien. ¿Alguien podría darme alguna razón?

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

no funciona en la función principal como golpe

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

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

Sin embargo, 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;
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta