2016-12-31 20 views
0

リンクリストの先頭に要素を挿入するCプログラムがありますが、要素を印刷しようとすると常に最初の要素がスキップされます。誰かが自分のプログラムで間違っていることを指摘できますか?リンクリストトラバーサルは最初の要素をスキップします

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


void PrintElements(); 
void InsertElement(int x); 

struct node 
{ 
    int data; 
    struct node* next; 
}; 

struct node* HEAD; 
struct node* temp; 
struct node* temp1; 


void PrintElements() 
{ 
    temp1=HEAD; 
    while(temp1->next!=NULL) 
    { 
     printf("\n\r Data %d\n\r",temp1->data); 
     printf("\n\r Address %x\n\r",temp1->next); 
     temp1=temp1->next; 
    } 
} 

void InsertElement(int x) 
{ 
    struct node* temp=(struct node*)malloc(sizeof(struct node)); 
    temp->data=x; 
    temp->next=HEAD; 
    HEAD=temp; 

} 

int main() 
{ 

    int i, x; 
    int n; //n stores the number of elements to be added to the linked list 
    HEAD=NULL; //Assigning HEAD to null when there are no elements in the list 
    printf("Enter the number of elements\n"); 
    scanf("%d",&n); 
    for(i=0;i<n;i++) 
    { 
     printf("\n\rEnter the number"); 
     scanf("%d",&x); 
     InsertElement(x); 
     PrintElements(); 
    } 

    return 0; 
} 

私は次の行を変更した場合

while(temp1->next!=NULL) 

while(temp1!=NULL) 

にプログラムが正常に動作しますが、私はまだ理由を理解することはできませんよ。

+0

要素のポインタをチェックし、もう1つでは_next_要素へのポインタをチェックする、つまり異なる条件で終了しているためです。長いリストを試してみると、何が起こるかが分かります。 PS:グローバル変数は悪いです。 – Jens

+0

'while(temp1-> next!= NULL)'でチェックすると、最初の要素はスキップされます。 – RoadRunner

+2

変更後の2番目の質問に対する答えは、最初のノードを挿入するとどうなりますか?その時点で 'HEAD'の価値は何ですか? (ヒント: 'NULL')。あなたは常にリストの先頭に挿入するので、 'first'ノードは常に* last *ノードになります。 * last *ノードを印刷するとき、 'node-> next'の値は何ですか? (これは 'NULL'です)。最後のノード(最初の値) 'temp1-> next == NULL'に到達したときに' while(temp1-> next!= NULL) 'を使うと、ループは終了し、最後のノード(最初の値)は出力されません。提案された変更を行うことでその問題は解決されます。 –

答えて

1

PrintElements()の制御式をtemp1 != NULLに変更することで、問題を修正できます。このようにしてtemp1がノードを指している場合は、datanextフィールドが印刷され、ノードがなくなるまでループが続きます。リンクされたリストを反復処理するときは、現在のノードで何をするかを決めるために次のノードを見るときに、通常混乱するようです。しかし、このコードには他にも問題があります。

最初にstructポインタをmain()に宣言し、それらをグローバル変数として宣言するのではなく関数に渡す方がはるかに優れています。可能な限り呼び出す関数の戻り値を確認する必要があります。入力が期待どおりであることを確認するには、scanf()をチェックする必要があります。これはまた、入力ループを制御する方法を提供し、データを入力する前に明示的にカウントを入力する必要がなくなります。また、malloc()への呼び出しによって返された値をチェックして、割り当てエラーを捕捉する必要があります。 tempが非常に次の行で参照解除されると、コード内のそのような割り当てエラーは未定義の動作につながります。

freeすべてのメモリ割り当ては、malloc()への呼び出しごとに1つずつ、free()にする必要があります。関数PrintElements()のリストのnextノードのアドレスを印刷すると、未定義の動作が呼び出されます。ポインタの値を出力するには、%pフォーマット指定子を使用し、ポインタを(void *)にキャストする必要があります。最後に、#include <malloc.h>は必要ありません。 stdlib.hが必要なものを処理します。

ここには、推奨される変更を実装するコードの修正版があります。割り当てエラーの場合、メッセージはstderrに出力され、プログラムはexitに出力されます。 malloc()への呼び出しが簡略化されました。malloc()の結果をC言語にキャストする理由はなく、指定された引数に明示的な型の代わりにメモリを割り当てるポインタの名前を使用する方がよいmalloc()。 が呼び出し関数に返され、リストのheadへのポインタがnew_nodeを指すように再割り当てされます。

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

struct node 
{ 
    int data; 
    struct node* next; 
}; 

void print_elements(struct node *start); 
struct node * insert_element(int x, struct node *head); 


int main(void) 
{ 
    struct node* head = NULL; 
    struct node* curr = NULL; 
    int x; 

    /* Read data into linked list */ 
    printf("Enter the first integer (q to quit): "); 
    while (scanf("%d", &x) == 1) { 
     head = insert_element(x, head); 
     print_elements(head); 
     printf("Enter another integer (q to quit): "); 
    } 

    /* Free allocated memory */ 
    while (head) { 
     curr = head; 
     head = curr->next; 
     free(curr); 
    } 

    return 0; 
} 

void print_elements(struct node *curr) 
{ 
    while(curr) { 
     printf(" Data: %d\n",curr->data); 
     printf("Address: %p\n\n",(void *) curr->next); 
     curr = curr->next; 
    } 
} 

struct node * insert_element(int x, struct node *head) 
{ 
    struct node *new_node = malloc(sizeof(*new_node)); 

    if (new_node == NULL) { 
     fprintf(stderr, "Allocation error in function insert_element()\n"); 
     exit(EXIT_FAILURE); 
    } 

    new_node->data = x; 
    new_node->next = head; 

    return new_node; 
} 
3

while(temp1->next!=NULL)

while(temp1 != NULL)

から

変更にこのそしてそれは正常に動作する必要があります。

理由:入力した最初の要素は印刷されないと思います。使用3 -> 2 -> 1 -> NULL 表記法:すべての数はdataであり、矢印ポインタnextを示す

例:入力:として形成1 2 3

リンクされたリスト。その後

あなたは各反復のために、ループを開始します。

  • プリント(2のアドレスにtemp1 -> nextポイントとして真)3

  • temp1 -> next != NULLのアドレスに

    • temp1ポイント3temp1は、現在2のアドレスを指しています

    • temp1 -> next != NULL(真1のアドレスにtemp1 -> next点として)

    • プリント2temp1は現在1

    • temp1 -> next != NULLのアドレスを指すこれは1のアドレスにtemp1ような点となってtemp1 -> nextはNULLです。

    1のループに入ることはありません。

    正しいことはtemp1 != NULLを使用することです。これは上記のバグを解消するためです。

  • +0

    良い説明!どのJNVからですか? –

    +0

    JNVとは何ですか、わかりません。 –

    関連する問題