広告
↓発売日:2018年09月22日↓
![]() |
新品価格 |
今回はポインタまとめ[その2]として注意するトコロと後半にポインタのポインタ、ダブルポインタの使い方について見ていきたいと思います。
/*九日目 プログラム1*/
#include <stdio.h>
int main(){
int suji = 100;
int *p = &suji;
int* p2 = &suji;
printf("p = %p\n",p);
printf("内容 = %d\n",*p);
printf("p2 = %p\n",p2);
printf("内容 = %d\n",*p2);
return 0;
}
これは最初の方にも説明しましたがポインタはC言語の時代や場面によってさまざまな書き方をされます。
もちろん引数でも
void func(int *suji); void func(int* suji);
これも同じ意味で扱われます。
int *func(void); int* func(void);
戻り値においても同じような書き方ができるようです。
今度は文字配列の先頭アドレスを保存する場合です。
/*九日目 プログラム2*/
#include <stdio.h>
int main(){
char bunsyou[20] = "hello";
char* p = bunsyou;
char* p2 = &bunsyou[0];
printf("pのアドレス = %p\n",p);
printf("pの内容 = %s\n",p);
printf("p2のアドレス = %p\n",p2);
printf("p2の内容 = %s\n",p2);
return 0;
}
配列の要素を省略した場合と、配列の先頭のアドレスだけを入れた場合ですね。
char* p = bunsyou; char* p2 = &bunsyou[0];
結果を見るとこちらも同じような意味になります。
こんな感じで少しあげただけでも同じ意味なのにポインタはいろんな書き方ができるのです。
まあこれもややこしいのですが、どちらが正しいというワケでもなく時代や場面によって異なる書き方をされたりするので、なんとなく覚えておいてください。
ところで先ほどもあげた配列のアドレスについてですが、結果を見るとどちらも同じアドレスが入っております。
前回までは深くは考えずこの配列のアドレスを他の関数に渡したりしていたワケですが、この時渡しているのは何なのか?というのをもう少し詳しくみてみたいと思います。
それぞれのサイズを調べる「sizeof()」演算子というのを使います。
/*九日目 プログラム3*/
#include <stdio.h>
void func(int* );
int main(){
char hairetu1[5] = "abcd";
int hairetu2[5] = {1,2,3,4,5};
int* p = hairetu2;
printf("charのサイズ = %d\n",sizeof(char));
printf("hairetu1 = %d\n",sizeof(hairetu1));
printf("intのサイズ = %d\n",sizeof(int));
printf("hairetu2 = %d\n",sizeof(hairetu2));
printf("\n");
func(p);
return 0;
}
void func(int* p){
printf("関数func内「p」のサイズ = %d\n",sizeof(p));
}
前半に軽く使い方を示したプログラムを書きましたが
sizeof(char)
のように書けばそのサイズを調べる事ができます。
配列なども同じように調べる事が可能です。
結果を見ると「char」のサイズが「1」、「int」のサイズが「4」、2つの配列もそれぞれその要素の大きさ分の大きさになっている事が確認できるかと思います。
ここで問題の関数「func()」に渡した配列のポインタの大きさですが、結果を見ると・・・、
関数func内「p」のサイズ = 4
なんと配列を渡したはずなのにサイズは「int」一つ分の「4」しかありません。
これはどういう事かと言いますと、関数に渡していたのは「配列の大きさの何か」ではなく、単なるその先頭アドレスを渡していたという事なんですね!
つまりはもしこの渡された元の配列などの大きさを知りたい時は、この関数内から調べる方法がないので引数の一つなどとしてそのサイズを渡してあげなければいけないという事です。
広告
配列の要素数を省略するとその配列の先頭アドレスになると説明しました。
ではこのアドレスを使って直接他の要素を見る事はできないのでしょうか?
というのを試したプログラムになります。
/*九日目 プログラム4*/
#include <stdio.h>
int main(){
int ary[10] = {1,2,3,4,5,6,7,8,9,0};
int i;
for(i=0;i<10;i++){
printf("%d ",*(ary + i));
}
printf("\n");
return 0;
}
思った通りポインタのようにその内容などを確認できましたね。
ではもしかして!と思って
ary++;
としてみると・・・、これはエラーになります。
配列名だけの場合はその先頭アドレス固定なのです。
ポインタ変数と通常の変数はやっぱり違うという事ですね!
最後にポインタのポインタ、ダブルポインタについて使い方だけ軽く見てみましょう。
/*九日目 プログラム5*/
#include <stdio.h>
int main(){
int suji = 120;
int* p = &suji;
int** p2 = &p;
printf("変数sujiの内容 = %d\n\n",**p2);
printf("変数sujiのアドレス = %p\n",&suji);
printf("変数sujiのアドレス = %p\n",p);
printf("変数sujiのアドレス = %p\n",*p2);
printf("\n");
printf("ポインタ変数pのアドレス = %p\n",&p);
printf("ポインタ変数pのアドレス = %p\n",p2);
return 0;
}
ポインタにも当たり前ですがアドレスがあります。
そのアドレスを保存するのがダブルポインタになります。
使い方はその言葉通り「*」アスタリスクを2つ付けます。
int* p; int** p2 = &p;
これでポインタ変数pのアドレスが保存されます。
大元の内容、変数sujiの値を確認したい場合は
printf("変数sujiの内容 = %d\n\n",**p2);
のようにします。
ではその変数sujiのアドレスを確認したい場合は
printf("変数sujiのアドレス = %p\n",*p2);
のようにします。
そしてダブルポインタp2が保存しているアドレス、この場合はポインタ変数pのアドレスですね、これを確認したい場合は
printf("ポインタ変数pのアドレス = %p\n",p2);
のようにします。
基本的な使い方だけでもだいぶ頭が痛い話ですね!
でも大丈夫です!
よっぽど高度なプログラムにならないとまず使う事はないので。
その頃はポインタなんて余裕!ってなってると思いますので今のトコロはさわりだけで良いと思われます。
同じ意味なのにたくさん書き方があったり、ほとんど同じ意味なのにエライ細かい部分で違いがあったり、果てはダブルポインタとか・・・。
もう、うんざりしますよね。
まあこのへんを完璧にしようとするとたぶんポインタを学ぶ間に人生が終わってしまうので、ここまで言っておいてなんですが、最初は前回ポインタ5で触れたような内容がおそらくよく使われるようなカタチなのでこのへんから少しずつ身につけていけばいいと思います。
では気分一新、次回はようやくポインタから離れてセットで一つのものを扱う構造体について見ていきたいと思います。
広告
↓発売日: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日↓
![]() |
新品価格 |