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 ответ
Я сделал некоторые правки после ваших предыдущих комментариев и после более тщательного анализа вашего кода. Я неверно истолковал одно замечание о предметах головы и хвоста, и хотя вы составляли круговой список
Я нашел время, чтобы скопировать / вставить / скомпилировать ваш код. Хотя это почти работает, я должен сказать, что я разработал бы
- перемещая
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': НЕПРАВИЛЬНО
- перемещая
Это не то, что думает компилятор. Он обрабатывает только единицы компиляции, по одной за раз. То, что не объявлено в.c, и другие включенные.h останутся неизвестными. Если вы хотите разделить объявления структур между двумя модулями и предотвратить ошибки в обслуживании кода, отрежьте typedefs и поместите их в общий заголовочный файл (например,
equipa.h
) который будет включен в оба.cВы должны использовать
char*
вместоchar[]
потому что в вашемmain()
в file1.c вы делаете прямые присваивания из литеральных строк, и компилятор не позволит вам присвоить литеральную строку массиву char. Если вы хотите использоватьchar[]
вместо этого поменяйтеeq.nome = "D team";
копируя строки как
strcpy(eq.nome, "D team");
конечно, я имею дело только с концепцией, на самом деле вы должны позаботиться о том, чтобы строка, которая будет скопирована, не длиннее буфера с помощью
strncpy()
а такжеsizeof(eq.nome)