关于用动态链表实现对学生数据的的删除与输出的提问

在设计动态链表用于存放学生的姓名,学号和三门课程的成绩,要求设计del函数实现对前六个学生中成绩平均分最高与最低的学生数据删除。
在设计过程中遇到了下列问题
1.动态链表的输出多了一段地址
2.结构体指针在使用时发生了冲突。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define len sizeof(struct date)
int n;//节点数量
struct date//建立结构体
{   
    char name;//姓名
    int id;//学号
    int score1;//成绩1
    int score2;//成绩2
    int score3;//成绩3
    struct date *next;//指向下一个结构体的指针
};
struct date* creat(void)//创建动态链表并返回头指针
{
    struct date* head, * p1, * end;
    n = 0;
    p1 = end = (struct date*)malloc(len);
    printf("请输入学生的姓名,学号,以及三门课程的成绩:\n");
    scanf("%c,%d %d %d %d", &p1->name,&p1->id, &p1->score1, &p1->score2, &p1->score3);
    head = NULL;
    while (p1->name!=32)
    {
        n = n + 1;
        if (n == 1)
            head = p1;
        else
            end->next= p1;
        end = p1;
        p1 = (struct date*)malloc(len);
        scanf("%c,%d %d %d %d", &p1->name, &p1->id, &p1->score1, &p1->score2, &p1->score3);
    }
    end->next = NULL;//尾指针
    return(head);
}
struct date* creat(void);
void del(struct date* pt);
int main()
{
    int i;
    struct date* pt,;
    pt = creat();//让pt成为头指针
    printf("若不执行任何操作请输0\n");
    printf("若要新增数据请输1;\n");
    printf("若要删除前面6个学生中平均分最高和最低的学生的数据请输2\n");
    scanf("%d", &i);
    switch (i)
    {
    case 0:break;
    //case 1:insert(pt, n); break;
    case 2:del(pt); break;
    }
    do{   
        printf("%c,%d %d %d %d\n",(pt->name),(pt->id),(pt->score1),(pt->score2),(pt->score3));//输出链表
        pt=pt->next;
    } while (pt ->next!= NULL);
    return 0;
}
void del(struct date* pt)//找出前6组数据中的最高,最低平均分并删去
{
    struct date* h1 = pt,*h2=pt,*in=pt,*h3=pt;
    int averge[6] = { 0 }, x = 0, i = 0, z = 0;
    int y, o=0, p;
    float min,max;
    min = (float)(averge[0]);
    max = (float)(averge[0]);
    for (y= 0; y < 6; y++)
    {
        averge[y] = (float)((h2->score1 + h2->score2 + h2->score3) / 3);//用一个数组记录每个人的平均分
        h2 = h2->next;
    }
    free(h2);
    for (y = 0; y < 6; y++)
    {
        if ((float)averge[y] < min)
        {
            min = (float)averge[y];
            o= y;//记下最小值的坐标
        }
        if ((float)averge[y] > max)
        {
            max = (float)averge[y];
            p = y;
        }
    }
    while (i < o && h1 != NULL)
    {
        in = h1;
        h1 = h1->next;//使指针移动到要找到的坐标
        i++;
    }
    if (h1 != NULL)
    {
        in->next = h1->next;//更改最小值坐标的前一个结构体的指针使其跳过该坐标
        free(h1);
    }
    while (z < p && h3 != NULL)
    {
        in = h3;
        h3= h3->next;
        i++;
    }
    if (h3 != NULL)
    {
        in->next = h3->next;
        free(h3);
    }
}

运行结果及详细报错内容

img

img

思路:对于del函数,先用数组储存每个同学的平均分,然后再找出最高分与最低分的地址。对其前一个结构体的指针进行修改。

我想要达到的结果,如果你需要快速回答,请尝试 “付费悬赏”

动态链表之所以会多出一段地址。是因为你的scanf里面有输入字符类型的变量,你每次输入一组数据是不是还要按一下回车。比如你输入a 1 2 3 4,此时输入缓冲区包含了a 1 2 3 4其实还有一个回车字符。程序在创建a 1 2 3 4这一个节点后再一次来到scanf函数,此时scanf发现缓冲区还有一个回车字符就不会让用户进行输入操作,而是会将回车也当作一个字符赋值给节点的name变量中,这就导致你输入一次数据程序实际上创建了两个节点。而回车这个字符是没有形状的,这也就是为什么你多出来的数据第一个字符显示空,后面四个int都是随机值。解决方法就是在scanf后面加一个getchar函数将回车字符回收掉。
代码仅供参考

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

typedef struct stu {
    char name;
    int id;
    int scoreOne;
    int scoreTwo;
    int scoreThree;
    struct stu* next;
} STUDATE;

STUDATE* CreateDate(void);
STUDATE* DeleteMaxOrMin(STUDATE* headPtr_);
STUDATE* DeleteNode(STUDATE* headPtr_, STUDATE* nodePtr_);
void PrintList(STUDATE* headPtr_);

int main(void) {
    STUDATE* headStr = CreateDate();
    headStr = DeleteMaxOrMin(headStr);
    PrintList(headStr);
    return 0;
}

