C 具有结构的双向链表

标签 c struct doubly-linked-list

我正在做一个双向链表。据我所知,它正在工作,但来这里是为了确保并看看我是否以正确的方式进行。

另一方面,当我做这个时,我遇到了其他与双向链表无关的问题,但与 C 文件之间的结构和“可见性”有关。如果您明白我应该针对这另外两个疑问提出其他问题,请告诉我。否则请随时启发我。

在我的 file1.c 上我有这个:

代码

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

typedef struct team{
    char *name;
    char *teamPlace;
}Team;

typedef struct nodeTeam{
    int numberOfTeams;
    Team team;
    struct nodeTeam *next;
    struct nodeTeam *prev;
}NodeTeam;

int createsListOfTeams(NodeTeam **head, NodeTeam **tail);
void printListOfTeams(NodeTeam *listofTeams);
int addNodeTeamsSorted(NodeTeam *head, NodeTeam **tail, Team team);

int main()
{
    NodeTeam *headEquipas,*tailEquipas;
    Team eq;
    /*Creates the doubly linked list*/
    if(createsListOfTeams(&headEquipas,&tailEquipas)){
        printf("\nError\n");
        return 0;
    }
    /*Add the teams to the doubly linked list. At the end, all teams will be sorted by name*/
    eq.name = "D team";
    eq.teamPlace = "D team place";
    if (addNodeTeamsSorted(headEquipas,&tailEquipas,eq)){
        printf("\nError\n");
        return 0;
    }

    eq.name = "A team";
    eq.teamPlace = "A team place";
    if (addNodeTeamsSorted(headEquipas,&tailEquipas,eq)){
        printf("\nError\n");
        return 0;
    }

    eq.name = "C team";
    eq.teamPlace = "C team place";
    if (addNodeTeamsSorted(headEquipas,&tailEquipas,eq)){
        printf("\nError\n");
        return 0;
    }

    eq.name = "B team";
    eq.teamPlace = "B team place";
    if (addNodeTeamsSorted(headEquipas,&tailEquipas,eq)){
        printf("\nError\n");
        return 0;
    }

    /*Will print all the teams*/
    printListOfTeams(headEquipas);

    return 0;
}

在我的 file2.c 上我有这个

代码

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

    typedef struct team{
        char *name;
        char *teamPlace;
    }Team;

    typedef struct nodeTeam{
        int numberOfTeams;
        Team team;
        struct nodeTeam *next;
        struct nodeTeam *prev;
    }NodeTeam;

    /*Add the teams to the doubly linked list. At the end, all teams will be sorted by name*/
    int createsListOfTeams(NodeTeam **head, NodeTeam **tail){
        (*head) = (NodeTeam *)malloc(sizeof(NodeTeam));

        if ((*head) == NULL){
            return -1;
        }
        (*head)->numberOfTeams = 0;
        (*head)->team.teamPlace = "";
        (*head)->team.name = "";
        (*head)->next = NULL;
        (*head)->prev = NULL;

        *tail = *head;
        return 0;
    }

    /*Creates the doubly linked list*/
    int addNodeTeamsSorted(NodeTeam *head, NodeTeam **tail, Team team){
        NodeTeam *no,*listIni;


        no = (NodeTeam*) malloc(sizeof(NodeTeam));
        if (no == NULL){
            return -1;
        }

        /*copy of my list*/
        listIni = head;

        no->team = team;
        /*to see is it's the first element of my list*/
        if(head->numberOfTeams == 0)
        {
            no->next = head->next;
            no->prev = head;
            head->next = no;
            *tail = no;

        }
        else{ /*If not the first element*/
            head = head->next;
            while(head->prev != *tail && strcmp(head->team.name,no->team.name) < 0 && strcmp((*tail)->team.name,no->team.name)>0){
                head = head->next;
                (*tail) = (*tail)->prev;
            }
            if(strcmp(head->team.name,no->team.name) >= 0 || head->prev == *tail){
                no->next = head;
                no->prev = head->prev;
                (head->prev)->next = no;
                head->prev = no;

            }
            else if(strcmp((*tail)->team.name,no->team.name) <= 0){
                no->next = (*tail)->next;
                no->prev = (*tail);
                (*tail)->next = no;
                *tail = no;

            }
        }

        /*Updates the number of element of the list*/
        head = listIni;
        head->numberOfTeams++;

        return 0;
    }
    /*Prints my lists*/
    void printListOfTeams(NodeTeam *listofTeams){
        printf("|   number of teams %22d |\n",listofTeams->numberOfTeams);
        printf("|      team name      |        team place      |\n");
        printf("--------------------------------------------------\n");
        listofTeams = listofTeams->next;
        while (listofTeams != NULL){
            printf("| %-21s | %-22s |\n",listofTeams->team.name,listofTeams->team.teamPlace);
            listofTeams = listofTeams->next;
        }
        printf("--------------------------------------------------\n\n");
    }

