広告
↓発売日:2018年09月22日↓
新品価格 |
今回は配列とポインタの関係を見ていきましょう!
まずは配列の先頭部分のメモリアドレスをポインタに入れて、そこから何番目というように他の場所を指定してみます。
/*六日目 プログラム1*/ #include <stdio.h> int main(){ int hairetu[5] = {10,9,8,7,6}; int* p; p = &hairetu[0]; printf("配列の先頭アドレス = %p\n",&hairetu[0]); printf("pに保存されたアドレス = %p\n",p); printf("先頭に保存されてる数字 = %d\n\n",*p); printf("配列番号2のアドレス = %p\n",&hairetu[2]); printf("p + 2 = %p\n",p + 2); printf("配列番号2の内容 = %d\n",hairetu[2]); printf("*(p + 2) = %d\n",*(p + 2)); return 0; }
ポインタを使って、間接的に他の配列番号の内容を確認します。
int hairetu[5] = {10,9,8,7,6};
こちらの配列の先頭部分のアドレスをポインタに保存します。
int* p; p = &hairetu[0];
ポインタを宣言する時は「int*」アスタリスクですね。
そしてアドレスを使う時は頭に「&」アンパサンドでした。
先頭部分のアドレスなので「&hairetu[0]」ですね。
では次にそのポインタのアドレスを計算して、他の配列番号の内容を確認してみます!
先頭アドレスから「+何番目?」というような感じで計算します。
「p + 0」だと先頭アドレス
「p + 1」だと「hairetu[1]」のアドレス
「p + 2」だと「hairetu[2]」のアドレス
こんな感じで計算します。
そして頭に「*」アスタリスクをつければ内容を確認できるので
*(p + 2) = 8;
こんな感じですね。
ちなみに、このかっこを外してこうしてみると
*p + 2 = 12;
ポインタ変数「p」の内容の方にたし算してしまうので注意しましょう。
何度も言いますが、
アドレス→「p」
内容→「*p」
です。
とにかく覚えましょう。
続いて内容の方も間接的にいじってみたプログラムです。
/*六日目 プログラム2*/ #include <stdio.h> int main(){ int hairetu[5] = {10,9,8,7,6}; int* p; p = &hairetu[0]; printf("配列番号2のアドレス = %p\n",&hairetu[2]); printf("p + 2 = %p\n\n",p + 2); printf("配列番号2の内容 = %d\n",hairetu[2]); printf("保存されてる内容に+2 = %d\n",*(p + 2) + 2); return 0; }
こんな感じになりますね。
広告
一つ目のプログラムの実行結果をもう一度見てください。
先頭アドレスp = 39fe30 配列番号2番目のアドレス = 39fe38
ここに疑問を感じた方は16進数をきちんと理解していますね!
16進数といっても数字の進みは一緒なので、
p = 39fe30; p + 2 = 39fe32;
とならなきゃ何か変だよ!となるワケです!
これははるか昔に習った
数字を使う時は「int」
文字を使う時は「char」
という変数を宣言する時のアレの事をもう少し知る必要があります!
こちらのサイトでは
数字専用が「int」
文字専用が「char」
というように紹介したと思います。
実はですね。特に専用ではなく、例えば
「int」だったら「メモリ4つ分」
「char」だったら「メモリ1つ分」
の場所を使いますよ!
というように、使う場所の大きさを指定していたのです!
それで「int」は「4つ分メモリ」、この大きさでポインタ変数も宣言しているので
int* p; p = 39fe30; p + 1 = 39fe34; p + 2 = 39fe38;
のように4つとびに進んでいたのです!
さきほどの「「int」の場合はメモリ4つ分」は使うコンパイラによって、変わる場合があります。メモリ2つ分とるコンパイラもあります!
C言語をみんなが使えるように、規則を決めましょう!と昔やっていた頃にごちゃごちゃっとなって、こんな統一感がない事になったらしいのですが・・・。
こういうもんだと覚えましょう!
「char」の場合はほとんどのコンパイラでメモリ1つ分が用意されます!
なぜに文字の方が小さいのかというような理由は。話せば長いので
こういうもんだと覚えましょう!
ここまでは最初に保存したアドレスを基準としてそこから何番目というように指定しました。
次はアドレスそのものを動かして値を確認したり変更したりしてみます。
/*六日目 プログラム3*/ #include <stdio.h> int main(){ int hairetu[5] = {10,9,8,7,6}; int* p; int i; p = &hairetu[0]; printf("pに保存されたアドレス = %p\n",p); printf("pの内容 = %d\n\n",*p); p++; printf("p++後\n"); printf("pに保存されたアドレス = %p\n",p); printf("pの内容 = %d\n\n",*p); *p = 1000; printf("*p = 1000後\n"); for(i=0;i<5;i++){ printf("%d",hairetu[i]); printf(" "); } printf("\n"); return 0; }
ポインタ変数「p」に保存されたアドレス自体を変更する事によって値を確認したり、値を変更したりしております。
p++;
とインクリメントするとアドレスが一つずれるのが確認できますね!
もちろん
p += 2;
のように計算する事も配列の大きさを超えない範囲で可能です。
これを使えばより柔軟にいろんな場面に対応させる事ができますね!
ポインタの持ってる内容、
たとえば先ほどのプログラムでいうトコロの
*p
こちらをインクリメントしたい時は
(*p)++
このように書きます。
*p++
こうやって書いてしまうとアドレスを先にずらして内容を確認している事になってしまうので注意です。
こういうややこしい場合は計算を分けたり、()かっこをつけて計算の順番を守ったりしましょう。
さきほどのプログラムで例えば、
*(p + 10) = 100;
とすれば先頭アドレスから10番目の場所が「100」になりますよね。
でもプログラム中では、5番目までは配列で宣言したけど、それ以上はしてません。
そこには
「ウインドウズがシステム管理の為に使っている超大事な数字」
があったりします。
なのでこの部分を大丈夫、大丈夫と好きかってにいじったりすると、データが破壊されたり、最悪PCが起動不能になったりもするので
ぜったいにやってはいけません!!!
まあ最近のコンパイラやPCなどはエラー対策をしていたりするそうですが、念のため!やめておきましょう!
今回やったアドレスの計算の事をポインタ演算っていいます。
これをやっていいのは足し算か引き算だけです。
かけ算やわり算は使ってはいけません。
では少し話が長くなってきたので続きは次回にしたいと思います!
広告
↓発売日:2016年02月29日↓
12歳からはじめる ゼロからのC言語 ゲームプログラミング教室 新品価格 |
↓発売日:2018年06月22日↓
新品価格 |
↓発売日:2018年03月09日↓
新品価格 |
↓発売日:2017年06月14日↓
新品価格 |
↓発売日:2018年05月21日↓
新品価格 |
↓発売日:2017年12月07日↓
新品価格 |
↓発売日:2017年02月08日↓
新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ) 新品価格 |
↓発売日:2017年09月26日↓
新品価格 |