Tora pointer32. やること
● ポインタ
● ポインタと配列
● 文字列
3. ポインタとは
● メモリのアドレスを
メモリのアドレス アドレス メモリの内容
0x00000000
格納する変数 0x00000001
0x00000002
0x00000003
● バグの温床 0x00000004
0x00000005
0x00000006
● でもこれがないと 0x00000007
C言語ははじまらない 0x00000008
0x00000009
0x0000000A
0x0000000B
0x0000000C
0x0000000D
0x0000000E
4. ポインタ・・・の前に
アドレス メモリの内容
0x00000000
0x00000001 12
int hoge = 12; 0x00000002 (hoge)
char piyo = 'a'; 0x00000003
double fuga = 0.123456; 0x00000004
0x00000005
0x00000006 'a'(piyo)
0x00000007 0.123456
32ビット環境では 0x00000008 (fuga)
int型は4バイト 0x00000009
char型は1バイト 0x0000000A
0x0000000B
double型は8バイト 0x0000000C
0x0000000D
0x0000000E
5. ポインタ関連の文法
アドレス メモリの内容
0x00000000
0x00000001 12
0x00000002 (hoge)
int hoge = 12; 0x00000003
0x00000004
printf(“%p”,&hoge); 0x00000005
0x00000006
//結果:0x00000001 0x00000007
0x00000008
0x00000009
変数のアドレスを得る 0x0000000A
0x0000000B
&変数名 0x0000000C
0x0000000D
0x0000000E
6. ポインタ関連の文法
アドレス メモリの内容
0x00000000
int hoge = 12; 0x00000001 12
int *phoge; 0x00000002 (hoge)
0x00000003
0x00000004
phoge = &hoge; 0x00000005
0x00000006 0x00000001
0x00000007
ポインタの定義 0x00000008
0x00000009
型の名前 *変数の名前; 0x0000000A
0x0000000B
/*32ビット環境では 0x0000000C
ポインタは4バイト*/ 0x0000000D
0x0000000E
7. ポインタ関連の文法
アドレス メモリの内容
0x00000000
int hoge = 12; 0x00000001 12
0x00000002 (hoge)
int *phoge; 0x00000003
0x00000004
phoge = &hoge; 0x00000005
0x00000006 0x00000001
0x00000007
printf(“%d” , *phoge); 0x00000008
0x00000009
ポインタを通して間接的に 0x0000000A
0x0000000B
変数を見る 0x0000000C
*変数名 0x0000000D
0x0000000E
8. ダブルポインタの動作
アドレス メモリの内容
int hoge = 22;
0x00000000 22
int *phoge;
0x00000001 (hoge)
int **pphoge;
0x00000002
phoge = &hoge; 0x00000003
pphoge = &phoge; 0x00000004 0x00000000
0x00000005 (phoge)
printf("%pn" , phoge ); 0x00000006
printf("%pn" , *pphoge ); 0x00000007
//結果:0x00000000 0x00000008 0x00000004
0x00000009 (pphoge)
printf("%pn" , &phoge ); 0x0000000A
printf("%pn" , pphoge ); 0x0000000B
//結果:0x00000004 0x0000000C
0x0000000D
printf(“%dn”,**pphoge); 0x0000000E
//結果:22
9. ポインタの例:スワップ
swap1(int a , int b) int hoge = 5;
{ int piyo = 10;
int tmp = b;
b = a; swap1(hoge,piyo);
a = tmp; //結果?
}
swap2(&hoge,&piyo);
swap2(int *a , int *b) //結果?
{
int tmp = *b;
*b = a;
*a = tmp;
}
10. スワップ
swap1(int a , int b) アドレス メモリの内容
{ 0x00000000 5
int tmp = b; 0x00000001 (hoge)
0x00000002
b = a;
0x00000003
a = tmp; 0x00000004 10
} 0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008
int piyo = 10;//←今ココ 0x00000009
0x0000000A
0x0000000B
swap1(hoge,piyo); 0x0000000C
printf( 0x0000000D
“%d,%d”,hoge,piyo); 0x0000000E
0x0000000F
11. スワップ
swap1(int a , int b)//←今ココ アドレス メモリの内容
{ 0x00000000 5
int tmp = b; 0x00000001 (hoge)
b = a; 0x00000002
a = tmp; 0x00000003
} 0x00000004 10
0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008 5
int piyo = 10; 0x00000009 (a)
0x0000000A
swap1(hoge,piyo);//←ココの 0x0000000B
printf(“%d,%d”,hoge,piyo);
0x0000000C 10
0x0000000D (b)
0x0000000E
0x0000000F
12. スワップ
swap1(int a , int b) アドレス メモリの内容
{ 0x00000000 5
int tmp = b; 0x00000001 (hoge)
b = a; 0x00000002
a = tmp;//←今ココ 0x00000003
} 0x00000004 10
0x00000005 (piyo)
... 0x00000006
0x00000007
0x00000008 10
int hoge = 5;
0x00000009 (a)
int piyo = 10;
0x0000000A
swap1(hoge,piyo);//←ココの 0x0000000B
printf(“%d,%d”,hoge,piyo); 0x0000000C 5
0x0000000D (b)
0x0000000E
0x0000000F
13. スワップ
swap1(int a , int b) アドレス メモリの内容
{ 0x00000000 5
int tmp = b; 0x00000001 (hoge)
b = a; 0x00000002
0x00000003
a = tmp;
0x00000004 10
}
0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008
int piyo = 10; 0x00000009
0x0000000A
swap1(hoge,piyo); 0x0000000B
printf( 0x0000000C
“%d,%d”,hoge,piyo); 0x0000000D
//↑今ココ 0x0000000E
0x0000000F
14. スワップ
swap2(int *a , int *b) アドレス メモリの内容
{ 0x00000000 5
int tmp = *b; 0x00000001 (hoge)
0x00000002
*b = *a;
0x00000003
*a = tmp; 0x00000004 10
} 0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008
int piyo = 10;//←今ココ 0x00000009
0x0000000A
0x0000000B
swap1(&hoge,&piyo); 0x0000000C
printf( 0x0000000D
“%d,%d”,hoge,piyo); 0x0000000E
0x0000000F
15. スワップ
swap2(int *a , int *b)//←今ココ アドレス メモリの内容
{ 0x00000000 5
int tmp = *b; 0x00000001 (hoge)
*b = *a; 0x00000002
0x00000003
*a = tmp;
0x00000004 10
}
0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008 0x00000000
int piyo = 10; 0x00000009 (a)
0x0000000A
swap1(&hoge,&piyo);//←ココ 0x0000000B
の 0x0000000C 0x00000004
printf(“%d,%d”,hoge,piyo); 0x0000000D (b)
0x0000000E
0x0000000F
16. スワップ
swap2(int *a , int *b) アドレス メモリの内容
{ 0x00000000 10
0x00000001 (hoge)
int tmp = *b;
0x00000002
*b = *a;
0x00000003
*a = tmp;//←今ココ 0x00000004 5
} 0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008 0x00000000
0x00000009 (a)
int piyo = 10;
0x0000000A
0x0000000B
swap1(&hoge,&piyo);//←ココ 0x0000000C 0x00000004
の 0x0000000D (b)
printf(“%d,%d”,hoge,piyo); 0x0000000E
0x0000000F
17. スワップ
swap2(int *a , int *b) アドレス メモリの内容
{ 0x00000000 10
int tmp = *b; 0x00000001 (hoge)
0x00000002
*b = *a;
0x00000003
*a = tmp; 0x00000004 5
} 0x00000005 (piyo)
... 0x00000006
0x00000007
int hoge = 5; 0x00000008
int piyo = 10; 0x00000009
0x0000000A
0x0000000B
swap1(&hoge,&piyo); 0x0000000C
printf(“%d,%d”,hoge,piyo); 0x0000000D
//↑今ココ 0x0000000E
0x0000000F
18. ポインタを使うタイミング
● 動的メモリの管理
● 複数の構造体などから同じデータを参照したい時
● 関数の引数に構造体を利用する時
● 関数の戻り値が2つ以上欲しい時
etc
22. 関数の引数に構造体を使うとき
typedef struct Human
{
int age;
int height;
int weight;
} Human;
//構造体をまるごとコピーして重い。
void print_human(Human h)
{
printf(“%dn”,sizeof(h) ); //結果:16(環境依存
}
//アドレスのみコピー
void print_human_size_p( Human *ph)
{
printf(“%dn”,sizeof(ph) ); //結果:4(環境依存
}
24. やること
● ポインタ
● ポインタと配列
● 文字列
25. ポインタと配列
● ポインタと配列は深い関係ある
● 配列で困ったときはポインタを思い出すと
納得行くことがあったり無かったり無かったり
● そして配列死ねよと思う(?)
26. ポインタと配列の衝撃の事実
● 配列へのアクセスにはポインタも利用できる
int i;
int ary[3] = {7,5,3};
int *p = ary;
for(i = 0 ; i < 3 ; ++i){
printf(“%dn” , ary[i] ); //出力結果は
printf(“%dn” , *(p+i) ); //一緒
}
27. 配列の先頭
アドレス メモリの内容
int ary[3] = {7,5,3}; 0x00000000 7
int *p = ary; 0x00000001
0x00000002
0x00000003
配列の先頭だけ記述 0x00000004 5
0x00000005
↓ 0x00000006
配列の先頭ポインタ 0x00000007
0x00000008 3
0x00000009
0x0000000A
0x0000000B
0x0000000C 0x00000000
0x0000000D
0x0000000E
0x0000000F
28. ポインタに整数を足すと
アドレス メモリの内容
int ary[3] = {7,5,3}; 0x00000000 7
int *p = ary;
0x00000001
0x00000002
printf(“%p”,ary); 0x00000003
printf(“%p”,&ary[0]);
0x00000004 5
printf(“%p”,p);
//一緒 0x00000005
0x00000006
printf(“%p”,&ary[2]); 0x00000007
printf(“%p”,p+2); 0x00000008 3
//一緒 0x00000009
0x0000000A
++p; 0x0000000B
printf(“%p”,&ary[1]);
printf(“%p”,p); 0x0000000C 0x00000000
//一緒 0x0000000D
0x0000000E
0x0000000F
29. 配列を関数の引数にする
//配列の先頭のポインタが渡される!
void func( int a[])
{
printf("%pn", a );//出力:0x000000ff
a[2] = 0;
}
///
int ary[] = {1,2,3};
printf("%p", ary );//出力:0x000000ff
func(ary);
//ポインタを渡したので、関数の書き換えが反映される
printf("%dn",ary[2]);//出力:0
33. 2次元配列についての罠
アドレス メモリの内容
● 要素数がある程度分からないと 0x00000000
要素の参照に困る 0x00000001 'a' ( [0][0] )
0x00000002 'b' ( [0][1] )
char hoge[][3] = {{'a','b','c'}, 0x00000003 'c' ( [0][2] )
{'d','e','f'}}; 0x00000004 'd' ( [1][0] )
0x00000005 'e' ( [1][2] )
//配列の最初を参照すればOK 0x00000006 'f' ( [1][3] )
hoge[0][0] = 'e'; 0x00000007
0x00000008
//配列の最初から3バイト先を 0x00000009
//参照しなくてはいけない 0x0000000A
hoge[1][0] = 'f'; 0x0000000B
0x0000000C
先ほどのポインタは、何バイト先を 0x0000000D
読み込めばいいか分からなかった。 0x0000000E
よってエラー
34. やること
● ポインタ
● ポインタと配列
● 文字列
35. 文字列
● 文字列はchar型の配列として扱うことができる
● 文字列の最後にはNULL文字がある。
char str1[5] = "abcd";
char str2[5] = {'a','b','c','d','0'};
printf("%sn",str1);
printf("%sn",str2);
a b c d 0
36. 文字列
● 文字列はchar型の配列として扱うことができる
● 文字列の最後にはNULL文字がある
char str1[5] = "abcd";
char str2[5] = {'a','b','c','d','0'};
int i;
for(i=0;i<5;++i){
printf("%c",str1[i]); //一緒
printf("%c",str2[i]); //一緒
}
//char型、文字列として出力する時、
//ヌル文字は出力されない
37. 文字列
● 文字列の最後にはNULL文字があるので・・・
char str1[5] = "abcd";
char str1[2] = '0';
printf("%sn",str1);
//出力:ab
a b 0 d 0
40. 今日の確認+α
char *str3 = "abcd";
メモリ上の何処かに{a,b,c,d,0}の配列が作られる
その配列の先頭のアドレスがstr3に格納
{a,b,c,d,0}の書き換えなどの操作は動作未定義
42. 今日の確認+α+β
void func1( char str1[5] ){ ... };
void func2( char str2[] ){...};
void func3( char *str3 ){...};
アドレスを受け取るのはどれも同じ。
要素数の指定(一番上)は
二次元以上の配列に必要となる。
例: void func4( int ary2[][5] ){...};
void func5( int ary3[][3][5]){...};
一番左の要素数は省略可。
43. 最後に
● ポインタと配列の深い関係についてやったけど、
「ポインタと配列は一緒」とか訳のわからない
事をいう大人にはならないように
● printf("%cn" , "abcde"[3] );
きもちわるいぃぃぃぃぃいいいい