Warm tip: This article is reproduced from serverfault.com, please click

print from users input linked list of struct

发布于 2020-11-28 01:09:26

I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.

I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.

I've tried debugging it, but I can't seem to find the problem. I removed all printf lines that I used to debug. I also removed all the irrelevant code.

I am looking to know how to fix it and what is wrong so I can run it with no problems.

What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well. I also tried using a double pointer instead of returning para but that didn't help.

any help will be appreciated,

thanks in advance

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

typedef struct word
{
    char * ch;//poiter to char
}
W;
typedef struct sentence
{
    W * currentWord;//pointer to a word
    int lineNumber;// holds the line number
    int numbersOfWords;//holds the number of words
    struct sentence* link;
}
sent;
typedef struct list
{
    sent* head;
    int count;
}
LISTS;

LISTS* createList()
{
    LISTS* list;
    list= (LISTS*) malloc (sizeof (LISTS));
    if (list)
    {
        list-> head = NULL;
        list-> count = 0;
    }
    return list;
} // createList
void printList(LISTS*  list)
{
    sent *temp = list -> head;

    //iterate the entire linked list and print the data
    while(temp != NULL)
    {
        printf("%s\n", temp->currentWord->ch);
        temp = temp->link;
    }
//    printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
    sent* newPtr; //new node
      if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
        printf(" Memory can not be allocated.");
        return;
    }
    newPtr->currentWord = itemPtr;
    newPtr->link = NULL;
    if(list->head == NULL)
    {
        list->head = newPtr;
    }else{
    sent* current = list->head;
    while(current->link != NULL){
        current = current->link;
        }
    current -> link = newPtr;
        }
    (list->count)++;
    return;
}  // insertList
LISTS * input1(LISTS *para)
{
    char * line;
    line = (char * ) malloc(1000 * sizeof(char));
    line[0] = '\0';

    while (line[0] != '\n')
    {
      W word;
            word.ch = (char * ) malloc(100);
      printf(" Please input a line : ");
      fgets(line, 1000, stdin);
      if(line[0] != '\n'){
        strcpy(word.ch, line);
                insertSentList(para,&word);
            }
    }
    free(line);
    return para;
}
int main()
{
    ///////////////////test////////////////
  LISTS* list = createList();
    
  W word;
  word.ch= "word0 ";
  W word1;
  word1.ch= "word1 ";
  W word2;
  word2.ch= "word2";

  insertSentList(list,&word);
  insertSentList(list,&word1);
  insertSentList(list,&word2);
    insertSentList(list,&word);
  insertSentList(list,&word1);
  insertSentList(list,&word2);

  printList(list);
    ///////////////////test////////////////

  LISTS *para = createList();
  para= input1(para);
  printList(para);

  return 0;
}
Questioner
hitomi layla
Viewed
1
dxiv 2020-11-28 12:03:32

Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.

The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.

void insertSentList (LISTS* list, W* itemPtr)
{
    sent* newPtr; //new node
      if (!(newPtr = malloc(sizeof(sent)))){
        printf(" Memory can not be allocated.\n");
        return;
    }
    W *newItem = malloc(sizeof(W));    // <-- make a deep copy of the `itemPtr` argument
    newItem->ch = strdup(itemPtr->ch); //     including a copy of the string itself
    newPtr->currentWord = newItem;     // <-- save the copy in the list, not the argument
    newPtr->link = NULL;
    if(list->head == NULL)
    {
      list->head = newPtr;
    }else{
      sent* current = list->head;
      while(current->link != NULL){
        current = current->link;
      }
      current->link = newPtr;
    }
    list->count++;
}  // insertList

For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.

void freeList(LISTS *list)
{
    sent *temp = list->head;
    while(temp != NULL)
    {
      sent *next = temp->link;
      free(temp->currentWord->ch);
      free(temp->currentWord);
      free(temp);
      temp = next;
    }
    free(list);
}