資料 4 プログラミング II ポ イ ン タ 1:基 礎 概 念 これに対して,配達する人に「配達先の情報が書いてあるホワイトボード」を見せて,その住所に行ってもらえ ば誰でも住所 X でも Y でもいけることになる.配達員 A はまずホワイトボードを見てその行き先が X なのでカ レーピザを用意すればよい. つまり,配達員 A は届けるアドレスを知って,その注文者をたどればその中身も 知る事ができる. 今日の内容と達成目標 ・変数には住所(アドレス)と値(value)があることを理解する ・アドレス情報を扱える専用の変数がポインタであることを知る プログラムにおいても,この配達先ホワイトボードに相当する,「アドレス情報を扱える変数」があれば非常に 便利になる.例えばある 10 人が,10 人住めるマンションに 1 号室から入居すれば一つのマンションで全員住む ことができるが,好き勝手に選ばせれば最悪の場合は 10 棟のマンションが必要になるので(一つの棟には 9 つの ◎変数の住所? 空き部屋があってとても非効率.プログラムで言えば無駄にメモリを使っている状態),アドレスを指定できれば scanf 命令の時に scanf(“%f”, &a)として&をつけた.&があると無いのとでは何が違うのかというと 便利である.同じように,後々プログラムレベルが上がってくると「この情報はこの場所に格納したい」とアド &は変数 a のアドレス(住所)を示し,&が無いと中身の値を意味する.一般的に レスを直接指定する場面が出てくる. int a, b , c; この,アドレス情報を扱える変数をポインタ変数と呼ぶ.これは int が整数を扱い,float が実数を扱うの と宣言するとコンパイルの時点で変数のアドレスが自動で割り当てられる.これはコンピュータが勝手に割 と同じで扱う情報の範囲がアドレスということである.ただし,その住所を見れば誰が住んでいるのかも知るこ り当てるのでどこになるかは分からない.普通の変数は一軒家,文字列を含む配列はマンションだと考えると理 とができるのでポインタ変数はアドレスとその中身の 2 情報を知ることができる.これもポインタが重要である 解しやすい.さて, 理由の一つである. ポインタ変数とはアドレスを直接あつかうことのできる変数である a=10; として a に 10 を代入したいが,そもそも a という変数がどこにいるのかを知る必要がある.これは,郵便配達 の時に「高専太郎さんに 10 を配達してくれ」といわれてもその住所が分からないとできないのと同じである. int *ptr; *:アスタリスク 逆に「戸倉 14-1 の 2 番地に 10 を配達してくれ」となるとそこにいるのが高専太郎さんであろうが高専花子さん であろうが関係なく配達することができる.つまり,アドレス指定を行えば変数名が a でも b でも関係がないこ と*をつけて書くと,変数 ptr はポインタ変数であり,アドレスを扱うことができる.前述のようにポインタ変数 とになる.では,なぜ変数名をつけているのかといえば,単純に我々がわかりやすいからである. はアドレス情報とそのアドレスの中身の 2 情報を知ることができるので以下のように使うことができる. 次の図を例にして考えてみる. ptr 次に配達する家はどこ?? 受付担当 B アドレス 例えば「ロッカー番号 3 番」など *ptr 「3 番のロッカー」に入っていた「消しゴム」のこと カレーピザを X まで! 重要なことは*ptr 自身の中身が消しゴムではないということである.ptr が扱うのはあくまでもアドレスだけで, *つけると「その住所を訪問して誰が住んでるか見てこい!」という意味だと理解して欲しい.つまり ptr が「ロ A C ッカー番号 7 番」というアドレスに書き換えられれば*ptr とした場合,今度は 7 番の中身なので「ノート」を参 次に配達する家の住所 ミックスピザを 配達ボードを参照 ○○町□丁目△番▽号 Y まで! 照することになる.ptr は参照先を示す司令塔のポジションである.ポインタを int で宣言した意味は,指定で きるロッカーの中は int 型の変数だけということであり,int の *ptr には実数は使えないことになる.実数 型を格納しているロッカーのアドレスは扱えない ptr に 3 番と言われたのでそこを見に行くと消しゴムがある ピザ屋で色々な住所から色々な注文が届く.これは色々な変数に値を代入すると考えて欲しい.このときに配達 員 A は住所 X にカレーピザを届ける人, 配達員 B は Y にミックスピザを届ける人と決めるのがこれまでの a=X;, b=Y というやり方である(逆に言うと,配達員 A は住所 Y にはいけない). ロッカー 3番 ptr:アドレス情報 0番 1番 2番 3番 4番 5番 6番 ロッカー:番号は住所.中身は int 型 7番 ポインタ変数は*をつけると自分の持っているアドレスの中身=値を ヘッダーファイルを調べてみよう!! ~ stdlib.h ~ ◎ある程度プログラムを作っていると,「○○をしてくれる機能を持った関数があればいいのに」と思う事がある。 参照することができる なかでも私たちがちょっと欲しいなぁと思う関数は「stdlib.h」の中にある事が多い。これは標準ライブラリ ※これはポインタ変数に初期値がなければ住所不定者ということである,当然その中身を見ることもできないこ とを意味する ○しかし,ポインタ変数に直接番地を入れるような使い方ではなく,何かの変数の住所を格納する使い方をする. (Standard Library)関数のことである。ライブラリは文字通り「図書館」で,その中にいろいろな機能を持った関数 (=本)が格納されている。 ◎ 今週からはこのページでは知っているとちょっとだけ便利な関数を紹介していきます。 (A 君の住んでいる住所をメモする感覚) clrscr(); 関数; ○int 型変数 a=10 であれば中身が 10 であることが重要であるが 10 が格納されているアドレスも持っている. この,普通の変数のアドレスを表示するのが&である.しかし,ポインタ型変数以外は決められた住所を 表示することはできるが,アドレスを扱えないので例えば新しいアドレスを与えること(引っ越し)はできない. クリアスクリーン 必要なヘッダーファイル;conio.h 機能;タイトルで stdlib が便利だと言っているのに conio.h からの紹介で申し訳ないが,これは実行して いる黒い窓(これを DOS 窓と呼びます)を一度きれいに する関数です。プログラムを実行すると右図のように 実行ファイルのフォルダ情報が表示されますが,これが美しくない!不必要!と言うときに使います。 ポインタの使用例 関数には引数が必要ないので getch();のようにこれだけを記述します。 int a=10,b=20,c=30; 関数; int *ptr; 必要なヘッダーファイル;stdlib.h (time.h) ランダム関連 機能; 簡単な確率シミュレーションなどではランダムを必要とします。ここではランダム変数の作り printf(“%d \n”,&a); //変数 a のアドレスを 10 進数で表示 アドレスなので&がついている printf(“%x \n”,&a); //変数 a のアドレスを 16 進数で表示 方を紹介します。ただし,疑似乱数なので厳密なシミュレーションのためのためには不十分です。 C++で便利になりました。基本的には 3)だけチェックしておけばいいでしょう。 int n; float x; 1) rand() ptr=&a; ここが重要です. ポインタ変数 ptr に変数 a のアドレスが代入されました. int 型で 0~32767 までの整数乱数を発生させる。 これにより ptr に意味が生まれました. ただし,ランダムと言ってもある乱数表の最初から 順番に持ってくるだけなので 5 回ランダムを発生 させるプログラムがあっても実行するたび同じ 5 個 printf(“%d \n”,*ptr); //この書式は ptr の持っている住所(つまり,a の住所)の値を //表示させます *ptr=50; ここも重要です.アドレスの参照先の値を変えることも可能です.ptr の アドレス,つまり変数 a の値に 50 を代入することになります.実行した ことは a=50 と同じですが,アドレスを利用したことに意味があります printf(“%p \n”,ptr); //ptr の持っている住所を 16 進数で表示 ポインタ変数はこちらを使う printf(“%d \n”,ptr); //ptr の持っている住所を 10 進数で表示 printf(“%d \n”,*ptr); //ptr の持っている住所の中身が 50 になっていることを確認する n=rand(); //ここで 0~32767 までの数が n にはいる x=10.0*rand()/32767; これにより 0~1 までの実数に変換 の乱数になる。 scanf(“%d”,&seed); srand(seed);//これで初期値(種)をずらす 2) srand(int 型変数) for(i=0;i<5;i++){ n=rand(); この種,seed が同じならやはり毎回同じ結果になる。 ・ そこで,乱数表のスタート位置をずらす事にする。 3) randomize() と random(int 型) (※これらは C++命令だったと思います) 2)の種に時間を使えば,時間は常に動いているので 同じ種にはなりません。と言う事でそれを自動的に 行うのが randomize()です。最初に一度宣言すれば OK です。ただし,そのためには時間を扱う time.h もイン int i,r,n; randomize(); //乱数の種まき for(i=0;i<1000;i++){ クルードしてください。これで,rand() は実行する 現時点で,なぜわざわざポインタ変数なるアドレス専用の変数を用意しているのかは疑問でしょう.このあと ごとに,毎回違う整数乱数を発生させます。 ドレス指定がなければ C 言語を使う意味がないとさえ言われるほど重要な概念です.残念なことは,初めて触れ る場合には少しややこしく理解しにくいと言うことです.アドレスを扱う割には int を指定したりしています. この辺は次回,メモリマップという概念を学習すると理解できるようになります. //0~32767 まで n=random(100);//0~99 まで printf("%d\t%d\n",r,n); 様々な使用法に触れて便利さを勉強していきます.簡単な科学計算ではポインタを理解していなくても何ら困る ことがありません.しかし,将来的に仕事で使うレベルでは確実に困ります.また,そもそもポインタによるア r=rand(); そして random(100) と言う便利な関数があります。 } これは 0~99 までの整数乱数を発生させます。つまり, サイコロシミュレーションなら random(6)+1 とすれば 1~6 までの数を発生させます。 「いくら からいくらまでの乱数」と言う指定が簡単にできるようになりました。
© Copyright 2024 ExpyDoc