感觉插入函数错了 出现Unhandled exception in 1.exe: 0xC0000005: Access Violation

#include
#include
#include

#define OverFlow -1
#define OK 1

typedef struct
{
int coe;
int exp;
}Elemtype;

typedef struct node
{
Elemtype data;
struct node *next;
}PNode,*Linklist;

int Contruct_Tables(Linklist *Head)
{
Linklist p;
p=(Linklist)malloc(sizeof(PNode));
if(p==NULL)
return OverFlow;
p->next=NULL;
*Head=p;
return OK;
}

int Insert_Last(Linklist Head, int n)
{

Elemtype x;
int i=0;
Linklist p,q;
int k=0;
p=(Linklist)malloc(sizeof(PNode));
if(p==NULL)
return OverFlow;
while(i {
printf("输入系数:\n");
scanf("%d",&x.coe);
printf("输入指数:\n");
scanf("%d",&x.exp);
p->data.coe=x.coe;
p->data.exp=x.exp;
q=Head;
while(q->next!=NULL)
{
q=q->next;
}
q->next=p;
i++;
}
return OK;
}

Linklist Add(Linklist Head1,Linklist Head2)
{

Linklist p=Head1;
Linklist q=Head2;
Linklist r;
while(p->next!=NULL)
{
    p=p->next;
}
p->next=q->next;
free(Head2);

p=Head1->next;
while(p->next!=NULL)
{
    while(q->next!=NULL)
    {   
        q=Head1->next;
        r=q;
        q=q->next;
        if(p->data.exp==q->data.exp)
        {p->data.coe=p->data.coe+q->data.coe;
                r->next=q->next;
                free(q);
        }
    }
}
p=p->next;
return Head1;

}

int Show_Linklist(Linklist Head)
{
Linklist p=Head->next;
Linklist q=p;
Linklist r=Head;
while(p->next!=NULL)
{
while(q->next!=NULL)
{
q=q->next;
if(p->data.exp>q->data.exp)
{
p->next=q->next;
q->next=p;
r->next=q;
}
}

    r=r->next;
    p=p->next;
}

p=Head->next;
if(p==NULL);
printf("空表");
while(p!=NULL&&p->next!=NULL)
{
    printf("%dx^%d+",p->data.coe,p->data.exp);
}

if(p!=NULL&&p->next==NULL)
    printf("%dx^%d",p->data.coe,p->data.exp);
return OK;

}

int main()
{

int Contruct_Tables(Linklist *Head);
int Insert_Last(Linklist Head,int n);
Linklist Add(Linklist Head1,Linklist Head2);
int Show_Linklist(Linklist Head);
int n;
int p;
Linklist Head1;
Linklist Head2;

printf("建立表1\n");
Contruct_Tables(&Head1);
printf("输入元素个数:\n");
scanf("%d",&n); 
Insert_Last(Head1,n);
printf("建立表2\n");
Contruct_Tables(&Head2);
printf("输入元素个数:\n");
scanf("%d",&p);
Insert_Last(Head2,p);
Add(Head1,Head2);
Show_Linklist(Add(Head1,Head2));
return OK;

}

p=(Linklist)malloc(sizeof(PNode));之后似乎忘记了p->next = NULL;。在Insert_Last函数中,由malloc分配的新结点插入到了链表的末尾,但 是新结点的next成员没有置NULL,所以程序在“while(q->next!=NULL);”处崩溃。
下面是修改后的代码:

PNode* Find_Last(PNode* first)
{
    PNode* p = first;
    while (p->next != NULL)
    {
        p = p->next;
    }
    return p;
}

int Insert_Last(Linklist Head, int n)
{
    int i;
    Linklist p;
    for(i = 0; i < n; ++i)
    {
        p = (PNode*)malloc(sizeof(PNode));
        if (p == NULL)
            return OverFlow;
        p->next = NULL;             // 建议分配新结点之后,立即初始化next域
        printf("输入系数:\n");
        scanf("%d",&p->data.coe);
        printf("输入指数:\n");
        scanf("%d",&p->data.exp);
        Find_Last(Head)->next = p;
    }
    return OK;
}

两点建议:
1)立即初始化指针变量和指针成员。
2)提炼重复的代码为独立的函数。比如你的代码中,有不止一处查找链表的尾结点,应把这些重复的代码提炼到一个独立的函数中,用一个恰当的函数名描述代码的意图。这样至少有以下一些好处:代码易于阅读,通过函数名理解代码的意图,而不是每次阅读这些重复的代码;代码易于维护,完成同一项任务或一组类似的任务,独立的函数比散布在多个地方的重复代码更易于修改和保持一致性。

多半是指针方面的问题,你不要直接运行,而是调试下,报错的时候停下来看那一行,上面的各个指针变量,哪个无效。