代码运行错误,求改正

我是用的是VS2019
错误是 使用了可能未初始化的本地指针变量fp
指针乱指,应该怎样修改呢
以下是我的代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
struct student1//学生信息结构体
{
    char name[10];//姓名
    int  num;//学号
    int  grade[4];//语文 数学 英语
};
struct student2//单链表节点定义
{
    struct student1 data;//单链表数据域,用于存储学生信息。
    struct student2 *next;//指针域
};
/* struct student3
{
char name[10];//姓名
int  num;//学号
int  grade[4];//语文 数学 英语
};
struct student4//单链表节点定义
{
struct student3 data1;//单链表数据域,用于存储学生信息。
struct student3 data2;//指针域
};*/
struct student2 *creat(struct student2 *head)//建立单链表,输入学生信息
{
    struct student2 *p1, *p2;
    int a = 0, b = 1, c;
    char str1[15] = { "studenta.txt" };
    char str2[15] = { "studentb.txt" };
    char ch = ' ';
    FILE *fp;
    p1 = p2 = (struct student2*)malloc(sizeof(struct student2));//申请空间
    while (a <= 0)
    {
        printf("请输入您要输入的学生人数:");
        scanf("%d", &a);
        if (a <= 0)
            printf("输入有误,请重新输入!\n");
    }
    printf("1.studenta.txt文件\n2.studentb.txt\n");
    printf("请选择您要保存的文件:");
    scanf("%d", &c);
    {
        if (c == 1)
            fp = fopen(str1, "w+");
        else if (c == 2)
            fp = fopen(str2, "w+");
    }
    printf("请输入第%d学生的姓名:", b);
    scanf("%s", &(p1->data.name));
    fputs((p1->data.name), fp);//将字符串读入文件
    fputc(ch, fp);//向文件写入一个空格字符
    printf("请输入第%d个学生的学号:", b);
    scanf("%d", &(p1->data.num));
    fprintf(fp, "%d", (p1->data.num));
    fputc(ch, fp);
    printf("请输入第%d学生的语文成绩:", b);
    scanf("%d", &(p1->data.grade[0]));
    fprintf(fp, "%d", (p1->data.grade[0]));
    fputc(ch, fp);
    printf("请输入第%d学生的数学成绩:", b);
    scanf("%d", &(p1->data.grade[1]));
    fprintf(fp, "%d", (p1->data.grade[1]));
    fputc(ch, fp);
    printf("请输入第%d学生的英语成绩:", b);
    scanf("%d", &(p1->data.grade[2]));
    fprintf(fp, "%d", (p1->data.grade[2]));
    fputc(ch, fp);
    (p1->data.grade[3]) = ((p1->data.grade[0]) + (p1->data.grade[1]) + (p1->data.grade[2]));
    fprintf(fp, "%d", (p1->data.grade[3]));
    fprintf(fp, "\n");
    printf("%s的总成绩为:%d\n", (p1->data.name), (p1->data.grade[3]));
    b++;
    p1->next = NULL;
    while (b <= (a + 1))
    {
        if (head == NULL)
            head = p1;/*空表,接入表头*/
        else
            p2->next = p1;/*非空表,接到表尾*/
        p2 = p1;
        if (b != a + 1)
        {
            p1 = (struct student2*)malloc(sizeof(struct student2));
            printf("请输入第%d学生的姓名:", b);
            scanf("%s", &(p1->data.name));
            fputs((p1->data.name), fp);//将字符串读入文件
            fputc(ch, fp);//向文件写入一个空格
            printf("请输入第%d个学生的学号:", b);
            scanf("%d", &(p1->data.num));
            fprintf(fp, "%d", (p1->data.num));
            fputc(ch, fp);
            printf("请输入第%d学生的语文成绩:", b);
            scanf("%d", &(p1->data.grade[0]));
            fprintf(fp, "%d", (p1->data.grade[0]));
            fputc(ch, fp);
            printf("请输入第%d学生的数学成绩:", b);
            scanf("%d", &(p1->data.grade[1]));
            fprintf(fp, "%d", (p1->data.grade[1]));
            fputc(ch, fp);
            printf("请输入第%d学生的英语成绩:", b);
            scanf("%d", &(p1->data.grade[2]));
            fprintf(fp, "%d", (p1->data.grade[2]));
            fputc(ch, fp);
            (p1->data.grade[3]) = ((p1->data.grade[0]) + (p1->data.grade[1]) + (p1->data.grade[2]));
            fprintf(fp, "%d", (p1->data.grade[3]));
            fprintf(fp, "\n");
            printf("%s的总成绩为:%d\n", (p1->data.name), (p1->data.grade[3]));
            p1->next = NULL;
            b++;
        }
        else break;
    }
    fclose(fp);
    return head;
}
 
