Ну, во-первых, ошибка (у вас две серьезные ошибки здесь):
Во-первых, вы допустили ошибку: вы правильно догадались, что, когда список пуст (просто NULL
указатель) вам придется изменить начальный указатель указателем на первый узел, но когда вы кодируете его, вы не учитываете его правильно и возвращаете исходный переданный указатель (который продолжает указывать на NULL
):
Tlist InsertAtEnd(Tlist list,int x){
Tnode *newnode,*tmp;
newnode=CreateNode(x);
tmp=list;
//CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp==NULL)
tmp=newnode;
необходимо изменить указатель list
, чтобы он возвращал правильное значение, например:
list=newnode;
или лучше:
return newnode;
Во-вторых, в функции печати вам нужно продолжать while
l oop, только до тех пор, пока у узла не будет элемента next
, (while(node->link != NULL)
) (который завершит l oop перед печатью последнего элемента , и что еще хуже, это то, что делает вашу программу неудачной, так как вы передаете ей начальный указатель NULL
, потому что вы неправильно заполнили список и пытаетесь получить доступ node->link
когда node
само по себе NULL
, что является ошибкой, и это то, что делает вас r запрограммируйте на cra sh), поэтому вам нужно проверить, когда iself указателя равен NULL
(как в while(node != NULL)
), что приводит к:
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}
или лучше:
void PrintList(Tlist list) {
Tnode *node;
for (node = list; node != NULL; node = node->link) {
PrintInfo(node->info);
}
return;
}
макрос assert:
Макрос assert
является макросом отладки , вы его неправильно используете. Он показывает вам строку, в которой код терпит неудачу (что хорошо), и выражение, которое вы передаете ему (что тоже хорошо). Но у него есть недостаток, который вы не рассматривали: в производственном коде #define NDEBUG 1
свойственно просто исключить все сделанные вами в коде утверждения (все утверждения скомпилированы условно). Это имеет одну проблему, так как все утверждения в вашем коде будут магически исчезать, , но это включает в себя все тесты, которые вы делаете в аргументах, которые вы ему передаете (и это не хорошо). Я попытался переписать все ваши утверждения с помощью набора макросов, которые сохранят набор текста, а также позволят вам проследить, где в коде у вас есть ошибка. Поскольку в этих макросах нет кода для их условной компиляции, вы можете быть уверены, что код будет в конечном производственном коде:
#define F(_fmt) __FILE__":%d: " _fmt, __LINE__
, это расширится:
printf(F("Error: %s has not been opened\n"), file);
в:
printf(__FILE__":%d: " "Error: %s has not been opened\n", __LINE__, file);
или, при условии, что этот оператор был в строке 112 файла pru.c
:
printf("pru.c" ":%d: " "Error: %s has not been opened\n", 112, file);
, что приведет к (предполагая, что файл "File1.txt"
):
pru.c:112: Error: File1.txt has not been opened
Чтобы сэкономить нажатия клавиш, я также определил макрос ERR(fmt, ...)
для расширения до вызова fprintf(stderr, ...)
.
ЗАКОНОДАТЕЛЬСТВО
Вы должны улучшить разборчивость вашего кода, чтобы он был более читабельным. Кажется, как будто вы оплачивали все пробелы, которые вы указали в коде.
После всех этих изменений ваш модифицированный код показан ниже:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define F(_fmt) __FILE__":%d: "_fmt, __LINE__
#define ERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
typedef struct node{
int info;
struct node *link;
}Tnode;
typedef Tnode *Tlist;
Tlist CreateList();
Tnode *CreateNode(int x);
Tlist InsertAtEnd(Tlist list, int x);
void PrintList(Tlist list);
void PrintInfo(int nodeinf);
int main(int argc, char** argv)
{
int x,i;
char *file_name = "file1.txt";
FILE *pf=fopen(file_name, "r");
if (!pf) {
ERR(F("%s: %s\n"), file_name, strerror(errno));
exit(EXIT_FAILURE);
}
Tlist list = CreateList(); /* it's good to initialize in declarations */
while(fscanf(pf, "%d", &x) == 1) {
list = InsertAtEnd(list, x);
}
PrintList(list);
return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x)
{
Tnode *newnode = malloc(sizeof(Tnode)); /* better initialize in declaration */
if (!newnode) {
ERR(F("malloc: %s\n"), strerror(errno));
exit(EXIT_FAILURE);
}
newnode->info = x;
newnode->link = NULL;
return newnode;
}
Tlist CreateList()
{
return NULL;
}
Tlist InsertAtEnd(Tlist list, int x)
{
Tnode *newnode = CreateNode(x), /* idem. */
*tmp = list;
// CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp == NULL) {
return newnode; /* return here, you have nothing else to do */
}
// NEL CASO IN CUI LA LISTA NON E' VUOTA
while(tmp->link != NULL) {
tmp = tmp->link;
}
tmp->link = newnode;
return list;
}
void PrintInfo(int nodeinf) {
printf("%d\n", nodeinf); /* you lacked a \n here */
}
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}