2014-10-06 161 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; 

    } 

這是ADDNODE功能

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; 
    } 

和的printList功能

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

這裏是的typedef

#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 

和文本文件的格式,被閱讀爲parsi NG。

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

只是爲了查明錯誤,是否在將它放入列表中以查看打印內容之前是否嘗試過打印?也許這不是一個列表問題,而是一個閱讀問題 – 2014-10-06 11:02:17

+0

另外,如果你不打算編輯文件,使用'fopen(filename,「r」)打開它' – 2014-10-06 11:03:52

+0

當使用setupNode函數功能時,我確保信息正確傳遞在返回之前打印stock_item。所以我知道信息正在正確地傳遞給一個節點。如果您想要這一步,我可以向您展示輸出結果嗎? – 2014-10-06 11:06:18

回答

1

您有undefined behavior,因爲在addNodeBottom中,您可以製作例如current->next指向你分配的新節點,那麼你的新節點免費,所以指向current->next的指針現在指向未分配的內存。

此外,設置當所述第一節點(當head->nextNULL)然後不設置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

謝謝,當我沒有釋放內存時,我最終生成了第一個節點的兩次節點,但所有其他節點都沒有問題。 – 2014-10-06 11:11:47

+0

@JoshuaTheeuf這是因爲你做的任務'head-> next = newNode'。然後在下一次函數被調用時,解引用'head-> next',它現在指向未分配的內存(因爲你執行'free(newNode)')並且你有未定義的行爲。 – 2014-10-06 11:17:30

+0

謝謝。這工作完美。 – 2014-10-06 11:24:41

0

主要問題是因爲您正在創建一個新節點,在其中存儲數據,然後使用free刪除新節點。 我理解你的邏輯,因爲它現在在列表中,所以你不再需要它了。但這不是問題。在列表中,您只需將一個指針指向您創建的新節點。您不要複製列表中的新節點。您只能將指針指向爲您創建的節點分配的內存。如果您釋放該部分內存,則該內存不再存在,並且該部分可以被任何其他應用程序或您的應用程序覆蓋。所以它最終成爲垃圾。

+0

恩,當我不釋放節點我endup與headNode,第二個節點的信息的副本,我不確定這實際上發生的地方。 – 2014-10-06 11:10:53

+0

好的。首先,您必須將'head-> next == NULL'更改爲'head == NULL'。這是檢查列表是否爲空的正確方法。嘗試一下,讓我知道結果 – 2014-10-06 11:14:24

+0

當我這樣做,它忽略headNode,並打印出其他每個節點。所以,當只是打印出ID的時候,我會得到如下輸出:(空)I0001 I0002 I0003 I0004 I0005 所以我不知道。如果我將'code current-> next == NULL'改爲當前==,那麼它會出現segfault。 – 2014-10-06 11:19:33