void printLinkList(struct student2 *head)//输出学生信息
{
    struct student2 *temp;
    temp = head;//取得链表的头指针
    printf("姓名      学号  语文 数学 英语 总分\n");
    while (temp != NULL)//只要是非空表
    {
        printf("%s          %d       %d          %d       %d        %d      \n", (temp->data.name), (temp->data.num), (temp->data.grade[0]), (temp->data.grade[1]), (temp->data.grade[2]), (temp->data.grade[3]));//输出链表节点的值
        temp = temp->next;///跟踪链表增长
    }
}
 
void find(struct student2 *head)
{
    int b;
    struct student2 *p;
    printf("请输入您要查找的学生的学号:");
    scanf("%d", &b);
    p = head;
    while (p != NULL)
    {
        if (b == p->data.num)
        {
            printf("%s           %d       %d          %d       %d        %d      \n", (p->data.name), (p->data.num), (p->data.grade[0]), (p->data.grade[1]), (p->data.grade[2]), (p->data.grade[3]));//输出链表节点的值
            break;
        }
        else
            p = p->next;
    }
}
 
 
void display(struct student2 *head)
{
    struct student2 *temp;
    FILE *fp;
    char ch = ' ';
    fp = fopen("student4.txt", "w+");
    temp = head;//取得链表的头指针
    printf("姓名      学号  语文 数学 英语 总分\n");
    while (temp != NULL)//只要是非空表
    {
        if (((temp->data.grade[0])<60) || ((temp->data.grade[1])<60) || ((temp->data.grade[2])<60))
        {
            printf("%s           %d       %d          %d       %d        %d      \n", (temp->data.name), (temp->data.num), (temp->data.grade[0]), (temp->data.grade[1]), (temp->data.grade[2]), (temp->data.grade[3]));//输出链表节点的值
            fputs((temp->data.name), fp);//将字符串读入文件
            fputc(ch, fp);//向文件写入一个空格
 
            fprintf(fp, "%d", (temp->data.num));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[0]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[1]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[2]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[3]));
            fputc(ch, fp);
 
        }
        temp = temp->next;
    }
    fclose(fp);
}
 
void merge(struct student2 *head)
{
    char a, b;
    FILE *fpA = fopen("studenta.txt ", "r "); //A文件
    FILE *fpB = fopen("studentb.txt ", "r "); //B文件,两个作为输入文件,内容有序
    FILE *fpout = fopen("studnetc.txt ", "w "); //输出文件,三个文件都在当前目录下
    a = fgetc(fpA);
    b = fgetc(fpB);
    while (a != EOF && b != EOF) //循环读取并根据比较结果写文件,之后读取新的数据
    {
        if (a <b) //假设是升序,如果是降序使用 > 即可
        {
            fputc(a, fpout);
            a = fgetc(fpA);
        }
        else
        {
            fputc(b, fpout);
            b = fgetc(fpB);
        }
    }
    while (a != EOF) //继续读取没有操作的数据
    {
        fputc(a, fpout);
        a = fgetc(fpA);
    }
    while (b != EOF)
    {
        fputc(b, fpout);
        b = fgetc(fpB);
    }
    fclose(fpA);
    fclose(fpB);
    fclose(fpout);
    printf("合并成功,请在studentc文件中查看!\n");
}
void sort(struct student2 *head)
{
    struct student2 *newNode = (struct student2*)malloc(sizeof(struct student2));
    newNode->next = NULL;
    while (head)
    {
        struct student2 *current = head;
        struct student2 *pre = head;
        struct student2 *preMin = head;
        struct student2 *min = head;
        while (current)
        {
            if (current->data.grade[3] < min->data.grade[3])
            {
                preMin = pre;
                min = current;
            }
            pre = current;
            current = current->next;
        }
        if (min == head)
        {
            head = head->next;
            min->next = newNode->next;
            newNode->next = min;
        }
        else
        {
            preMin->next = min->next;
            min->next = newNode->next;
            newNode->next = min;
        }
    }
    head = newNode->next;
    free(newNode);
    newNode = head;
    while (newNode)
    {
        printf("%s %d %d %d %d %d\n",newNode->data.name,newNode->data.num,newNode->data.grade[0],newNode->data.grade[1],newNode->data.grade[2],newNode->data.grade[3]);
        newNode = newNode->next;
    }
    
}
 
