早くも年末ですね~ブログの更新おせーよ!!って自分でも思うわけですが、限りある時間を見つけてなんとか書いていかねば!それはさておき、最近はアナログ回路から少し離れて、会社ではCPU周りのファームプログラムを学んでおります。最近ではアナログ回路のみで完結する装置などはほぼ少なくなっており、制御するために様々なICを使います。デジタル回路を用いてみたり、CPUでADコンバータやDAコンバータを制御したりするわけです。その際に、PICやAVR、ARMなどのCPU内臓のICを用いて制御することがあるわけですが、装置の通信やICを直接制御するには、ハードウェアに近い言語を使わねばなりません。その最たるものがアセンブラですが、「今の時代アセンブラなんて書いてられん!無駄にコード行数が長くなるし、読みにくい!」という問題があるわけです。そこで、C言語が挙げられるわけです。こいつは最近流行のオブジェクト指向言語と少し趣が違う。いうのは、メモリを直接いじれたりするからであります。C言語の文法の問題というより、CPUやメモリの原理を理解している等のハードウェアに関する知識が必要なのです。C言語でデバイスのプログラムなどやったことなかった僕は、ほぼすべての関数でつまづき、倒れ、意味が分かりませんでした。C言語の文法の問題だだと思っていたポインタに関しても、「は?なにやってんの・・・・俺の頭では・・・即座に理解ならん!!」となりました。然る後、メモリを読め!という先輩の指示に従い、デバッグでメモリを見つつプログラミングをしていたら、なるほどどうして理解の速度が上がりました。C言語の文法と思っていたポインタさえ、メモリというハードウェアの領域だったのです。いうことで、ここでは、難解であるC言語プログラムのポインタとやらをメモリウィンドウによるメモリの追跡をすることで、実体験的に把握しようと努めます。専門用語は本とかを見ると、載りまくっているので必要と思われる部分以外は使用しません。Studioで、あまねく学習者が無料で使う事が出来る高機能エディターです。別にこのソフトでなくてもいいのですが、メモリも参照することが出来ますし、何より情報があふれているので、困った時にも調べやすいことと思われます。以下に今回書いたコードを載せております。125となって値が出てくるというものです。細かい点は知らなくても、結果が予測できるようなプログラムとなっております。*nPtr;}デバッグ雰囲気こうなるんだろうなぁ、と思って写してコンパイルしてみても、さして理解したような気になれない不思議。ここは、1行ずつデバッグして変数とそのメモリのアドレスを調べてみましょう。main()の最初の行(6行目)において、ステップイン(F11ボタンを押す)により、1行ずつデバッグすることが出来ます。メモリウィンドウの使い方は以下のサイトに見やすく書かれていますので、参考にしてみてください。Studioのメモリウィンドウがこんなに使いやすいなんて知らなかった6行目6行目でデバッグすると、numberに初期値を入れていないため、10034707という全くランダムな数字が入っていることがわかります。初期化の重要性がわかりますね。次に、numberというint型の変数に5を代入します。numberのメモリアドレスを見てみると、住所はどうやら0x00000005ということです。本当かよ?この5って代入した値の5なんじゃねーの?と思って調べてみますと、変数を下に突っ込むとその中の値が出力される模様。後にこれを検証します。変数に&をつけることで、その変数のアドレスがわかります。先のnumberのアドレスを確かめるべく、&numberを出力させてみます。すると、結果は、0095FA5Cということが判明。ここで発見したのが、numberのみを見ると、アドレスの部分に05と出るのですが、&numberをメモリウィンドウに突っ込むと、以下のようになります。先頭の05は16進数の0x05です。16進数の0x05は10進数で5となるので、値はあっております。アドレス:0x0095FA5C値:05この結果から、変数をメモリウィンドウに突っ込むとアドレスの部分に値が出て、下のメモリ番地の部分は????になるということが判明しました。デバッグ16行目l12行目に行くと、cubeByReference関数のあるl15に飛びます。cubeByReference関数の引数は、&numberですのでnumber変数の番地をそのまま値として運ぶということになります。ここらへんは、デバッグして初めて把握しましたね!!メモリウィンドウみないままやってると、全くわからなかった。nPtrだけをメモリウィンドウに突っ込むと、以下のようになります。&numberで見たのと全く同じですね。こいつがポインタというやつですね。*は初心者殺しで、ざっとCの本を読んだりしても全然わからないわけです。いうことで、細かいことはさておき、どう動くのかを追跡してみましょう。*nPtrをメモリウィンドウに突っ込むと、05と出てきます。これは先に述べた通り、メモリ番地の表示が?になっておりますので、アドレスではなく値を示しています。&をつけると、その変数のアドレスを取得することが出来ました。0x0095FA5Cだったわけです。*をつけると、そのアドレス(0x0095FA5C)に入っている値(5)を取り出すことが出来るということです。う~む、難しい!けど、メモリウィンドウを負い続ければ、把握は出来るわけです。18行目*nPtrを三乗したわけですが、赤くなっているところは値が変化した部分を示しています。05から7dに値が変わったわけです。16進数の7dは10進数で125なので、きちりと計算されていることがわかります。なりますが、*をつけることで、アドレスの中身を取り出すことが出来るようです。これがどうやらポインタの逆参照というやつらしい。ここで*nPtrが三乗されたわけだが、この計算によりnumberの中身の値が変わる、ということも観測されました。これも、地味に難しいポイントだと思われます。先の16進数の掛け算を電卓などを用いてやってみましょう。(Windows10の電卓を使えば、16進数の計算も一瞬で出来ます)電卓のプログラマー欄を選択した後、16進数なのでHEXを選択します。0x7Dとなっており、正しいことが分かります。まとめの図ポインタの短いプログラムを実行して、メモリのアドレスを確認しつつ動きを確認しました。その結果を再解釈し、絵にすると以下のようになるのではなかろうか?まず、numberのアドレスが0x0095FA5Cであることは調べてわかっております。このアドレスは、変数の頭に&を付けることで、取得できました。こいつは理解しやすい。問題は、*をつけたやつです。nPtrの中にはnumberのアドレスが格納されていました。このアドレスに保存されている値を取り出すのが、*nPtrの働きであったことは、先の実験から明らかになったことです。*nPtr、すなわち逆参照という概念は、2つの働きを持っているというようにも見えます。当該アドレスの値を取得この複雑な動きのせいで、我々初学者を地獄に叩き落していると思われます。ここまで言語化して、ようやく自分でもおぼろげながら理解してきました。次も、このポインタ関係をより深く追求していこうと思っております。tanushiたぬしの空想半径プログラミングC#を0から初めて1ヶ月。実験屋(人生含む)たぬし実験屋たぬしです。その後、これまでやったことない分野(アナログ回路)の零細企業に入り、日々実験を継続中。回路関係の実験・解析や物理など理系のことやバイク・音楽・文学などついても書いております。