Meu código trava e fecha

#include <stdio.h>
#include <stdlib.h>

typedef struct cel{
    int conteudo;
    struct celula *prox;
}celula;


celula *cria(void){
    return NULL;
}

celula *InsereInicio(int x,celula *p){
    celula *inserir;
    inserir = malloc(sizeof(celula));
    inserir->conteudo = x;
    inserir->prox = p;
    p = inserir;
    return p;
}

void InsereMeio(int x, celula *p){
    celula *inserir;
    inserir = malloc(sizeof(celula));
    inserir->conteudo = x;
    inserir->prox = p->prox;
    p->prox = inserir;
}

void InsereFim(int x, celula *p){
    celula *inserir;
    inserir = malloc(sizeof(celula));
    inserir->conteudo = x;
    inserir->prox = p->prox;
    p->prox = inserir;
}

void Imprimir(celula *p){
    celula *imprimir;

    for(imprimir = p; imprimir != NULL; imprimir = imprimir->prox){
        printf("END M: %p   -  VALOR: %d   - PROX END: %p \n\n",imprimir,imprimir->conteudo,imprimir->prox);
    }
}

int main(){
    int escolha,valor;
    celula *ini;

    while(escolha != -1){
        printf("CRIAR LISTA ............ 1\n");
        printf("INSERIR NO INICIO ...... 2\n");
        printf("INSERIR NO MEIO ........ 3\n");
        printf("INSERIR NO FIM ......... 4\n");
        printf("IMPRIMIR ............... 5\n");

        scanf("%d",&escolha);

        switch(escolha){
        case 1:
            ini = cria();
            break;
        case 2:
            printf("DIGITE O VALOR A SER INSERIDO NO INICIO\n");
            scanf("%d",valor);
            InsereInicio(valor,ini);
            break;
        case 3:
            printf("DIGITE O VALOR A SER INSERIDO NO MEIO\n");
            scanf("%d",valor);
            InsereMeio(valor,ini);
            break;
        case 4:
            printf("DIGITE O VALOR A SER INSERIDO NO FIM\n");
            scanf("%d",valor);
            InsereFim(valor,ini);
            break;
        case 5:
            Imprimir(ini);
            break;
        }

    }
}