为什么我的教授的链接列表向后打印?
Why is my Professor's Linked List Printing Backwards?
我有一个系统编程课程的项目。我正在建立我教授的代码。 (请不要介意她缺少标签等 - 我会尽力清理它。)
有谁知道为什么她的链表代码打印反了?
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[15];
char title[15];
int year;
struct Node *next;
struct Node *prev;
};
typedef struct Node *Box;
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
int main() {
Box head = NULL, temp;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
outputp = fopen("output.txt", "w");
head = insert_node(inputp);
for (i = 0; i < 4; i++) {
temp = insert_node(inputp);
temp->next = head;
head = temp;
}
print_list(head);
return 0;
}
Box print_list(Box pointer) {
Box here = pointer;
while (here != NULL) {
printf("%s, %s, %d \n", here->name, here->title, here->year);
here = here->next;
}
return pointer;
}
Box insert_node(FILE *inputp) {
Box temp = NULL;
temp = (Box)malloc(sizeof(struct Node));
fscanf(inputp, "%s", &temp->name);
fscanf(inputp, "%s", &temp->title);
fscanf(inputp, " %d", &temp->year);
temp->next = NULL;
temp->prev = NULL;
return temp;
}
该程序的目的是读取歌曲的 .txt 文件“播放列表”并从中创建一个链接列表。输入是:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
当程序输出:
Bach, Toccatas, 2005
Beethoven, Symphony_No_5, 1994
Vivaldi, The_Seasons, 2003
Mozart, Symphony_No_41, 2000
Rachmaninov, Concerto_No_2, 1999
(我也不知道她为什么在代码中包含一个输出文件,所有输出都在控制台,而不是存储在文件中。忽略它。)
列表以相反的顺序打印,因为您在列表的开头插入了每个新节点。您应该使用 tail
指针来跟踪列表的末尾。
另请注意以下备注:
next
和 prev
链接都应该更新。
像 typedef struct Node *Box;
那样将指针隐藏在 typedef 后面被认为是不好的做法,因为它令人困惑且容易出错。
insert_node
是一个容易混淆的函数名称,它只是从文件数据中分配一个新节点。
insert_node
应该测试 fscanf()
是否成功读取数据
如果作曲家的名字超过 14 个字节,fscanf(inputp, "%s", &temp->name);
有未定义的行为。这同样适用于title
。在空终止符之前要存储到目标数组中的最大字符数应指定为 %14s
,并且这些数组应定义为更大的长度。
main
应该检查节点是否从文件数据成功分配和初始化。只要可以从文件中读取节点,就应该迭代而不是硬编码节点数。
这是修改后的版本:
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[40];
char title[40];
int year;
struct Node *next;
struct Node *prev;
};
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
int main() {
Node *head = NULL;
Node *tail = NULL;
Node *node;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
if (!inputp) {
fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
return 1;
}
outputp = fopen("output.txt", "w");
if (!outputp) {
fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
return 1;
}
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
} else {
node->prev = tail;
tail = tail->next = node;
}
}
print_list(head);
// should free node list
return 0;
}
void print_list(const Node *pointer) {
while (pointer != NULL) {
printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
pointer = pointer->next;
}
}
Node *read_node(FILE *inputp) {
Node *temp = malloc(sizeof(*temp));
if (temp != NULL
&& fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
} else {
free(temp);
return NULL;
}
}
我有一个系统编程课程的项目。我正在建立我教授的代码。 (请不要介意她缺少标签等 - 我会尽力清理它。)
有谁知道为什么她的链表代码打印反了?
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[15];
char title[15];
int year;
struct Node *next;
struct Node *prev;
};
typedef struct Node *Box;
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
int main() {
Box head = NULL, temp;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
outputp = fopen("output.txt", "w");
head = insert_node(inputp);
for (i = 0; i < 4; i++) {
temp = insert_node(inputp);
temp->next = head;
head = temp;
}
print_list(head);
return 0;
}
Box print_list(Box pointer) {
Box here = pointer;
while (here != NULL) {
printf("%s, %s, %d \n", here->name, here->title, here->year);
here = here->next;
}
return pointer;
}
Box insert_node(FILE *inputp) {
Box temp = NULL;
temp = (Box)malloc(sizeof(struct Node));
fscanf(inputp, "%s", &temp->name);
fscanf(inputp, "%s", &temp->title);
fscanf(inputp, " %d", &temp->year);
temp->next = NULL;
temp->prev = NULL;
return temp;
}
该程序的目的是读取歌曲的 .txt 文件“播放列表”并从中创建一个链接列表。输入是:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
当程序输出:
Bach, Toccatas, 2005
Beethoven, Symphony_No_5, 1994
Vivaldi, The_Seasons, 2003
Mozart, Symphony_No_41, 2000
Rachmaninov, Concerto_No_2, 1999
(我也不知道她为什么在代码中包含一个输出文件,所有输出都在控制台,而不是存储在文件中。忽略它。)
列表以相反的顺序打印,因为您在列表的开头插入了每个新节点。您应该使用 tail
指针来跟踪列表的末尾。
另请注意以下备注:
next
和prev
链接都应该更新。像
typedef struct Node *Box;
那样将指针隐藏在 typedef 后面被认为是不好的做法,因为它令人困惑且容易出错。insert_node
是一个容易混淆的函数名称,它只是从文件数据中分配一个新节点。insert_node
应该测试fscanf()
是否成功读取数据
如果作曲家的名字超过 14 个字节,fscanf(inputp, "%s", &temp->name);
有未定义的行为。这同样适用于title
。在空终止符之前要存储到目标数组中的最大字符数应指定为%14s
,并且这些数组应定义为更大的长度。main
应该检查节点是否从文件数据成功分配和初始化。只要可以从文件中读取节点,就应该迭代而不是硬编码节点数。
这是修改后的版本:
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[40];
char title[40];
int year;
struct Node *next;
struct Node *prev;
};
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
int main() {
Node *head = NULL;
Node *tail = NULL;
Node *node;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
if (!inputp) {
fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
return 1;
}
outputp = fopen("output.txt", "w");
if (!outputp) {
fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
return 1;
}
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
} else {
node->prev = tail;
tail = tail->next = node;
}
}
print_list(head);
// should free node list
return 0;
}
void print_list(const Node *pointer) {
while (pointer != NULL) {
printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
pointer = pointer->next;
}
}
Node *read_node(FILE *inputp) {
Node *temp = malloc(sizeof(*temp));
if (temp != NULL
&& fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
} else {
free(temp);
return NULL;
}
}