C言語構造体ポインタ初期化(回転)

9388 ワード

reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html
今日はCのメモリ管理について議論します.先週、食卓で同僚とC言語の台頭について話し合ったとき、メモリ管理について話したとき、私はすべてのポインタを使用する前に初期化しなければならないと言っていました.構造体のメンバーポインタも同じで、そうではないでしょうか.以前二叉木アルゴリズムをしていたとき、彼の左右の子供のポインタを使用していたときに初期化したのではないでしょうか.その時、私はなぜか理由が思いつかなかったのです.初期化すると信じていたが、数日後に同僚が試してみたと言った.構造体のメンバーポインタは初期化されていないので(左サブツリーと右サブツリーポインタ)ドキュメントの整理に追われていたので、今日はエアコンを抜いてみたが、結論は、初期化が必要だった.そして、コードを書かないと原因が分からない(パソコンに長い間IQと記憶性が大幅に下がっているのかもしれない)テストコードは以下の通りである
struct student{   
  char     *name          ;   
  int      score          ;   
  struct   student * next ;   
}stu,*stu1;    
  
int main(){    
  stu.name = (char*)malloc(sizeof(char));     /*1.            */  
  strcpy(stu.name,"Jimy")               ;   
  stu.score = 99                        ;   
  
  stu1 = (struct student*)malloc(sizeof(struct student))   ;/*2.          */  
  stu1->name = (char*)malloc(sizeof(char))                 ;/*3.                 */  
  stu.next   = stu1                                        ;   
  strcpy(stu1->name,"Lucy")                                ;   
  stu1->score = 98                                         ;   
  stu1->next  = NULL                                       ;   
  printf("name %s, score %d 
",stu.name, stu.score) ; printf("name %s, score %d
",stu1->name, stu1->score) ; free(stu1) ; return 0 ; }

テストコードを書く過程で、同僚が言った二叉木遍歴アルゴリズムで使われている左サブツリーと右サブツリーポインタは初期化する必要はありませんが、実はそうです.左サブツリーと右サブツリーは、ツリーノードタイプの構造体ポインタ(同じ長さのポインタを入力してもよい)を指します.この構造体ポインタは初期化する必要があります.(注2参照)つまり、mallocでメモリを割り当てるのではなく、別のポインタの値を割り当てるということです.たちまち無言で、確かに多くの大学の教材を見て、二叉木の遍歴などのアルゴリズム定義の構造体は以下の形式にほかならない.
struct node{   
  int    data                  ;   
  struct node* lchild, rchild  ;   
};  

使用時に直接的:
 struct node* root;   
 root = (struct node*)malloc(sizeof(struct node));   
 root->data = 3;   
  
 struct node* nlchild;   
 nlchild = (struct node*)malloc(sizeof(struct node));   
 root->lchild = nlchild;   
 nlchild->data = 2;    
  
 struct node* nrchild;   
 nlrchild = (struct node*)malloc(sizeof(struct node));   
 root->rchild = nrchild;   
 nrchild->data = 4;   

構造体メンバーポインタが初期化されていないような錯覚を与える.しかし、ポインタであれば、それを使用する前にポインタ変数の値が有効な値であることを保証しなければならない.そうでなければ、メモリがゴミデータを指しているに違いありません.C言語のメモリ管理は重要で、迫力と面倒を一身に集めて、あなた自身の心理状態を見てみましょう.もしあなたが積極的に直面すれば、あなたはすべてをコントロールしています.イライラしているなら、すべてをコントロールしなければなりません.Cは相変わらず博大で奥深い言語で、信C兄!/*添付:相変わらずポインタ*/
stu1 = (struct student*)malloc(sizeof(struct student));  /*2.          */  

この文はsizeofの中にstruct student*と記入する人もいるかもしれません.stuはもともとstruct student*ですが、このように構造体に十分なメモリを割り当てていません.使用中はメモリエラーで同じようにエラーが発生します.もちろん、構造体ポインタにメモリを割り当てるだけでは十分ではありません.構造体メンバーポインタには、次のようにメモリを割り当てる必要があります.
stu1->name = (char*)malloc(sizeof(char))   ;  

  
自分が構造体のポインタを使っているときに出会った引用問題は、ネット上で探した文字がいいと思います.皆さんに役に立つかもしれません.
構造体ポインタ変数を使用すると、「低レベル」のエラーが発生しやすくなります.すなわち、構造体ポインタ変数を定義すると、構造体ポインタ変数が指す構造体メンバーが直接操作され、わけのわからないエラーが発生します.構造体ポインタ変数を正常に動作させるには、構造体ポインタ変数に有効な構造体変数アドレスを付与する必要があります.例:
struct UART{
             int   a  ;
             uchar b  ;
           }

main()
{
      struct UART  *p;
      p->a = 0xXXX;
      p->b = 0xXX;
      printf("%i,%c",p->b,p->a);
}

このプログラムが出力する値は予知できない.「プログラムでは構造体ポインタ変数が定義されているだけで、構造体ポインタ変数に有効な値が与えられていないため、構造体変数が指すアドレスが不確定になり、予想される結果が得られない」
以下に変更する必要があります.
struct UART{
             int     a  ;
             uchar   b  ;
       }

main()
{
      struct UART  *p  ;
      struct UART  dd  ;
      p = &dd          ;               //      ,            
      p->a = 0xXXX    ;
      p->b = 0xXX     ;
     printf("%i,%c",p->b,p->a);
}

 
 
C/C++中構造体(struct)知識点強化:
構造体という重要な知識点をさらに学ぶために、今日はチェーン構造を学びましょう.
構造体はカスタムデータ型と見なすことができ、構造体は互いにネストして使用することができるが、条件があり、構造体は構造体ポインタを含むことができるが、構造体に構造体変数を絶対に含まないという重要な特性がある.
   struct test
   {
     char   name[10] ;
     float  socre    ;
     test * next     ;
   };                  //      !
   struct test
   {
   char   name[10]  ;
   float  socre     ;
   test   next      ;
   };               //      !

構造体のこの点の特殊な特性を利用して,一つのリングブッシュの一種の線構造を自分で生成することができ,一つはもう一つを指す.
チェーンテーブルの勉强は思ったほど简単ではありません.多くの人がここまで勉强する时、困难に直面します.多くの人もそのために勉强を放弃しました.ここで私は、绝対に放弃してはいけません.その勉强に対応して、私たちは分解式の勉强をしなければなりません.方法はとても重要です.理解には时间がかかります.自分を追い詰める必要はありません.学習前にも最も基本的な準備をしなければなりません.スタックメモリの基本的な知識を備えなければなりません.また、構造体の基本的な認識も必要です.この2つの重要な条件があれば、分解的な学習を行うと、この節の内容の難点を簡単に把握することができます.
次に、チェーンテーブルを作成する完全なプログラムを提供します.理解していても理解していなくても、読者が先に真剣に見てほしいと思っています.考えてみてください.理解していなくても大丈夫です.私の下には分解式のチュートリアルがありますが、前の基本的な思考は必ずしなければなりません.私が分解しても理解できません.
コードは次のとおりです.重要な部分に注釈を付けました.
   #include
   using namespace std;
   struct test
   {
     char name[10];
     float socre;
     test *next;
   };

   test *head;                    //                

   test *create()
   {
     test *ls;                   //    
     test *le;                   //    
     ls = new test;                // ls            
     cin>>ls->name>>ls->socre;
     head=NULL;                  //         head        ,             null    
     le=ls;                     //                    ,      le->next,           

     while(strcmp(ls->name,"null")!=0)      //       ls->name    null,        
     {
       if(head==NULL)               //            
       {
         head=ls;                 //          ,                           
       }
       else
       {
         le->next=ls;          //                      le->next                    
       }
       le=ls;                //                 ,                    next                    
       ls=new test;             //                 
       cin>>ls->name>>ls->socre;
     }

     le->next=NULL;    //      next    ,              ,                      
     delete ls;        //                     ,       
     return head;    //      
   }

   void showl(test *head)
   {
     cout<next;
     }
   }

   void main()
   {
     showl(create())  ;
     cin.get()        ;
     cin.get()        ;
   }

上のコードは、入力した人名とスコアを格納し、チェーン構造でチェーン構造に組み合わせることを目的としています.
プログラムには、test*create()とvoid showl(test*head)の2つの関数があり、createはチェーンテーブルを作成するために使用され、showlはチェーンテーブルを表示するために使用されます.
create関数の戻りタイプは構造体ポインタであり、プログラム呼び出し時にshowl(create()を使用した.参照しない目的は、ブートポインタがグローバルポインタ変数であるため、showl()関数内に移動操作head=head->nextがあるため、showl()内で変更することはできません.引用であればheadポインタの位置を破壊し、会頭アドレスの位置を探すことができなくなりました.
次はプログラム全体を分解して、初心者の思想でプログラム全体を考えて、浅いから深いまで徐々に解釈します.
まず、このプログラムを書くには、チェーンテーブル構造であるため、その大きさがどれほど大きいかを知ることはできません.この問題は、プログラムが終了する前に常に有効であり、関数スタック空間のライフサイクルの制限を受けないため、スタックメモリを動的に開くことで解決できます.しかし、このチェーン構造のアクセスアドレスを格納するためにポインタ変数が必要であることに注意してください.関数の内部でこのポインタ変数を確立するのは明らかに適切ではありません.関数が終了すると、このポインタ変数も失効するので、プログラムの開始にグローバルポインタ変数を宣言しました.
   test *head;    //                

この2つの問題を解決して、私たちは次に考えます.
入力があれば必ず出力があります.出力関数と入力関数は相対的に独立しているので、プログラムの正確性/デバッグを絶えずテストするために、出力関数とmain関数の呼び出しを書き、関数を作成するにはcreateという名前を約束します.
まず、次のコードを書きます.
   #include
   using namespace std;
   struct test
   {
     char name[10];
     float socre;
     test *next;
   };

   test *head;            //                

   test *create()
   {
     return head;          //      
   }

   void showl(test *head)
   {
     cout<next;
     }
   }

   void main()
   {
     showl(create());
     cin.get();
     cin.get();
   }

プログラムはここまで書かれていて、基本的な形態はすでに出ていて、入力と呼び出しはすでにあります.
次に入力問題を解決します.チェーンテーブルの実現は循環入力によって実現されます.循環である以上、循環を終了する条件を考慮し、デッドサイクルと無効なサイクルの発生を避けなければなりません.
create()関数の内部では、まず次のように書きます.
   test *create()
   {
   test *ls;          //    
   test *le;          //    
   ls = new test;        // ls            
   cin>>ls->name>>ls->socre;
   head=NULL;          //         head        ,             null    
   le=ls;            //                    ,      le->next,           
   le->next=NULL;        //      next    ,              ,                      
   delete ls;          //                     ,       
   return head;        //      
   }

ループを作成する前に、入力しない場合を考慮する必要があります.
プログラムがcreate関数に入ると、まずノードを作成しなければなりません.まずノードポインタを作成し、その後、ノードポインタを動的に開いたtestタイプの動的メモリアドレスの位置に指します.
   test *ls;
   ls = new test;

プログラムは循環入力である以上、構造メンバーtest*nextは次の接点のメモリアドレスを格納するために使用され、循環するたびに新しいメモリ空間を動的に作成するので、前回の循環動的に開いたメモリアドレスを格納するためのポインタが必要になります.
   test *le;

次にループに入る前にチェーンテーブルの最初のノードを作成します.最初のノードは必ずループ外で作成されます.
   cin>>ls->name>>ls->socre;

プログラム実行者の場合は位置するので、最初からプログラムを実行し続けたくない場合を考慮しなければならないので、最初はheadガイドポインタをアドレス、つまり
   head=NULL;

leつまりチェーンテールポインタの設計構想に合致するために、ループの前に動的に開いたばかりのメモリアドレスを保存しなければなりません.次のループの時に前のノードのnextメンバーの指向を設定すると、次のループがあります.
   le=ls;

ループ入力を実現するために、次のコードを追加しました.
本文は:駅長(http://www.qqcf.com)詳細出典参考:http://study.qqcf.com/web/171/19838.htm
転載先:https://www.cnblogs.com/limanjihe/p/10114650.html