STUDATE* CreateDate(void) {
    STUDATE* headPtr = NULL;
    STUDATE* tempPtr = NULL;
    STUDATE* endPtr = NULL;
    while (1) {
        tempPtr = (STUDATE*)malloc(sizeof(STUDATE));
        tempPtr->next = NULL;
        scanf("%c%d%d%d%d", &(tempPtr->name), &(tempPtr->id), &(tempPtr->scoreOne), &(tempPtr->scoreTwo), &(tempPtr->scoreThree));
        getchar();
        if (tempPtr->name == '#')
            break;
        if (headPtr == NULL) {
            headPtr = tempPtr;
            endPtr = tempPtr;
        } else {
            endPtr->next = tempPtr;
            tempPtr->next = NULL;
            endPtr = tempPtr;
        }
    }
    return headPtr;
}

STUDATE* DeleteMaxOrMin(STUDATE* headPtr_) {
    STUDATE* maxPtr = headPtr_;
    STUDATE* minPtr = headPtr_;
    int avergeMin = 0;
    int avergeMax = 0;
    int currentAverge = 0;
    STUDATE* ptr = headPtr_->next;
    while (ptr) {  // ptr != NULL
        avergeMax =
            (maxPtr->scoreOne + maxPtr->scoreTwo + maxPtr->scoreThree) / 3;
        avergeMin =
            (minPtr->scoreOne + minPtr->scoreTwo + minPtr->scoreThree) / 3;
        currentAverge = (ptr->scoreOne + ptr->scoreTwo + ptr->scoreThree) / 3;
        if (currentAverge < avergeMin)
            minPtr = ptr;
        if (currentAverge > avergeMax)
            maxPtr = ptr;
        ptr = ptr->next;
    }
    // delete
    if (maxPtr == minPtr)  // 代表所有学生平均成绩都相等 不做删除操作
        return headPtr_;
    headPtr_ = DeleteNode(headPtr_, maxPtr);
    headPtr_ = DeleteNode(headPtr_, minPtr);
    return headPtr_;
}

STUDATE* DeleteNode(STUDATE* headPtr_, STUDATE* nodePtr_) {
    STUDATE* deletePrev = headPtr_;
    if (nodePtr_ == headPtr_) {
        headPtr_ = headPtr_->next;
        nodePtr_->next = NULL;
        free(nodePtr_);
        return headPtr_;
    }
    while (deletePrev->next != nodePtr_)  // 指向删除节点的前一个节点
        deletePrev = deletePrev->next;

    if (nodePtr_->next = NULL) {  // 要删除的在最后
        deletePrev->next = NULL;
        free(nodePtr_);
    } else {  // 在中间
        deletePrev->next = nodePtr_->next;
        nodePtr_->next = NULL;
        free(nodePtr_);
    }
    return headPtr_;
}

void PrintList(STUDATE* headPtr_) {
    STUDATE* str = headPtr_;
    while (str) {
        printf("%c %d %d %d %d\n", str->name, str->id, str->scoreOne, str->scoreTwo, str->scoreThree);
        str = str->next;
    }
}

```c


```

修改完善如下,供参考:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define len sizeof(struct date)
int n;//节点数量
struct date//建立结构体
{
    char name;//姓名
    int id;//学号
    int score1;//成绩1
    int score2;//成绩2
    int score3;//成绩3
    struct date *next;//指向下一个结构体的指针
};

struct date* creat(struct date *head);
void del(struct date** pt);

struct date* creat(struct date *head)//创建动态链表并返回头指针
{
    struct date* p1, * end;
    while (1)
    {
        p1 = (struct date*)malloc(len);
        p1->next = NULL;
        scanf(" %c", &p1->name);
        if (p1->name == '#') {  //以 '#' 结束输入
            free(p1);
            break;
        }
        scanf("%d %d %d %d",&p1->id, &p1->score1, &p1->score2, &p1->score3);
        if (head == NULL)
            head = p1;
        else{
            for (end = head;end->next; end=end->next);
            end->next= p1;
        }
    }
    return(head);
}

int main()
{
    int i;
    struct date* pt=NULL;
    pt = creat(pt);//让pt成为头指针
    printf("删除前面6个学生中平均分最高和最低的学生的数据:\n");
    del(&pt);
    do{
        printf("%c %d %d %d %d\n",(pt->name),(pt->id),(pt->score1),(pt->score2),(pt->score3));//输出链表
        pt=pt->next;
    } while (pt != NULL);
    return 0;
}
void del(struct date** pt)//找出前6组数据中的最高,最低平均分并删去
{
    struct date* h1 = (*pt),*h2=(*pt),*in=NULL;
    int  y, i=0;
    float average,min,max;
    for (y = 0;h2 && y < 6; y++)
    {
        average = ((h2->score1 + h2->score2 + h2->score3) / 3.0);
        if (y == 0){
            min = max = average;
        }
        else{
            if (average < min)
                min = average;
            if (average > max)
                max = average;
        }
        h2 = h2->next;
    }
    while (h1 != NULL && i < y)
    {
        average = ((h1->score1 + h1->score2 + h1->score3) / 3.0);
        if (min == average || max == average){
            if (in == NULL){
                in = (*pt);
                (*pt) = in->next;
                free(in);
                in = NULL;
                h1 = (*pt);
            }
            else{
                in->next = h1->next;
                free(h1);
                h1 = in->next;
            }
        }
        else{
            in = h1;
            h1 = h1->next;
        }
        i++;
    }
}

运行效果:

img