void main()
{
    int i = 0;
    struct student2 *head = NULL;
    struct student2 *creat();
    void printLinkList();
    printf(" -------------------------------------------------\n");
    printf("|   ***欢迎使用西安工程大学学生成绩管理系统***    |\n");
    printf("|                                                 |\n");
    printf("|       1.建立学生成绩单                          |\n");
    printf("|       2.显示学生成绩单                          |\n");
    printf("|       3.查找学生成绩                            |\n");
    printf("|       4.按总成绩进行排序并显示                  |\n");
    printf("|       5.显示需要补考的学生信息并存入新文件4     |\n");
    printf("|       6.合并学生成绩单1和2存入新的成绩单3中     |\n");
    printf("|       7.退出系统                                |\n");
    printf("|                                                 |\n");
    printf(" -------------------------------------------------\n");
    while (i != 6)
    {
        printf("请选择您需要的操作:");
        scanf("%d", &i);
        if (i <= 0 || i>6)
            printf("输入有误,请重新输入!\n");
        else if (i == 1)
        {
            head = NULL;
            head = creat(head);
        }
        else if (i == 2)
            printLinkList(head);
        else if (i == 3)
            find(head);
        else if (i == 4)
            sort(head);
        else if (i == 5)
            display(head);
        else if (i == 6)
            merge(head);
        else
            printf("退出系统成功!!!\n");
    }
}



