por que ponteiro para ponteiro é necessário para alocar memória na função

Eu tenho uma falha de segmentação no código abaixo, mas depois que eu mudei para ponteiro para ponteiro, tudo bem. Alguém poderia me dar algum motivo?

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

não funciona na função principal como golpe

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

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

no entanto, funciona assim.

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

questionAnswers(3)

yourAnswerToTheQuestion