链接列表:添加和删除问题

时间:2016-12-19 14:06:45

标签: c linked-list

首先,对不起我的英语。

对于一个项目,我必须制作一个车库管理程序。这是一个链接的力学列表。我现在做了一个功能:一个用于在此列表中添加机制(addMec),另一个用于删除机制(remMec)。

这是addMec函数:

    void addMec(mechanics* first)
{
    mechanics *new = malloc(sizeof(mechanic));
    int speciality();
    if(first==NULL)
    {
        return(0);
    } else
    {

        printf("Add mechanic : \n");
        // Ask for needed informations.
        printf("Employee-Number : ");
        scanf("%5d",&new->number);
        printf("\nName : ");
        scanf("%s",&new->name);
        printf("\nFirst Name : ");
        scanf("%s",&new->first_name);
        new->speciality = speciality();
        // Add to end -> new->next = NULL
        new->next = NULL;
        printf("%d %s %s %d\n",new->number, 
               new->name, new->first_name, new->speciality);
        mechanics *current = first;
        while(current->next!=NULL)
        {
            current = current->next;
        }
        current->next = new;
    }
}

此功能不会在列表中添加任何内容。如果我尝试调试程序,我会收到一条SIGSEGV消息。

功能remMec

int remMec(mechanics* first)
{
    int numrem, ret = 0;
    mechanics *current, *intercale;
    printf("Supprimer l'employe numero : ");
    scanf("%5d",&numrem);
    // On parcoure la liste à la recherche du numero d'employe.
    current = first;
    while(current->next != NULL)
    {
        // Nécéssaire si l'élément à supprimer est le premier de la liste.
        if(current->number == first->number)
        {
            if(current->number == numrem && current != NULL)
            {
                intercale = first;
                first = first->next;
                free(intercale);
                ret = 1;
            }
        }
        if(current->number == numrem)
        {
            intercale = current->next;
            current->next = intercale->next;
            free(intercale);
            ret = 1;
        }
        current = current->next;
    }
    if(ret)
    {
        return 1;
    } else
    {
        return 0;
    }
}

此函数的问题在于它删除了搜索元素的下一个元素。 示例:在列表中: 15264约翰克里斯1 12569克里斯约翰2 如果我试图删除John Chris,它将删除Chris John

这是结构:

typedef struct{
    char name[31],first_name[31];
    int speciality, number;
    struct mechanic *next;
}mechanic;

编辑:当我尝试显示列表时,似乎发生了SIGSEGV。这是函数:

void displayList(mechanic *first, int n)
{
    int i;
    mechanic *courant = malloc(sizeof(mechanic));
    current = first;
    printf("Mechanics :\n");
    for(i = 1; i<n; i++)
    {

        printf("%5d %s %s",current->number,current->name, current->first_name);
        switch(current->speciality)
        {
            case 1: printf(" Wheels\n");break;
            case 2: printf(" Motor\n");break;
            case 3: printf(" Carrosserie\n");break;
            case 4: printf(" Chassis\n");break;
            default: printf(" Maintenance\n");break;
        }
        current = current->next;
    }
}

主要:

int main()
{
    int nbMec = 1,i,choise;
    int menu();
    int remMec(mechanics*);
    void afficherListe(mechanics*, int);
    void addMec(mechanics*);
    mechanics *first, *current, *nextM;
    first = malloc(sizeof(mechanics));
    current = first;

    FILE *fdat, *fdat2;
    fdat = fopen("clients.dat","r");
    fdat2 = fopen("employe.dat","r");

    // Lecture du fichier contenant les mécaniciens
    fscanf(fdat2,"%5d",&current->number);
    while(!feof(fdat2))
    {
        fscanf(fdat2,"%s%s%1d",&current->name, &current->first_name, &current->speciality);
        nextM = malloc(sizeof(mechanics));
        current->next = nextM;
        nbMec++;
        current = nextM;
        fscanf(fdat2,"%5d",&currentM->number);

    }

    //Finir la liste avec NULL
    current = first;
    for(i = 1; i<nbMec; i++){
        current = current->next;
    }
    current->next = NULL;
    free(nextM);

    DisplayList(first,nbMec);

    // Redirection en fonction du choix dans le menu
   choise = menu();
   if(choise == 1)
   {
       // Ajout d'un mécano
        addMec(first);
        nbMec++;
        displayList(first,nbMec);

   } else if (choise == 2)
   {
       if(remMec(first))
       {
           printf("Mecanicien efface de la liste.\n");
           nbMec--;
       } else
       {
           printf("Impossible.\n");
       }
       afficherListe(first,nbMec);
   } else
   {
       //Ajout d'un rendez-vous
   }



    return 0;
}

