Your SlideShare is downloading. ×
Tora pointer3
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Tora pointer3

705
views

Published on


0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
705
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. ポインタと配列と文字列 HN:MARISHI 牛乳おいしいよ>
  • 2. やること● ポインタ● ポインタと配列● 文字列
  • 3. ポインタとは● メモリのアドレスを メモリのアドレス アドレス メモリの内容 0x00000000 格納する変数 0x00000001 0x00000002 0x00000003● バグの温床 0x00000004 0x00000005 0x00000006● でもこれがないと 0x00000007 C言語ははじまらない 0x00000008 0x00000009 0x0000000A 0x0000000B 0x0000000C 0x0000000D 0x0000000E
  • 4. ポインタ・・・の前に アドレス メモリの内容 0x00000000 0x00000001 12int hoge = 12; 0x00000002 (hoge)char piyo = a; 0x00000003double fuga = 0.123456; 0x00000004 0x00000005 0x00000006 a(piyo) 0x00000007 0.12345632ビット環境では 0x00000008 (fuga)int型は4バイト 0x00000009char型は1バイト 0x0000000A 0x0000000Bdouble型は8バイト 0x0000000C 0x0000000D 0x0000000E
  • 5. ポインタ関連の文法 アドレス メモリの内容 0x00000000 0x00000001 12 0x00000002 (hoge)int hoge = 12; 0x00000003 0x00000004printf(“%p”,&hoge); 0x00000005 0x00000006//結果:0x00000001 0x00000007 0x00000008 0x00000009変数のアドレスを得る 0x0000000A 0x0000000B&変数名 0x0000000C 0x0000000D 0x0000000E
  • 6. ポインタ関連の文法 アドレス メモリの内容 0x00000000int hoge = 12; 0x00000001 12int *phoge; 0x00000002 (hoge) 0x00000003 0x00000004phoge = &hoge; 0x00000005 0x00000006 0x00000001 0x00000007ポインタの定義 0x00000008 0x00000009型の名前 *変数の名前; 0x0000000A 0x0000000B/*32ビット環境では 0x0000000Cポインタは4バイト*/ 0x0000000D 0x0000000E
  • 7. ポインタ関連の文法 アドレス メモリの内容 0x00000000int hoge = 12; 0x00000001 12 0x00000002 (hoge)int *phoge; 0x00000003 0x00000004phoge = &hoge; 0x00000005 0x00000006 0x00000001 0x00000007printf(“%d” , *phoge); 0x00000008 0x00000009ポインタを通して間接的に 0x0000000A 0x0000000B変数を見る 0x0000000C*変数名 0x0000000D 0x0000000E
  • 8. ダブルポインタの動作 アドレス メモリの内容int hoge = 22; 0x00000000 22int *phoge; 0x00000001 (hoge)int **pphoge; 0x00000002phoge = &hoge; 0x00000003pphoge = &phoge; 0x00000004 0x00000000 0x00000005 (phoge)printf("%pn" , phoge ); 0x00000006printf("%pn" , *pphoge ); 0x00000007//結果:0x00000000 0x00000008 0x00000004 0x00000009 (pphoge)printf("%pn" , &phoge ); 0x0000000Aprintf("%pn" , pphoge ); 0x0000000B//結果:0x00000004 0x0000000C 0x0000000Dprintf(“%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 0x00000007int hoge = 5; 0x00000008int piyo = 10;//←今ココ 0x00000009 0x0000000A 0x0000000Bswap1(hoge,piyo); 0x0000000Cprintf( 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 0x00000007int hoge = 5; 0x00000008 5int piyo = 10; 0x00000009 (a) 0x0000000Aswap1(hoge,piyo);//←ココの 0x0000000Bprintf(“%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 10int hoge = 5; 0x00000009 (a)int piyo = 10; 0x0000000Aswap1(hoge,piyo);//←ココの 0x0000000Bprintf(“%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 0x00000007int hoge = 5; 0x00000008int piyo = 10; 0x00000009 0x0000000Aswap1(hoge,piyo); 0x0000000Bprintf( 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 0x00000007int hoge = 5; 0x00000008int piyo = 10;//←今ココ 0x00000009 0x0000000A 0x0000000Bswap1(&hoge,&piyo); 0x0000000Cprintf( 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 0x00000007int hoge = 5; 0x00000008 0x00000000int piyo = 10; 0x00000009 (a) 0x0000000Aswap1(&hoge,&piyo);//←ココ 0x0000000Bの 0x0000000C 0x00000004printf(“%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 0x00000007int hoge = 5; 0x00000008 0x00000000 0x00000009 (a)int piyo = 10; 0x0000000A 0x0000000Bswap1(&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 0x00000007int hoge = 5; 0x00000008int piyo = 10; 0x00000009 0x0000000A 0x0000000Bswap1(&hoge,&piyo); 0x0000000Cprintf(“%d,%d”,hoge,piyo); 0x0000000D//↑今ココ 0x0000000E 0x0000000F
  • 18. ポインタを使うタイミング● 動的メモリの管理● 複数の構造体などから同じデータを参照したい時● 関数の引数に構造体を利用する時● 関数の戻り値が2つ以上欲しい時 etc
  • 19. 動的メモリの確保int num;scanf(“%dn”,&num);int *ary = (int*)malloc( sizeof(int) * n );
  • 20. 複数の「何か」から同じデータを参照アドレスさえあれば、同じデータを簡単に共有できる。 int apple_num;//0x003344550x00334455 0x00334455 MARISHI kano
  • 21. 複数の「何か」から同じデータを参照 乱用すると、意図しない値の操作が行われた時に、 どのプログラムが間違ってるか分かり辛い int apple_num;//0x00334455誰だ5個も食いやがった奴は! 0x003344550x00334455 0x00334455 *apple_num -= 5 MARISHI kano xALTx ククク・・・
  • 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(環境依存}
  • 23. 関数の戻り値が複数欲しい時void yanagisawa_info(int *age , int *weight){ *age = 22; * weight = …//ヒミツ}
  • 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 7int *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 7int *p = ary; 0x00000001 0x00000002printf(“%p”,ary); 0x00000003printf(“%p”,&ary[0]); 0x00000004 5printf(“%p”,p);//一緒 0x00000005 0x00000006printf(“%p”,&ary[2]); 0x00000007printf(“%p”,p+2); 0x00000008 3//一緒 0x00000009 0x0000000A++p; 0x0000000Bprintf(“%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 );//出力:0x000000fffunc(ary);//ポインタを渡したので、関数の書き換えが反映されるprintf("%dn",ary[2]);//出力:0
  • 30. 配列を関数の引数にする(応用)//配列の先頭のポインタを渡すので、これでもいいvoid func2(int *a){ *(a+2) = 0; //a[2] = 0;//1次元の場合、これでもよい。}///int ary[] = {1,2,3};func(ary);printf("%dn",ary[2]);//0
  • 31. 2次元配列について//一番左の要素数は省略可void func(int ary[][3]){ ary[1][1] = 2;}int main(){ int ary[][3] = { {0,1,2}, {3,4,5} }; func(ary);}
  • 32. 2次元配列についての罠void func(int ary[][3]){ ary[1][1] = 2;}//ポインタでも扱いは同様と思ってるとvoid func(int *ary){ ary[1][1] = 2;//エラー!}
  • 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
  • 38. 今日の確認+αchar str1[5] = "abcd";char str2[] = "abcd";char *str3 = "abcd";どう違うか?
  • 39. 今日の確認+αchar str1[5] = "abcd";char str2[] = "abcd";どちらも同じ。char型の配列、要素数5 a b c d 0
  • 40. 今日の確認+αchar *str3 = "abcd";メモリ上の何処かに{a,b,c,d,0}の配列が作られるその配列の先頭のアドレスがstr3に格納{a,b,c,d,0}の書き換えなどの操作は動作未定義
  • 41. 今日の確認+α+βvoid func1( char str1[5] ){ ... };void func2( char str2[] ){...};void func3( char *str3 ){...};どう違うか?
  • 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] ); きもちわるいぃぃぃぃぃいいいい