Странная ошибка dumpcore при выполнении моей программы (C) - PullRequest
0 голосов
/ 27 января 2020

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

Я пока не уверен (fscanf ... et c). Какой цикл я могу сделать, чтобы прочитать все числа до конца файла?

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

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;
    FILE *pf=fopen("file1.txt","r");
    assert(pf!=NULL);
    Tlist list;
    list=CreateList();

    while(fscanf(pf,"%d",&x)==1){
        list=InsertAtEnd(list,x);
    }
    PrintList(list);

    return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x){
    Tnode *newnode;
    newnode=malloc(sizeof(Tnode));
    assert(newnode!=NULL);
    newnode->info=x;
    newnode->link=NULL;
    return newnode;
    }

Tlist CreateList(){
    return 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;
    else{//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",nodeinf);
}

void PrintList(Tlist list){
    Tnode *node;
    node=list;
    while (node->link!=NULL){
        PrintInfo(node->info);
        node=node->link;
    }

return;
} 

Когда я создаю его, он не дает мне ошибок. Затем, когда я запускаю его, это показывает

0 [main] simulazione_1 669 cygwin_exception::open_stackdumpfile: Dumping stack trace to simulazione_1.exe.stackdump

RUN FAILED (exit value 35.584, total time: 1s)

Что это за ошибка. Что не так с моим кодом?

Ответы [ 2 ]

2 голосов
/ 28 января 2020

Ну, во-первых, ошибка (у вас две серьезные ошибки здесь):

Во-первых, вы допустили ошибку: вы правильно догадались, что, когда список пуст (просто 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;
} 
1 голос
/ 27 января 2020

Функция InsertAtEnd недействительна. Если изначально список пуст, функция возвращает значение NULL, поскольку указатель list не изменяется в функции. Изменяется указатель tmp.

При вашем подходе функция может выглядеть следующим образом

Tlist InsertAtEnd( Tlist list, int x ) 
{
    Tnode *newnode = CreateNode(x);

    if ( list == NULL )
    {
        list = newnode;
    }
    else
    {    
        Tnode *tmp = list;

        while ( tmp->link != NULL )
        {
            tmp = tmp->link;
        }

        tmp->link = newnode;
    }

    return list;
}

Также функция PrintList также неверна. Это должно быть определено следующим образом

void PrintList( Tlist list )
{
    for (  Tnode *node = list; node != NULL; node = node->link )
    {
        PrintInfo(node->info);
    }
} 
...