#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
struct student1//学生信息结构体
{
    char name[10];//姓名
    int  num;//学号
    int  grade[4];//语文 数学 英语
};
struct student2//单链表节点定义
{
    struct student1 data;//单链表数据域,用于存储学生信息。
    struct student2* next;//指针域
};
/* struct student3
{
char name[10];//姓名
int  num;//学号
int  grade[4];//语文 数学 英语
};
struct student4//单链表节点定义
{
struct student3 data1;//单链表数据域,用于存储学生信息。
struct student3 data2;//指针域
};*/
struct student2* creat(struct student2* head)//建立单链表,输入学生信息
{
    struct student2* p1, * p2;
    int a = 0, b = 1, c;
    char str1[15] = { "studenta.txt" };
    char str2[15] = { "studentb.txt" };
    char ch = ' ';
    FILE* fp;
    p1 = p2 = (struct student2*)malloc(sizeof(struct student2));//申请空间
    while (a <= 0)
    {
        printf("请输入您要输入的学生人数:");
        scanf("%d", &a);
        if (a <= 0)
            printf("输入有误,请重新输入!\n");
    }
    printf("1.studenta.txt文件\n2.studentb.txt\n");
    printf("请选择您要保存的文件:");
    scanf("%d", &c);
    if (c == 1)
        fp = fopen(str1, "w+");
    else
        fp = fopen(str2, "w+");
    printf("请输入第%d学生的姓名:", b);
    scanf("%s", &(p1->data.name));
    fputs((p1->data.name), fp);//将字符串读入文件
    fputc(ch, fp);//向文件写入一个空格字符
    printf("请输入第%d个学生的学号:", b);
    scanf("%d", &(p1->data.num));
    fprintf(fp, "%d", (p1->data.num));
    fputc(ch, fp);
    printf("请输入第%d学生的语文成绩:", b);
    scanf("%d", &(p1->data.grade[0]));
    fprintf(fp, "%d", (p1->data.grade[0]));
    fputc(ch, fp);
    printf("请输入第%d学生的数学成绩:", b);
    scanf("%d", &(p1->data.grade[1]));
    fprintf(fp, "%d", (p1->data.grade[1]));
    fputc(ch, fp);
    printf("请输入第%d学生的英语成绩:", b);
    scanf("%d", &(p1->data.grade[2]));
    fprintf(fp, "%d", (p1->data.grade[2]));
    fputc(ch, fp);
    (p1->data.grade[3]) = ((p1->data.grade[0]) + (p1->data.grade[1]) + (p1->data.grade[2]));
    fprintf(fp, "%d", (p1->data.grade[3]));
    fprintf(fp, "\n");
    printf("%s的总成绩为:%d\n", (p1->data.name), (p1->data.grade[3]));
    b++;
    p1->next = NULL;
    while (b <= (a + 1))
    {
        if (head == NULL)
            head = p1;/*空表,接入表头*/
        else
            p2->next = p1;/*非空表,接到表尾*/
        p2 = p1;
        if (b != a + 1)
        {
            p1 = (struct student2*)malloc(sizeof(struct student2));
            printf("请输入第%d学生的姓名:", b);
            scanf("%s", &(p1->data.name));
            fputs((p1->data.name), fp);//将字符串读入文件
            fputc(ch, fp);//向文件写入一个空格
            printf("请输入第%d个学生的学号:", b);
            scanf("%d", &(p1->data.num));
            fprintf(fp, "%d", (p1->data.num));
            fputc(ch, fp);
            printf("请输入第%d学生的语文成绩:", b);
            scanf("%d", &(p1->data.grade[0]));
            fprintf(fp, "%d", (p1->data.grade[0]));
            fputc(ch, fp);
            printf("请输入第%d学生的数学成绩:", b);
            scanf("%d", &(p1->data.grade[1]));
            fprintf(fp, "%d", (p1->data.grade[1]));
            fputc(ch, fp);
            printf("请输入第%d学生的英语成绩:", b);
            scanf("%d", &(p1->data.grade[2]));
            fprintf(fp, "%d", (p1->data.grade[2]));
            fputc(ch, fp);
            (p1->data.grade[3]) = ((p1->data.grade[0]) + (p1->data.grade[1]) + (p1->data.grade[2]));
            fprintf(fp, "%d", (p1->data.grade[3]));
            fprintf(fp, "\n");
            printf("%s的总成绩为:%d\n", (p1->data.name), (p1->data.grade[3]));
            p1->next = NULL;
            b++;
        }
        else break;
    }
    fclose(fp);
    return head;
}

void printLinkList(struct student2* head)//输出学生信息
{
    struct student2* temp;
    temp = head;//取得链表的头指针
    printf("姓名      学号  语文 数学 英语 总分\n");
    while (temp != NULL)//只要是非空表
    {
        printf("%s          %d       %d          %d       %d        %d      \n", (temp->data.name), (temp->data.num), (temp->data.grade[0]), (temp->data.grade[1]), (temp->data.grade[2]), (temp->data.grade[3]));//输出链表节点的值
        temp = temp->next;///跟踪链表增长
    }
}

void find(struct student2* head)
{
    int b;
    struct student2* p;
    printf("请输入您要查找的学生的学号:");
    scanf("%d", &b);
    p = head;
    while (p != NULL)
    {
        if (b == p->data.num)
        {
            printf("%s           %d       %d          %d       %d        %d      \n", (p->data.name), (p->data.num), (p->data.grade[0]), (p->data.grade[1]), (p->data.grade[2]), (p->data.grade[3]));//输出链表节点的值
            break;
        }
        else
            p = p->next;
    }
}


