2014-10-06 2 views
-1

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

void print_list(struct vm_node *root); 
    int addNodeBottom(char *val, struct vm_node *head); 
    struct stock_item* setupNode(char *line); 
    int main(int argc, char * argv[]) { 
     struct vm vm; 
     struct menu_item menu_items[NUM_MENU_ITEMS]; 
     struct vm_node *vmNode; 
     vmNode = malloc(sizeof(struct vm_node)); 

     /* The UNUSED() function is designed to prevent warnings while your 
     * code is only partially complete. Delete these 4 function calls once 
     * you are using the data structures declared above in your own code */ 
     UNUSED(argc); 
     UNUSED(argv); 
     UNUSED(vm); 
     UNUSED(menu_items); 
     if (argc != 3) { 
      printf("insuffcient arguments \n"); 
      return EXIT_SUCCESS; 
     } 

     /*open stock file*/ 
     char* fileName = argv[1]; 
     FILE *file; 
     file = fopen(fileName, "r+"); 
     char buf[256]; 
     vmNode->next = NULL; 

     while (fgets(buf, sizeof buf, file) != NULL) { 

      addNodeBottom(buf,vmNode); 

     } 

     print_list(vmNode); 
     /* Test reason for reaching NULL. */ 
     if (feof(file)) /* if failure caused by end-of-file condition */ 
      puts("End of file reached"); 
     else if (ferror(file)) /* if failure caused by some other error  */ 
     { 
      perror("fgets()"); 
      fprintf(stderr, "fgets() failed in file %s at line # %d\n", __FILE__, 
        __LINE__ - 9); 
      exit(EXIT_FAILURE); 
     } 
     fclose(file); 

     return EXIT_SUCCESS; 
    } 

Следующая функция: как я описал функцию setupNode.

struct stock_item* setupNode(char *line) { 

     struct stock_item *root; 
     root = malloc(sizeof(struct stock_item)); 
     char *ptr; 
     const char del[2] = "|"; 
     const char delm[2] = "."; 
     char *prices; 
     strcpy(root->id, strtok_r(line, del, &ptr)); // returns the ID and stores in in the root node. 
     strcpy(root->name, strtok_r(NULL, del, &ptr)); // returns the description and stores it in the root node. 
     strcpy(root->description, strtok_r(NULL, del, &ptr)); // returns the description and stores it in the root node. 
     prices = strtok_r(NULL, del, &ptr); // returns a string of the price for vm_item. 
     int dol = atoi(strtok(prices, delm)); 
     int cent = atoi(strtok(NULL, delm)); 
     root->price.dollars = dol; 
     root->price.cents = cent; 
     int quantity = atoi(strtok_r(NULL, del, &ptr)); // returns how many items are in stock. 
     root->on_hand = quantity; 
     return root; 

    } 

Это функция

int addNodeBottom(char *val, struct vm_node *head){ 
     //create new node 

     struct vm_node *newNode = malloc(sizeof(struct vm_node)); 
     if(newNode == NULL){ 
      printf("%s", "Unable to allocate memory for new node\n"); 
      exit(-1); 
     } 

     newNode->data = setupNode(val); 
     newNode->next = NULL; // Change 1 

     //check for first insertion 
     if(head->next == NULL){ 
      head->data = newNode->data; 
      head->next = newNode; 
     } 

     else 
     { 
      //else loop through the list and find the last 
      //node, insert next to it 
      struct vm_node *current = head; 
      while (TRUE) { // Change 2 
       if(current->next == NULL) 
       { 
        current->next = newNode; 
        break; // Change 3 
       } 
       current = current->next; 
      }; 
     } 
     free(newNode); 
     return 0; 
    } 

AddNode и перечень печати функция

void print_list(struct vm_node *root) { 
     while (root) { 
      printf("%s ", root->data->id); 
      root = root->next; 
     } 
     printf("\n"); 
    } 

Вот что определение типов

#ifndef VM_TYPE 
    #define VM_TYPE 

    #define IDLEN 5 
    #define NAMELEN 40 
    #define DESCLEN 255 
    #define NUMDENOMS 8 
    #define UNUSED(var) (void)var 
    #define COIN_COUNT 20 
    #define DEFAULT_ONHAND 20 

    /* Type definition for our boolean type */ 
    typedef enum truefalse 
    { 
     FALSE, TRUE 
    } BOOLEAN; 

    /* Each price will have a dollars and a cents component */ 
    struct price 
    { 
     unsigned dollars,cents; 
    }; 

    /* The different denominations of coins available */ 
    enum denomination 
    { 
     FIVE_CENTS, TEN_CENTS, TWENTY_CENTS, FIFTY_CENTS, ONE_DOLLAR, 
     TWO_DOLLARS, FIVE_DOLLARS, TEN_DOLLARS 
    }; 

    /* Each coin in the coins array will have a denomination (20 cents, 
    * 50 cents, etc) and a count - how many of that coin do we have on hand 
    */ 
    struct coin 
    { 
     enum denomination denom; 
     unsigned count; 
    }; 

    /* The data structure that holds the data for each item of stock 
    */ 
    struct stock_item 
    { 
     char id[IDLEN+1]; 
     char name[NAMELEN+1]; 
     char description[DESCLEN+1]; 
     struct price price; 
     unsigned on_hand; 
    }; 

    /* The data structure that holds a pointer to the stock_item data and a 
    * pointer to the next node in the list 
    */ 
    struct vm_node 
    { 
     struct stock_item * data; 
     struct vm_node * next; 
    }; 

    /* The head of the list - has a pointer to the rest of the list and a 
    * stores the length of the list 
    */ 
    struct vm_list 
    { 
     struct vm_node * head; 
     unsigned length; 
    }; 

    /* This is the head of our overall data structure. We have a pointer to 
    * the vending machine list as well as an array of coins. 
    */ 
    struct vm 
    { 
     struct vm_list * item_list; 
     struct coin coins[NUMDENOMS]; 
     char * foodfile; 
     char * coinsfile; 
    }; 

    #endif 

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

