Связанный список в C - PullRequest
       1

Связанный список в C

3 голосов
/ 16 сентября 2010

У меня возникли проблемы с запуском реализации этого связанного списка (содержащего слова в качестве данных). Проблема в том, что когда я пытаюсь напечатать слова (которые я вставил) в Связанный список, я ничего не получаю. Что я делаю не так, ломая голову над этим? Я надеюсь, что это не что-то глупое. В любом случае вот код -

typedef struct node
{
    void *data;
    struct node *next;
} NODE;

NODE *new_node(void *data)
{
    NODE *new = malloc(sizeof(NODE));
    if(new)
    {
        new->data = data;
        new->next = NULL;
        return new;
    }
    else
    {
        return NULL;
    }
}

void print_list(NODE *head, void (print_fn) (void*))
{
    if(head && head->next)
    {
        while(head->next)
        {
            if(print_fn)
                print_fn(head->data);
            else
                printf("Word: %s\n", (char *)head->data);
            head = head->next;
        }
    }
    return;
}

void append(NODE **head, NODE *node)                                                                                  
{
    NODE *tmp = *head;
    if(tmp && node)
    {
        while(tmp->next)
            tmp = tmp->next; 
        (*head)->next = node; /*add as last node*/
    }
    return;
}


NODE *create_list()
{
    FILE *dict_file = fopen("trial.txt", "r");

    if(dict_file)
    {
        NODE *head = new_node(NULL);
        if(!head) return NULL;

        char word[20];
        int first  = TRUE;
        memset(word, '\0', 20);

        while(fgets(word, sizeof(word), dict_file) != NULL )
        {
            if(first)
            {
                head->data = (void*)word;
                first = FALSE;
            }
            else
            {
                append(&head, new_node((void*)word));
            }
        }
        fclose(dict_file);
        return head;
    }
    else
    {
        printf("ERROR: File not found");
        return NULL;
    }
}

int main(int argc, char *argv[])
{
    NODE *head = create_list();

    if(!head)
    {
        printf("ERROR: Either malloc() failed or data not found\n");
        return FALSE;
    }
    else
    {
        print_list(head, NULL);
        return TRUE;
    }
}

Ответы [ 2 ]

15 голосов
/ 16 сентября 2010

Это стало довольно длинным ответом.Не принимайте это на свой счет, но вы сделали немало ошибок новичка.В университете я встречался со многими людьми, которым помогал изучать язык Си и программирование в целом, поэтому я привык замечать подобные вещи.

Важные проблемы, которые я мог найти

  • Вы назначаете указатель на переменную стека на words
    Это очень плохо, потому что это значение будет перезаписано, как только выполнение выйдет из функции, которая создаетЭто. Решение: скопируйте содержимое этой переменной в переменную кучи.

  • Ваша функция append неисправна
    Она добавляетдобавлен элемент на второе место вместо последнего.Обратите внимание, что вам не нужен возврат в конце.Также нет смысла требовать двойной указатель в качестве входных данных для метода append.Кроме того, после присвоения head tmp бесполезно проверять tmp и NULL, поскольку оно не будет NULL, если head не NULL.Также я рекомендую проверить новый узел по NULL.Если это NULL, это избавит вас от итерации по всей коллекции.

  • Функция create_list неоптимальна
    Fist,Различие между первым и другим делом бесполезно.Введение другого указателя (называемого current в моем коде) избавит от необходимости проверять, является ли он первым или нет.Далее, вы всегда вызываете функцию append на head, поэтому вам всегда нужно перебирать всю коллекцию.Это также можно оптимизировать, введя переменную current.(Которому при запуске должно быть присвоено значение head.)

  • Функция print_list ошибочна
    Не печатаетсячто угодно, если есть только один узел.Это также избыточно проверяет указатели на ноль.(В начале цикла это тоже проверяется.) Оператор return в конце этой функции void также не нужен.

  • Вы должны освободить память, когда выне используйте его
    @Baltasarq написал в своем ответе хорошую функцию clear, вы должны использовать ее.:)

Несерьезные ошибки, но вы должны знать о них

  • Не следует использовать void* вместо char* ЕслиВы знаете, что data член структуры NODE будет хранить символы, почему вы используете void*?Это плохая практика!(Если, конечно, у вас нет веских причин.)

  • Использование слова new в качестве имени переменной делает ваш код несовместимым с C ++.Таким образом, я рекомендую против этого.

  • Примите лучший стиль кодирования, пожалуйста - это сделает ваш код намного проще для чтения

  • Несоответствие: если в print_list вы не выделяете новую переменную для прохода по коллекции (как вы делаете с переменной tmp в append), то ошибочно называть параметр head.(Я переименовал его в node в моем коде.)

Вот фиксированный код

(Обратите внимание, что могут быть небольшие синтаксические ошибки, потому что янабрал код в браузере, не проверяя его.)

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

typedef struct node
{
    void *data;
    struct node *next;
} NODE;

NODE *new_node(void *data)
{
    NODE *newNode = (NODE*)malloc(sizeof(NODE));
    if (newNode)
    {
        newNode->data = data;
        newNode->next = NULL;
        return newNode;
    }
    return NULL;
}

void append(NODE *head, NODE *node)
{
    if (head && node)
    {
        NODE *tmp = head;
        while (tmp->next)
            tmp = tmp->next; 
        tmp->next = node; /* add as last node */
    }
}

void print_list(NODE *node, void (print_fn) (void*))
{
    while (node)
    {
        if (print_fn)
            print_fn(node->data);
        else
            printf("Word: %s\n", (char *)node->data);

        node = node->next;
    }
}

NODE *create_list()
{
    FILE *dict_file = fopen("trial.txt", "r");

    if (dict_file)
    {
        NODE *head = NULL;
        NODE *current = head;

        char word[20];
        memset(word, '\0', 20);

        while (fgets(word, sizeof(word), dict_file))
        {
            // Creating a variable on the heap
            char *data = calloc(sizeof(word) + 1, sizeof(char));
            // Copying the contents of words to it
            strcpy(data, word);

            append(current, new_node((void*)data));
            if (current->next)
                current = current->next
        }
        fclose(dict_file);
        return head;
    }
    else
    {
        printf("ERROR: File not found");
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    NODE *head = create_list();

    if (!head)
    {
        printf("ERROR: Either malloc() failed or data not found\n");
    }
    else
    {
        print_list(head, NULL);
    }
    return 0;
}
1 голос
/ 16 сентября 2010

Будьте осторожны, так как malloc () и производные могут отвечать указателем NULL, когда недостаточно памяти.Фактически, учтите, что вам также понадобится метод clear () , который освобождает все данные, а также сами узлы.

void clear(NODE *node)
{
    NODE * temp = NULL;

    while( node != NULL ) {
       temp = node->next;
       free( node->data );
       free( node );

       node = temp;
    }
}

Ваша функция main ()должен возвращать код выхода в операционную систему EXIT_SUCCESS или EXIT_FAILURE вместо TRUE или FALSE.

int main(int argc, char *argv[])
{
    NODE *head = create_list();
    int toret = EXIT_SUCCESS;

    if(!head)
    {
        printf("ERROR: Either malloc() failed or data not found\n");
        toret = EXIT_FAILURE;
        clear( head );
    }
    else
    {
        print_list(head, NULL);
        clear( head );
    }

    return toret;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...