void display(struct student2* head)
{
    struct student2* temp;
    FILE* fp;
    char ch = ' ';
    fp = fopen("student4.txt", "w+");
    temp = head;//取得链表的头指针
    printf("姓名      学号  语文 数学 英语 总分\n");
    while (temp != NULL)//只要是非空表
    {
        if (((temp->data.grade[0]) < 60) || ((temp->data.grade[1]) < 60) || ((temp->data.grade[2]) < 60))
        {
            printf("%s           %d       %d          %d       %d        %d      \n", (temp->data.name), (temp->data.num), (temp->data.grade[0]), (temp->data.grade[1]), (temp->data.grade[2]), (temp->data.grade[3]));//输出链表节点的值
            fputs((temp->data.name), fp);//将字符串读入文件
            fputc(ch, fp);//向文件写入一个空格

            fprintf(fp, "%d", (temp->data.num));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[0]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[1]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[2]));
            fputc(ch, fp);
            fprintf(fp, "%d", (temp->data.grade[3]));
            fputc(ch, fp);

        }
        temp = temp->next;
    }
    fclose(fp);
}

void merge(struct student2* head)
{
    char a, b;
    FILE* fpA = fopen("studenta.txt ", "r "); //A文件
    FILE* fpB = fopen("studentb.txt ", "r "); //B文件,两个作为输入文件,内容有序
    FILE* fpout = fopen("studnetc.txt ", "w "); //输出文件,三个文件都在当前目录下
    a = fgetc(fpA);
    b = fgetc(fpB);
    while (a != EOF && b != EOF) //循环读取并根据比较结果写文件,之后读取新的数据
    {
        if (a < b) //假设是升序,如果是降序使用 > 即可
        {
            fputc(a, fpout);
            a = fgetc(fpA);
        }
        else
        {
            fputc(b, fpout);
            b = fgetc(fpB);
        }
    }
    while (a != EOF) //继续读取没有操作的数据
    {
        fputc(a, fpout);
        a = fgetc(fpA);
    }
    while (b != EOF)
    {
        fputc(b, fpout);
        b = fgetc(fpB);
    }
    fclose(fpA);
    fclose(fpB);
    fclose(fpout);
    printf("合并成功,请在studentc文件中查看!\n");
}
void sort(struct student2* head)
{
    struct student2* newNode = (struct student2*)malloc(sizeof(struct student2));
    newNode->next = NULL;
    while (head)
    {
        struct student2* current = head;
        struct student2* pre = head;
        struct student2* preMin = head;
        struct student2* min = head;
        while (current)
        {
            if (current->data.grade[3] < min->data.grade[3])
            {
                preMin = pre;
                min = current;
            }
            pre = current;
            current = current->next;
        }
        if (min == head)
        {
            head = head->next;
            min->next = newNode->next;
            newNode->next = min;
        }
        else
        {
            preMin->next = min->next;
            min->next = newNode->next;
            newNode->next = min;
        }
    }
    head = newNode->next;
    free(newNode);
    newNode = head;
    while (newNode)
    {
        printf("%s %d %d %d %d %d\n", newNode->data.name, newNode->data.num, newNode->data.grade[0], newNode->data.grade[1], newNode->data.grade[2], newNode->data.grade[3]);
        newNode = newNode->next;
    }

}

void main()
{
    int i = 0;
    struct student2* head = NULL;
    //struct student2* creat();
    //void printLinkList();
    printf(" -------------------------------------------------\n");
    printf("|   ***欢迎使用西安工程大学学生成绩管理系统***    |\n");
    printf("|                                                 |\n");
    printf("|       1.建立学生成绩单                          |\n");
    printf("|       2.显示学生成绩单                          |\n");
    printf("|       3.查找学生成绩                            |\n");
    printf("|       4.按总成绩进行排序并显示                  |\n");
    printf("|       5.显示需要补考的学生信息并存入新文件4     |\n");
    printf("|       6.合并学生成绩单1和2存入新的成绩单3中     |\n");
    printf("|       7.退出系统                                |\n");
    printf("|                                                 |\n");
    printf(" -------------------------------------------------\n");
    while (i != 6)
    {
        printf("请选择您需要的操作:");
        scanf("%d", &i);
        if (i <= 0 || i > 6)
            printf("输入有误,请重新输入!\n");
        else if (i == 1)
        {
            head = NULL;
            head = creat(head);
        }
        else if (i == 2)
            printLinkList(head);
        else if (i == 3)
            find(head);
        else if (i == 4)
            sort(head);
        else if (i == 5)
            display(head);
        else if (i == 6)
            merge(head);
        else
            printf("退出系统成功!!!\n");
    }
}