Чтение строк по одной из файла и добавление их в связанный список

Я пытаюсь прочитать строки из текстового файла одну за другой и добавить их в связанный список. Узлы содержат саму строку и количество вхождений строки в файле. Таким образом, каждая строка будет добавлена ​​в связанный список только один раз, если в связанном списке уже есть строка, переменная int num в узле должна быть увеличена на единицу. Использование массивов запрещено.

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

node* addToHead(node *head, char word[])
{
    if (Contains(head, word) == 0)
    {
        node *tmp = (node*)malloc(sizeof(node));
        tmp->word = (char)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        tmp->word = word;
        tmp->num = 1;

        if (head == NULL)
        {
            tmp->next = NULL;
            head = tmp;
        }
    }
    return head;
}
node* add(node *head, char word[])
{
    if (Contains(head, word) == 0)
    {
        node *iter = head;
        node *tmp = (node*)malloc(sizeof(node));
        tmp->word = (char)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        tmp->word = word;
        tmp->num = 1;
        if (head != NULL)
        {
            while(iter->next != NULL)
                iter = iter->next;

            iter->next = tmp;
            tmp->next = NULL;
            return head;

        }
        else if (head == NULL)
        {
            head = addToHead(head, word);
            return head;
        }

    }
 return head;
}
int Contains(node *head, char word[])
{
    node *iter = head;
    while(iter!= NULL)
    {
        if (strcmp(iter->word, word) == 0)
        {
            iter->num++;
            return 1;
        }
        iter = iter->next;
    }
    return 0;
}
void printList(node *head)
{
    node *iter = head;
     while(iter!=NULL)
    {
        printf("word: %s || number of word: %d\n", iter->word, iter->num);
        iter=iter->next;
    }
}
   int main()
   {
        node *head=NULL;


    FILE* file= fopen("text.txt", "r");
    char word[500];

    for(int i = 0; fscanf(file, "%s", word) != EOF; i++)
    {

        head = add(head, word);

        printList(head);

    }
    printList(head);




    return 0;
}

В этом коде я переписываю связанный список каждый раз, когда добавляю новую строку в связанный список. Насколько я могу судить, он не создает новый узел, а перезаписывает слово на ранее добавленном слове. Запятые и точки не проблема. Я написал один и тот же абзац Lorem Ipsum 3 раза. Вывод такой:

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

Хм. Ваша проблема в том, где вы назначаете строку. Вы выделяете память с помощью malloc, а в следующей инструкции вы назначаете указатель, содержащий выделенную память, на word. Это означает, что (а) у вас больше нет доступа к выделенной памяти, что является утечкой памяти, и (б) что все они имеют одни и те же данные, то есть все, что написано в линейном буфере, если он все еще «жив». C довольно явный, и после выделения достаточного количества байтов для длины строки и терминатора вы должны strcpy ввести строку в эту память.

M Oehm 26.12.2020 18:31

Возможно, вы слышали, что в C не следует приводить результат malloc. С++ требует приведения типов, поэтому некоторые люди все равно это делают. Но чего вы определенно не хотите делать, так это приводить указатель к char — вы попытаетесь сохранить 64-битное значение в 8 битах, что является рецептом катастрофы. Потеряйте состав и, пока вы это делаете, также замените sizeof(char) на 1. У тебя все будет хорошо и хорошо, коротко malloc(strlen(word) + 1));

M Oehm 26.12.2020 18:35

ОМГ большое спасибо. strcpy() решил все мои проблемы.

Yekta Yüksel 26.12.2020 18:48

Использование массивов запрещено. Тогда у вас возникнут проблемы с хранением строк. Строки — это не что иное, как массив char, где последний char имеет значение '\0'.

Andrew Henle 26.12.2020 18:52

@AndrewHenle Выделение памяти и сохранение в ней данных (формирование строки) на самом деле не создает массив. OTOH, printf("word: %s || number of word: %d\n" действительно использует массив. В любом случае "Использование массивов запрещено". является размышлением о слабом задании, подчеркивающем неправильные идеи.

chux - Reinstate Monica 26.12.2020 19:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Протестировано с массивом фиксированного размера из 6 строк, ваши коды работают правильно, и вывод соответствует ожидаемому:

int main()
{
    node *head=NULL;
    char * word[6] = {"Alpha", "Beta", "Alpha", "Teta", "Alpha", "Beta"};

    for(int i = 0; i<6; i++)
    {
        head = add(head, word[i]);
    }
    printList(head);
    return 0;
}

Выход :

word: Alpha || number of word: 3
word: Beta  || number of word: 2
word: Teta  || number of word: 1

Итак, как объясняется в комментариях, проблема скорее в том, как вы выделяете эти строки и/или читаете их из файла.

Ответ принят как подходящий

Как указано выше, есть несколько проблем с вашим кодом:

  1. tmp->word = (char)malloc((sizeof(char)* strlen(word) + sizeof(char)));. Malloc возвращает указатель на выделенный адрес, поэтому вы должны написать: tmp->word = (char *)malloc((sizeof(char)* strlen(word) + sizeof(char)));

  2. Вот почему вы не получаете ожидаемого результата: tmp->word = word;, делая это, даже если вы выделяете новый узел, его поле слова указывает на текущее слово. Таким образом, когда вы читаете слово в цикле, вы случайно меняете head->word. Так что вы должны делать это таким образом strcpy(tmp->word, word).

Я также добавил исправленный код для справки.

#include<stdio.h>
typedef struct node
{
    char *word;
    int num;
    struct node *next;
} node;

node* addToHead(node *head, char word[])
{
    if (Contains(head, word) == 0)
    {
        node *tmp = (node*)malloc(sizeof(node));
        //tmp->word = (char)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        //tmp->word = word;
        tmp->word = (char *)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        strcpy(tmp->word, word);
        tmp->num = 1;

        if (head == NULL)
        {
            tmp->next = NULL;
            head = tmp;
        }
    }
    return head;
}
node* add(node *head, char word[])
{
    if (Contains(head, word) == 0)
    {
        node *iter = head;
        node *tmp = (node*)malloc(sizeof(node));
        //tmp->word = (char)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        //tmp->word = word;
        tmp->word = (char *)malloc((sizeof(char)* strlen(word) + sizeof(char)));
        strcpy(tmp->word, word);
        tmp->num = 1;
        if (head != NULL)
        {
            while(iter->next != NULL)
                iter = iter->next;

            iter->next = tmp;
            tmp->next = NULL;
            return head;

        }
        else if (head == NULL)
        {
            head = addToHead(head, word);
            return head;
        }

    }
 return head;
}
int Contains(node *head, char word[])
{
    node *iter = head;
    while(iter!= NULL)
    {
        if (strcmp(iter->word, word) == 0)
        {
            iter->num++;
            return 1;
        }
        iter = iter->next;
    }
    return 0;
}
void printList(node *head)
{
    node *iter = head;
     while(iter!=NULL)
    {
        printf("word: %s || number of word: %d\n", iter->word, iter->num);
        iter=iter->next;
    }
}
   int main()
   {
        node *head=NULL;


    FILE* file= fopen("text.txt", "r");
    char word[500];

    for(int i = 0; fscanf(file, "%s", word) != EOF; i++)
    {

        head = add(head, word);

        printList(head);


    }
    printList(head);




    return 0;
}

Другие вопросы по теме