簡體   English   中英

C鏈表指針問題(無限循環)

[英]C Linked list pointer problems (infinite loop)

編輯:添加了新代碼,當前問題是當我插入一個節點時,它工作正常,但是如果我插入多個節點,則insert_node方法永遠不會完成,第一條語句會打印出來,說“插入已調用”,那么它將永遠不會完成“插入完成” ”永遠不會打印。

我唯一能想到的是while循環條件,但是我看不到為什么這是無限的。

另外,當我插入1個節點時,它可以正常打印,但從不停止打印,這又是另一個無限循環。

關於所說錯誤的原因有什么想法嗎?

 /* 
 * File:   main.c
 * Author: che16
 *
 * Created on 20 November 2013, 08:59
 */

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

#include "structure.h"

/*
 * 
 */

node* head = NULL;
int set_head = 0;

int main(int argc, char** argv) {

    int no;

    printf("enter amount of books \n");

    scanf("%d", &no);

    create_books(no);
    print_list(head);


    return (EXIT_SUCCESS);

}

node* create_books(int no_of_books) {
    char title[50];
    char author[30];
    unsigned int number;
    int i;

    for (i = 0; i < no_of_books; i++) {
        node* new_node;
        new_node = (node *) malloc(sizeof (node));
        printf("enter book title \n");
        scanf("%s", title);
        printf("enter author name \n");
        scanf("%s", author);
        printf("enter ISDN number \n");
        scanf("%10u", &number);

        strncpy(new_node->btitle, title, 40);
        strncpy(new_node->name, author, 40);

        new_node->isbn = number;
        new_node->n = NULL;

        if (!set_head) {
            head = new_node;
            insert_node(head, new_node);
            set_head = 1;
            continue;
        }
        insert_node(head, new_node);
    }
}

void insert_node(node* head, node* insert) {
    printf("insert called \n");
    insert->n = NULL;

    if (head == NULL) {
        head = insert;
    } else {
        node* curr = head;

        while (curr->n != NULL) {
            curr = curr->n;
        }
        curr->n = insert;
    }
    printf("insert complete \n");

}

void delete_node(node* head, node * node) {

}

void print_list(node * head) {
    while (head) {
        printf("%s: \"%s\" (%u)\n", head->btitle, head->name, head->isbn);

        head = head->n;
    }
}

您的代碼有幾個問題。

首先,您分配了過多的內存。 臨時局部變量只是指向現有內存的指針。 您要分配內存的唯一位置是create_book ,您可以在其中創建數據。 您必須通過稍后刪除節點來free該內存。 (我認為您可能會對指針所扮演的不同角色感到困惑:有時它們只是標識新分配的內存,更多時候它們被用於訪問和遍歷已經存在的內存。)

接下來, head本身並不是一個節點,它只是指向第一個節點的指針。 如果沒有節點,則此指針為NULL 在程序開始時就是這樣,這意味着您必須對其進行初始化:

node* head = NULL;

但是,如果所有書籍都已從清單中刪除,也是如此。 顯然,如果添加第一個節點或刪除第一個節點,則head改變。 您的insert_node應該注意這些更改。 一種方法是將head作為指針傳遞給節點指針。

(在C語言中,作為參數傳遞的所有內容都是本地副本。更改is將使調用函數中的原始值保持不變。但是,如果傳遞指針,則在調用函數和被調用函數中指向的東西都是相同的。您可以通過poiner進行更改。)

此外,無論是head需要改變應該是關注insert_node的不是調用( 客戶端 )的代碼, main 如果跳過所有錯誤的malloc,則插入會容易得多:

void insert_node(node **head, node* insert)
{
    insert->n = NULL;

    if (*head == NULL) {
        *head = insert;
    } else {
        node* curr = *head;

        while (curr->n) curr = curr->n;
        curr->n = insert;
    }
}

您可以像這樣從main無條件調用它:

insert_node(&head, create_book(title, author, number));

請注意,所有這些也使head_set多余:如果設置了head ,則它具有合法的指針值,否則為NULL

發生抱怨指針不兼容的編譯器錯誤,因為該結構沒有名稱。 在C語言中,結構類型由單詞struct和名稱定義。 有人認為,該struct的關鍵字是不必要的, typedef的結構為單字類型。 您可以在單個語句中執行此操作。 您可以聲明:

typedef struct node {
    char btitle[40];
    char name[40];
    unsigned int isbn;
    struct node* n;
} node;

或者您可以將類型和結構分開:

typedef struct node node;

struct node {
    char btitle[40];
    char name[40];
    unsigned int isbn;
    struct node* n;
};

typedef可能會進入主源文件中的標頭和結構中。)

您會注意到,我已經將char *btitle更改為char btitle[40] 如果僅存儲指向標題的指針,則實際上將指向本地緩沖區title的指針存儲在main 該緩沖區用於循環輸入,在打印書籍時,該緩沖區包含第三本書的值。 這意味着列表中的所有書籍將具有相同的名稱和作者。

解決此問題的一種方法是將指向緩沖區的內容復制到該結構中,該結構當然必須為其緩沖區提供內存,如上所示。 您的create_book變為:

node* create_book(char* t, char* auth, unsigned int num)
{
    node* new_node;

    new_node = malloc(sizeof (node));

    strncpy(new_node->btitle, t, 40);
    strncpy(new_node->name, auth, 40);
    new_node->isbn = num;
    new_node->n = NULL;

    return new_node;
}

例程strncpy最多40個字符從第二個緩沖區復制到第一個緩沖區。 您應該在原型中包含<string.h> 還要注意,我將指向下一個節點的指針初始化為n ,將其n顯式指定為NULL ,就像我在main中使用head 下一個節點指針始終為NULL或指向有效節點的指針。

現在插入工作正常了,打印列表很容易:

void print_list(node* head)
{
    while (head) {
        printf("%s: \"%s\" (%u)\n", head->btitle, head->name, head->isbn);

        head = head->n;
    }
}

查看代碼如何僅使用節點自身中包含的數據,以及如何使用head == NULL或僅head fo short作為到達列表末尾的便捷標准。 print_node函數不需要將head作為指針傳遞給node指針,因為它從不更改列表,而只是檢查其數據。)

仍然有一些問題需要解決,例如在使用后刪除節點(或while列表)以及如何處理分配失敗的問題,但是通過這些更改,您的代碼至少應該編譯並運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM