c语言数组指针,不报错,就停止工作,请问哪里错了

第一次提问,多包含,也不报错,为什么一运行就按停止工作报错
#include
#include
#include

struct arr
{
int *pbase;//第一个元素的首地址
int len;//数组所能容纳的最大元素个数
int cnt;//当前数组有效元素个数
};

void init_arr(struct arr *p1,int length)
{
(p1->pbase) = (int *)malloc(sizeof(int) * length);//给数组分配空间

if(NULL == (p1->pbase))
{
    printf("分配内存失败!");
    exit(-1);
}
else
{
    p1->len = length;
    p1->cnt = 0;
}
return;

}

bool is_empty(struct arr *p3)
{
if(0 == (p3->cnt))
return true;
else
return false;
}

void show_arr(struct arr *p2)
{
if(is_empty(p2))
{
printf("用户数据为空!");
}
else
{
for(int i=0; i<(p2->cnt); i++)
{
printf("%d ", *((p2->pbase)+i));
}
printf("\n");
}
}

main()
{
struct arr *p;
int j;//数组最大长度

printf("请输入定义的数组的最大长度:");
scanf("%d", &j);
init_arr(p,j);
//init_arr(p,5);
show_arr(p);

}

在数据结构这本书中有类似的结构体调用,创建顺序链表的例子,其中关于这一语句

void init_arr(struct arr *p1,int length)此处似乎应改为void init_arr(struct arr &p1,int length)

不应使用*p1,这样*p1为指向该结构体指针,而是用&p1则为结构体p1的地址,然后调用时应该这样调用init_arr(p1,length),调用时只用p1,因为p1本来就是结构体地址,我们常常通过p1->len来使用数据。
例如
struct data{
int i;
int j;
}p1;

如果有
data *p;

*p=p1;
那么想通过p访问p1中的i就应该
(*p)->i;