I0001|Coke   |375 ml Can of coke           |3.50|50 

I0002|Pepsi   |375 ml Can of pepsi          |3.00|20 

I0003|Lemon Cheesecake|A delicious, 1/8 size slice of cheesecake     |4.00|10 

I0004|Mars Bar  |A delicious 50 g Mars Bar chilled just the way you like it.|3.00|20 

I0005|Lemon Tart  |A delicious lemon butter tart with a pastry based   |3.75|12 

Выход при попытке распечатать список - полный мусор, поэтому любые мысли?

+0

Чтобы точно определить ошибки, попробовали ли вы распечатать их перед тем, как поместить их в список, чтобы увидеть, что напечатано? Возможно, это не проблема с списком, а проблема чтения. –

+0

Также, если вы не планируете редактировать файл, открывайте его с помощью 'fopen (filename,« r »)' –

+0

При использовании функции функции setupNode я гарантировал, что информация передается правильно распечатав файл stock_item перед его возвратом. Поэтому я знаю, что информация передается узлу правильно. Я могу показать вам результат, если вы хотите этого шага? –

ответ

1

У вас есть undefined behavior, потому что в addNodeBottom вы делаете, например. current->next укажите новый узел, который вы выделили, затем освободите новый узел, поэтому указатель в current->next теперь указывает на нераспределенную память.

Кроме того, при установке первого узла (когда head->next является NULL), то не устанавливайте next указатель head, пусть это будет NULL. Вместо того, чтобы провести различие между пустым списком или нет, проверьте ненулевой data поля:

if (head->data == NULL) 
{ 
    // List is empty 
} 
else 
{ 
    // List is not empty 
} 

Других советов: Там нет необходимости выделять новый узел, пока вы на самом деле добавить его в список. И петля, чтобы найти последний узел в списке может быть упрощена следующим образом:

vm_node *current; 
for (current = head; current->next != NULL; current = current->next) 
{ 
    // Empty loop body 
} 

После указанного цикла current будет последним узлом в списке, и теперь вы можете выделить новый узел.


Если бы я переписать функцию addNodeBottom (без изменения функции подписи), это будет выглядеть примерно так (без какой-либо обработки ошибок):

int addNodeBottom(char *val, struct vm_node *head){ 
    //create new node 

    stock_item *data = setupNode(val); 

    if (head->data == NULL) 
     head->data = data; 
    else 
    { 
     vm_node *current; 
     for (current = head; current->next != NULL; current = current->next) 
      ; 

     current->next = malloc(sizeof(*current->next)); 
     current->next->data = data; 
     current->next->next = NULL; 
    } 

    return 0; 
} 

Примечание: Вы должны установите vmNode->data = NULL перед вызовом вышеуказанной функции в первый раз, а не только vmNode->next.

+0

Спасибо, когда я не освободил память, я заканчиваю тем, что узел генерируется дважды для первого узла, но все остальные узлы в порядке. –

+0

@JoshuaTheeuf Это потому, что вы выполняете назначение 'head-> next = newNode'. Затем, в следующий раз, когда вызывается функция, вы разыгрываете «head-> next», которые теперь указывают на нераспределенную память (потому что вы делаете «free (newNode)»), и у вас есть неопределенное поведение. –

+0

Спасибо. Это сработало отлично. –

0

Основная проблема заключается в том, что вы создаете новый узел, сохраняя в нем данные, а затем удаляя новый узел с помощью free. Я понимаю вашу логику, как сейчас, в списке, поэтому вам это больше не нужно. Но это не проблема. В списке вы просто помещаете указатель, указывающий на новый узел, который вы создали. Вы не копируете новый узел в списке.Вы указываете только указатель, указывающий на выделенную память для созданного вами узла. Если вы освободите эту часть памяти, то она больше не существует и эта часть может быть перезаписана любым другим приложением или вашим. Таким образом, это становится мусором.

+0

Ум, если я не освобожу узел i endup с дубликатом информации в headNode и втором узле, и я не уверен, что это происходит на самом деле. –

+0

Хорошо. Сначала вы должны изменить 'head-> next == NULL' на' head == NULL'. Это правильный способ проверить, пуст ли список. Попробуйте это и сообщите мне об итогах –

+0

Когда я это делаю, он игнорирует headNode и печатает каждый другой узел. Поэтому, когда просто распечатываю идентификатор, я получаю следующий вывод: (null) I0001 I0002 I0003 I0004 I0005 Так что я понятия не имею. Если я меняю 'current current'> next == NULL на current == next, то появляется segfault. –

Смежные вопросы