C двусвязный список со структурой

Я делаю двусвязный список. Насколько я знаю, это работает, но приехал сюда, чтобы убедиться и убедиться, что я поступаю правильно.

С другой стороны, когда я сделал это, я натолкнулся на другие вопросы, не связанные с двусвязным списком, но со структурами и "видимостью" между 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 team и struct nodeTeam? Поскольку все они находятся в одном проекте, не должно ли объявление быть "видимым" для всех файлов моего проекта?

Q3 - В struct teamпочему я должен объявить char *name вместо char name[31]?

1 ответ

Решение

Я сделал некоторые правки после ваших предыдущих комментариев и после более тщательного анализа вашего кода. Я неверно истолковал одно замечание о предметах головы и хвоста, и хотя вы составляли круговой список

  1. Я нашел время, чтобы скопировать / вставить / скомпилировать ваш код. Хотя это почти работает, я должен сказать, что я разработал бы

    • перемещая prev/ next указатели в struct team
    • и заменить team член nodeTeam по head указатель на первый team,

    Это будет иметь следующие преимущества:

    • предотвратить бесполезную трату пространства для numberOfTeams что дублируется для каждого nodeTeams но имеет значение только для первого
    • избежать путаницы между концептуальным head и фактическая первая команда

    Добавляя значение указателей в списке команды с

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

    Я заметил возможную ошибку в вашей ссылке:

    | Команда | Командное место | 0x101d00980 - p = 0x101d00920 n = 0x101d009e0

    | B команда | B командное место | 0x101d009e0 - p = 0x101d00980 n = 0x101d009b0

    | С командой | C командное место | 0x101d009b0 - p = 0x101d00980 n = 0x101d00950

    | D команда | D командное место | 0x101d00950 - p=0x101d009b0 n=0x0

    Вы можете видеть, что следующие указатели в порядке, но предыдущие указатели показывают подозрительные дубликаты (0x101d00920 действительно является "головой").

    Если вы отслеживаете выполнение своего кода и проверяете, что он сделал в addNodeTeamsSorted() Вы могли заметить, что все хорошо до шага 3 (добавление команды C, после существующего A & D):

    • из-за странной двойной модификации головы и хвоста, чтобы найти место для вставки нового предмета, голова и хвост пересекаются: хвост на самом деле указывает на "А" и направляется на "D" (не забывайте, что пока head является Nodeteam * и его модификация не будет распространяться за пределы функции, tail это Nodeteam **таким образом, когда это будет изменено на вызывающего абонента и для следующего вызова, это будет неправильно
    • на шаге 4 (добавление "B") в else if часть теста, вы корректно меняете предыдущий / следующий noследующий (* хвост), но не пред. no->next так что у тебя есть
      • "B" -> далее = "C": ОК
      • 'B' -> prev = 'A': ОК
      • *tail (='A') -> next = 'B': ОК
      • 'C' -> предыдущая еще = 'A': НЕПРАВИЛЬНО
  2. Это не то, что думает компилятор. Он обрабатывает только единицы компиляции, по одной за раз. То, что не объявлено в.c, и другие включенные.h останутся неизвестными. Если вы хотите разделить объявления структур между двумя модулями и предотвратить ошибки в обслуживании кода, отрежьте typedefs и поместите их в общий заголовочный файл (например, equipa.h) который будет включен в оба.c

  3. Вы должны использовать char* вместо char[] потому что в вашем main() в file1.c вы делаете прямые присваивания из литеральных строк, и компилятор не позволит вам присвоить литеральную строку массиву char. Если вы хотите использовать char[] вместо этого поменяйте

    eq.nome = "D team";

    копируя строки как

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

    конечно, я имею дело только с концепцией, на самом деле вы должны позаботиться о том, чтобы строка, которая будет скопирована, не длиннее буфера с помощью strncpy() а также sizeof(eq.nome)

Другие вопросы по тегам