这是employe.dat文件:

12345 Ric Hochet 1
13456 Jean Valjean 2
14567 Rick Grimes 3
15007 James Bond 4
16789 Rogge Jacquie 5

记录示例:

XXXXX  CCCCC   CCCCC        X
number name  first_name speciality
你能帮帮我吗? 谢谢!

2 个答案:

答案 0 :(得分:1)

你的第一个功能是这样开始的:

void addMec(mechanics* first)
{
    mechanics *new = malloc(sizeof(mechanic));
    int speciality();
    if(first==NULL)
    {
        return(0);
    } else
    {
        ......
        ......

这不会编译!首先是因为return带有void函数的值,第二个是未定义的类型名称。

即使它确实如此,也没有任何意义。首先,分配一块内存并将指针存储在new变量中。然后测试first是否为NULL,如果是,则从函数返回。

仔细看:你从这个功能回来了。因此,您不输入新变量的任何数据,不会将附加到列表中。这意味着,如果之前没有从文件中填充,那么您的程序可以构建用户输入的任何列表。

此外,从函数返回时,所有本地自动变量都将丢失。其中包含new。这意味着您不再能够访问刚刚分配的块 - 它会丢失。您分配了一些内存但无法以任何方式使用它。这就是我们所说的内存泄漏。

为了使函数更具可读性(并且更容易进一步开发),我将它分成两部分:一部分用于创建一个新对象并将其放入列表中,一个子例程用用户输入填充它:

void inputMec(mechanic *mec)
{
    int speciality();

    printf("Add mechanic : \n");
    // Ask for needed informations.
    printf("Employee-Number : ");
    scanf("%5d", & mec->number);
    printf("\nName : ");
    scanf("%s", & mec->name);
    printf("\nFirst Name : ");
    scanf("%s", & mec->first_name);
    mec->speciality = speciality();
}

void addMec(mechanic* first)
{
    if(first != NULL)   // only if the list's head exists
    {
        mechanic *new = malloc(sizeof(mechanic));

        if(new != NULL) // a new object created sucessfully
        {
            inputMec(new);

            printf("%d %s %s %d\n",new->number, 
                   new->name, new->first_name, new->speciality);

            // find the last item in the list
            mechanic *last = first;
            while(last->next != NULL)  // still not the last one?
            {
                last = last->next;     // step forward
            }
            last->next = new;          // append after the last
            new->next = NULL;          // terminate the list
        }
    }
}

如果列表中的排序不重要(从您的代码中看起来如此),那么您可以更轻松地在列表的开头添加新项目:

            // insert the item just after the list's head
            new->next = first->next;  // append the list after the new item
            first->next = new;        // link the new item to the head

在实际的编程任务中,您还必须考虑限制和验证输入,这两者都是内部限制(字符串非空?它们不是太长了吗?是字典范围中的speciality值吗? )和外部一致性(员工的标识符是否不同?是他们的名字+ first_name对不同吗?) 如果内部不一致,您可能会要求正确的数据,并循环读取输入直到它正确,或放弃输入操作;在后一种情况下,inputMec例程应该return某种状态。然后调用程序例程addMec应该测试状态以决定是否在列表中插入新项目,或者在输入失败时将free()插入列表中。 如果发生外部冲突,您可以打印相应的消息,暂时保留新项目并迭代读取输入以获取非冲突数据,或者您可以放弃操作free()对象并返回主菜单,用户所在可以再次进入添加机制。

答案 1 :(得分:1)

我找到了解决方案: 关于addMec,感谢CiaPan 。 在这些问题之后,我选择在列表的开头添加一个新的机制。 我还创建了一个包含第一个元素的列表结构。 这是正确的addMec(请注意,对于该项目,我已添加了rep(修复)数组):

    void addMec(list *list, int number, char name[], char first_name[], int speciality)
{
    int i;
    mechanics *new = malloc(sizeof(mechanics));
    if(list == NULL || new == NULL)
    {
        exit(EXIT_FAILURE);
    }
    new->number = number;
    strcpy(new->name,name);
    strcpy(new->first_name,first_name);
    new->speciality = speciality;

    for(i = 1; i<=50; i++)
    {
        new->rep->year=0;
        new->rep->day = 0;
        new->rep->month = 0;
        new->rep->price = 0;
        new->rep->emergency = 0;
        strcpy(new->rep->brkdwn,"");
    }
    new->next = list->first;
    list->first = new;
    list->nbElmt++;



}

关于remMec,我在另一个网站上搜索,一个名为 pagrette 的用户解释了我。 有了这些行,

intercale = current->next;
current->next = intercale->next;
free(intercale);

我只是释放下一个元素 谢谢你的帮助!