Почему моя настольная программа ha sh продолжает зависать? - PullRequest
1 голос
/ 15 апреля 2020

Я пытаюсь создать программу, которая читает словарь, а затем сохраняет слова в таблице ha sh, а затем читает другой файл, проверяет каждое слово этого файла, если оно находится в таблице ha sh, если оно не тогда он будет выведен как слово с ошибкой. Сначала я пытаюсь проверить, могу ли я загрузить файл словаря в свою таблицу ha sh, а затем вывести слова в таблицу ha sh, но мой код, похоже, обрабатывает sh всякий раз, когда я пытаюсь его запустить. Используемая мной функция ha sh была взята из Inte rnet. Я также все еще плохо знаком со структурами данных, и мне трудно понять.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// file to read
#define dictionary "dictionary.txt"
// No. of buckets
const unsigned int N = 10;

typedef struct node
{
    char* word;
    struct node *next;
}
node;

node *table[10];

// hash function
unsigned int hash(char *word)
{
// TODO
    unsigned int hash = 5381;
    int c = 0;

    while (c == *word++)
        hash = ((hash << 5) + hash) + c;

    return hash % 10;
}

int main(void)
{
    // initialize array heads to NULL
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }

    // Open file to read
    FILE *indata = fopen(dictionary, "r");   
    if (indata == NULL)
    {
        printf("cant open\n");
        return 1;
    }

    // variable to store words read from the file
    char *words = malloc(sizeof(char) * 20);
    if (words == NULL)
    {
        printf("no memory\n");
        return 1;
    }

    // While loop to read through the file
    while (fgets(words, 20, indata))
    {
        // get the index of the word using hash function
        int index = hash(words);

        // create new node
        node *newNode = malloc(sizeof(node));
        if (newNode == NULL)
        {
            printf("here\n");
            return 1;
        }

        // make the new node the new head of the list
        strcpy(newNode->word, words);
        newNode->next = table[index];
        table[index] = newNode;

        // free memory
        free(newNode);
    }
    // free memory
    free(words);
    // loop to print out the values of the hash table
    for (int i = 0; i < N; i++)
    {
        node *tmp = table[i];
        while (tmp->next != NULL)
        {
            printf("%s\n", tmp->word);
            tmp = tmp->next;
        }
    }

    // loop to free all memory of the hash table
    for (int i = 0; i < N; i++)
    {
        if (table[i] != NULL)
        {
            node *tmp = table[i]->next;
            free(table[i]);
            table[i] = tmp;
        }
    }

    // close the file
    fclose(indata);
}

Ответы [ 2 ]

0 голосов
/ 15 апреля 2020

По крайней мере три ошибки, которые независимо вызвали segfault:

Во-первых, newNode->word используется unitialized , поэтому он указывает на случайную память, поэтому strcpy будет segfault. Лучше использовать strdup

Кроме того, после того, как вы положили newNode в таблицу, вы делаете free(newNode), делая то, что он указывает на недействительным. Это приводит к тому, что второй l oop переходит в состояние сбоя

В-третьих, во втором l oop, если table[i] равно нулю, while (tmp->next != NULL) будет прерваться из-за ошибки

Я комментировал и исправил ваш код:

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

// file to read
#define dictionary "dictionary.txt"

// No. of buckets
const unsigned int N = 10;

typedef struct node {
    char *word;
    struct node *next;
} node;

node *table[10];

// hash function
unsigned int
hash(char *word)
{
// TODO
    unsigned int hash = 5381;
    int c = 0;

    while (c == *word++)
        hash = ((hash << 5) + hash) + c;

// NOTE: not a bug but probably better
#if 0
    return hash % 10;
#else
    return hash % N;
#endif
}

int
main(void)
{
    // initialize array heads to NULL
    for (int i = 0; i < N; i++) {
        table[i] = NULL;
    }

    // Open file to read
    FILE *indata = fopen(dictionary, "r");

    if (indata == NULL) {
        printf("cant open\n");
        return 1;
    }

    // variable to store words read from the file
    char *words = malloc(sizeof(char) * 20);

    if (words == NULL) {
        printf("no memory\n");
        return 1;
    }

    // While loop to read through the file
    while (fgets(words, 20, indata)) {
        // get the index of the word using hash function
        int index = hash(words);

        // create new node
        node *newNode = malloc(sizeof(node));

        if (newNode == NULL) {
            printf("here\n");
            return 1;
        }

        // make the new node the new head of the list
// NOTE/BUG: word is never set to anything valid -- possible segfault here
#if 0
        strcpy(newNode->word, words);
#else
        newNode->word = strdup(words);
#endif
        newNode->next = table[index];
        table[index] = newNode;

        // free memory
// NOTE/BUG: this will cause the _next_ loop to segfault -- don't deallocate
// the node you just added to the table
#if 0
        free(newNode);
#endif
    }

    // free memory
    free(words);

    // loop to print out the values of the hash table
    for (int i = 0; i < N; i++) {
        node *tmp = table[i];
// NOTE/BUG: this test fails if the tmp is originally NULL (i.e. no entries
// in the given hash index)
#if 0
        while (tmp->next != NULL) {
#else
        while (tmp != NULL) {
#endif
            printf("%s\n", tmp->word);
            tmp = tmp->next;
        }
    }

    // loop to free all memory of the hash table
    for (int i = 0; i < N; i++) {
        if (table[i] != NULL) {
            node *tmp = table[i]->next;

            free(table[i]);
            table[i] = tmp;
        }
    }

    // close the file
    fclose(indata);
}

ОБНОВЛЕНИЕ:

Я создал программу со связанным списком до того, как она сохранит целое число в списке, int number; struct node *next; а я использовал newNode->number = 5; и это сработало, почему в этом случае это не так ?? Это потому, что я здесь работаю со строками ??

Разница в том, что word является указателем . Ему должно быть присвоено значение, прежде чем его можно будет использовать. strcpy не не присваивает значение word. Он пытается использовать содержимое word в качестве адреса назначения копии.

Но другие две ошибки происходят независимо от того, * word является char * против number будучи int.

Если вы определили word не как указатель, а как фиксированный массив [не так хорош в этом использовании], strcpy сработало бы. То есть вместо char *word;, если вы сделали (например) char word[5];

Но то, что вы сделали, лучше [с изменением strdup], если вы не можете гарантировать, что длина word может держать вход. strdup гарантирует это.

Но обратите внимание, что я [намеренно] сделал word только пять символов, чтобы проиллюстрировать проблему. Это означает, что добавляемое слово может быть длиной всего 4 символа [нам нужен один дополнительный байт для нулевого символа-терминатора]. Вам нужно было бы использовать strncpy вместо strcpy, но strncpy имеет проблемы [он делает не гарантированно добавить нулевой символ в конце, если длина источника слишком велика].

Кстати, сегодня существует еще один вопрос, на который есть ответ, который может помочь пролить немного света на различия вашего элемента word struct: Разница в распределении памяти элемента структуры (указатель или массив) в C

0 голосов
/ 15 апреля 2020

Беглый взгляд Я вижу две проблемы:

  1. Вы не выделяете место для своего слова в узле; Вы просто strcopy слово в неопределенный указатель. Возможно, вы захотите использовать strdup.

  2. Вы освобождаете память узла после добавления ее в список. Таблица представляет собой массив указателей, поэтому вы сохраняете точку в таблице, а затем выбрасываете память, на которую она указывает.

О, три: и в конечном l oop Вы снова освобождаете нераспределенную память ...

...