这是我的树问题:

Q1 - 这是实现头和尾分别指向列表开头和结尾的双向链表的正确方法吗?

Q2 - 为什么要在我的两个文件中声明 struct teamstruct nodeTeam?既然它们都在同一个项目中,那么声明对我项目中的所有文件不应该“可见”吗?

Q3 - 在 struct team 中,为什么我必须声明 char *name 而不是 char name[31]?

最佳答案

在您之前的评论并更仔细地分析了您的代码后,我做了一些编辑。 我错误地解释了关于头项和尾项的一条评论,尽管您正在设计一个循环列表

  1. 我花了时间复制/粘贴/编译您的代码。虽然它几乎可以工作,但我必须说我会以另一种方式进行设计

    • prev/next 指针移至 struct team
    • 并将 teamnodeTeam 成员替换为指向第一个 headteam 指针。

    这将带来以下好处:

    • 防止 numberOfTeams 的空间被重复,但仅对第一个 nodeTeams 有意义
    • 避免概念上的 head 和实际的第一支球队之间的混淆

    通过添加团队列表中的指针值

    printf("| %-21s | %-22s | %p - p=%p n=%p\n",listofTeams->team.name, listofTeams->team.teamPlace, listofTeams, listofTeams->prev, listofTeams->next);

    我注意到您的链接中可能存在错误:

    | A team | A team place | 0x101d00980 - p=0x101d00920 n=0x101d009e0

    | B team | B team place | 0x101d009e0 - p=0x101d00980 n=0x101d009b0

    | C team | C team place | 0x101d009b0 - p=0x101d00980 n=0x101d00950

    | D team | D team place | 0x101d00950 - p=0x101d009b0 n=0x0

    您可以看到 next 指针没问题,但 prev 指针显示可疑重复(0x101d00920 确实是“头”)。

    如果您跟踪代码的执行并检查它在 addNodeTeamsSorted() 中执行的操作,您可能会注意到,直到步骤 3 一切正常(在现有 A 和 D 之后添加团队 C):

    • 由于为了找到插入新项目的位置而对头部和尾部进行了奇怪的双重修改,头部和尾部交叉:尾部实际上指向“A”而头部指向“D”(不要忘记,虽然 headNodeteam * 及其修改不会传播到函数外部, tail 是一个 Nodeteam ** ,因此当它更改为调用者时,下次调用时它将是错误的
    • 在测试的 else if 部分的步骤 4(添加“B”)中,您正确更改了 no 的上一个/下一个、 (*tail) 的下一个但是不是 no->next 的上一个,所以你有
      • 'B' -> 下一个 = 'C':好的
      • 'B' -> prev = 'A':好的
      • *tail (='A') -> next = 'B': 好的
      • 'C' -> 上一个仍然 = 'A':错误
  2. 这不是编译器所想的那样。他只处理编译单元,一次一个。 .c 中未声明的内容以及包含的不同 .h 将仍然未知。如果您想在两个模块之间共享结构声明,并防止代码维护中出现错误,请剪切 typedef 并将它们放入一个公共(public)头文件(例如 equipa.h )中,该头文件将包含在两个 .c 中

  3. 您必须使用 char* 而不是 char[],因为在 file1.c 的 main() 中,您正在直接从文字字符串进行赋值,而编译器不会让您将文字字符串赋给 char 数组。如果您想使用 char[] 改为更改您的

    eq.nome = "D team";

    通过字符串复制

    strcpy(eq.nome, "D team");

    当然,我只是处理概念,实际上你应该注意使用 strncpy()sizeof(eq.nome) 来复制的字符串不要长于缓冲区

关于C 具有结构的双向链表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10562763/

相关文章:

c++ - 在双向链表上插入函数

c - 我是否正确地在 C 中实现了双向链表的删除节点函数?

c - 我的函数没有返回它应该返回的内容

c - 使用 C 中的隐藏变量和方法进行测试驱动开发

c - 如何访问作为指针确定的结构体的结构体成员?

c - 将结构体的 fwrite() 和 fread() 部分写入二进制文件

c - 如何在 C 中合并和排序两个双向链表

c - 函数除了它的数据成员(char 数组)之外不返回任何东西,可以在 main 函数中访问。这怎么可能?

c - 驱动程序到用户模式通信

c++ - 将源代码与 C++ 程序的汇编列表相关联