1

私は C を学んでおり、このプログラムでは単純な連結リストを実装しようとしています。リストの各ノードには、整数と次のノードへのポインターが含まれます。ポインターheadはリストの最初のノードを指しますが、最初はリストが空なので、初期化しhead = NULLました。

リストに対して2つの操作を実行したい-入力して印刷します。

insert_nodeリストにデータを入力するために、2 つの引数を指定して function を呼び出しています:headと、挿入する整数です。

問題はinsert_node、値を変更する関数が必要なことですhead(したがって、NULL ではなく、更新されたリストを指します)。その方法がわからないのでhead、グローバル変数を作成し、その値を変更しようとしています。何らかの理由でhead、関数内で の値が変更されているにもかかわらず、insert_node再度関数を呼び出すと、head の値は NULL のままです。

質問:

  1. グローバル変数の値がグローバルに変更されないのはなぜですか?

  2. グローバル変数の使用が適切でないことは承知していますが、リストへのポインターを適切に更新するにはどうすればよいでしょうか? insert_node関数が実際にリストへのポインターを返すようにすることを考えていましたが、これは良い方法ですか?

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


struct node {

  int data;
  struct node *link;
};

void insert_node(struct node *head, int n); 
void print_list(struct node *head);

struct node *head = NULL;

main() {

  int i;

  for(i=1; i<5; i++) 

      insert_node(head, i*i);

  print_list(head);

}

void print_list(struct node *head) {

  if(head == NULL) 

      return;

  else {

      printf("%i ", head->data);  
      print_list(head->link);
  }

  return;
}


void insert_node(struct node *head, int n) {

  struct node N = {n, NULL};
  struct node *next, *prev;
  int prev_data = 0;

  //case one: list is empty - point head to N, and set N.link to NULL

  if(head == NULL) 

      head = &N;

  //case two: n is less than first element in the list:

  else if(n < head->data) {

      N.link = head;
      head = &N;
  }


  else {

      next = head;

  //case three: N.data is equal to existing element, do nothing:

      while(next != NULL) {

          if(n == next->data) {

              printf("this element already exists.\n\n");
              return; 
          }
          prev = next;          //save the current element
          next = next->link;    //look at the next element
      }

  //case four: N.data is greater than last element:

      if(n > prev->data) {

          prev->link = &N;
          return;
      }

  //case five: N.data is in between list elements:

      next = head;

      while(next != NULL) {

          prev_data = next->data;   //save the current element
          prev = next;              //save pointer to current element
          next = next->link;        //look at the next element

          if((n > prev_data) && (n < next->data)) {

              prev->link = &N;
              N.link = next;
              return;
          }
      }
  }

  return;

}
4

3 に答える 3

5
  1. globalhead を valueで functionに渡すためですinsert_node()
    次に、関数insert_node()はローカル変数を作成します(ちなみに、headこれはローカルでありグローバルではないため、混乱する可能性のある名前も持っています)。ローカルheadおよびそれらの変更がグローバル変数に表示されないように変更しますhead。これはいわゆるシャドウイングです (同じ名前の変数ですが、ローカル スコープ内では、同じ名前の他の変数とは区別されます)。
  2. 先頭のアドレスを関数に渡し、関数の引数ポインタを構造体へのポインタにする。

宣言

void insert_node(struct node **ptr_to_head, int n);

使用法

insert_node(&head, 5);

ptr_to_headこれで、insert_node関数内で逆参照することで head を変更できます。

(*ptr_to_head)=&new_node;
     ^            ^
     |            |
   head       =  value returned by malloc 

そうです、insert_node 関数から戻ることはできますが、main 関数でhead代入を行うことを忘れないでください。head

于 2013-10-06T21:45:17.587 に答える
1

head という名前のグローバル変数を追加しましたが、同じ名前を持つ関数 insert_node、print_list などのパラメーターを削除するのを忘れました。ローカルはグローバルよりも優先されるため、割り当てはグローバルではなくローカルに割り当てられます。

同じ名前のパラメーターを削除すると、問題は解決します。

ただし、グローバルの使用を容認しているわけではありません:)

于 2013-10-06T22:08:09.833 に答える