Comments
Description
Transcript
ポインタ変数は変数の値がアドレスになっている. 配列のアドレスは連続
! ポインタ変数は変数の値がアドレスになっている. 配列のアドレスは連続して確保される. ! ! 下の例だと4bitずつアドレスがずれている. ポインタ変数は別の変数の場所を指し示している. int main(void){ 1000 int x = 5; 1004 1008 int *ptr = &x ptr 1020 cout << x << endl; cout << &x << endl; 1012 cout << *ptr << endl; 1016 1020 x cout << ptr << endl; 5 cout << &ptr << endl; 1024 return 0; } //print_adress.cpp //実行例 int main(void){ const int size =10; % ./a.out int list[size]={0}; 5 for(int i=0; i<size; i++){ 0x7fff518e4bb88 cout << &list[i] << endl; 5 } 0x7fff518e4bb88 0x7fff518e4bb80 return 0; } //実行例 0x7fff5e09abd0 0x7fff5e09abd4 0x7fff5e09abd8 0x7fff5e09abdc 0x7fff5e09abe0 0x7fff5e09abe4 0x7fff5e09abe8 0x7fff5e09abec 0x7fff5e09abf0 0x7fff5e09abf4 ! 配列の要素位置をアドレスとするポインタ変数と配列の関係. ! 下のプログラムの実行結果はどうなる?? //test.cpp int main(void){ int a[4] = {1, 2, 3, 4}; int *x = &a[0]; int *y = &a[2]; cout << *x << , << *y << endl; cout << x[0] << , << x[1] << endl; cout << y[0] << , << y[1] << endl; ! 配列の要素位置をアドレスとするポインタ変数と配列の関係. ! 下のプログラムの実行結果はどうなる?? 1000 x 1012 1004 y 1020 //test.cpp int a[4] = {1, 2, 3, 4}; int *x = &a[0]; 1008 1012 a[0] 1 1016 a[1] 2 1020 a[2] 3 1024 a[3] 4 3, 4 cout << x[0] << , << x[1] << endl; cout << y[0] << , << y[1] << endl; return 0; なぜ,こうなる?? } 配列の要素位置をアドレスとするポインタ変数と配列の関係. ! ポインタが配列のアドレスを保持する場合,ポインタが指し示す配 列要素を0番目として配列の要素にアクセス可能. ! ポインタ自身を配列のように扱える. xは配列aの先頭(a[0])アドレス. ! x[0]はa[0]にアクセス. ! x[1]はa[1]にアクセス. ! 1, 3 cout << *x << , << *y << endl; } ! % test 1, 2 int *y = &a[2]; return 0; ! //実行結果 int main(void){ yは配列aの3番目(a[2])アドレス. ! y[0]はa[2]にアクセス. ! y[1]はa[3]にアクセス. 1000 x 1012 1004 y 1020 x[0] a[0] a[1] a[2] a[3] 1008 1012 a[0] 1 1016 a[1] 2 1020 a[2] 3 1024 a[3] 4 *x (=x[0]) x[1] x[2] x[3] y[0] *y (=y[0]) y[1] ! ポインタ変数に配列の変数をそのまま代入すると,配列 の先頭アドレスがポインタ変数に保存される. //test2.cpp int *z = a; cout << z[0] << , << z[2] << endl; return 0; } char型の変数のアドレスは直接出力できない(前回) ! アドレスを表示しようとすると,変数の値が出力される. //chartest.cpp int main(void){ int a[4] = {1, 2, 3, 4}; ! int main(void){ char a = \0 ; int *z = &a[0]と同じ意味. char b = b ; char c[4] = { a , b , c , \0 } //実行結果 cout << &a << endl; % test2 cout << &b << endl; 1, 3 //実行結果 % chartest b abc abc cout << &c[0] << endl; cout << c << endl; return 0; } ! 理由は簡単にいうと,C++の仕様. 関数に配列を渡すこともできる. ! 文字列 = char型の配列 = charポインタのアドレス ! 配列を渡すときは,先頭のアドレスのみを渡す. ! char型の配列cに対して,一気に文字を出力したり入力できるの ! 引数は先頭のアドレスを受け取るポインタでよい. も上が理由. ▪ cout << c; ▪ cin >> c; ! ! 文字列の出力 ! 指定アドレスの先頭からnull文字( \0 )までの文字を表示. //test3a.cpp void print(int *ptr, int n){ for(int i=0; i<n; i++){ cout << ptr[i] << endl; } } int main(void){ int a[4] = {1,2,3,4}; ! null文字が見つからないと,プログラムが正常に動作しない. print(a, 4); //print(&a[0], 4)でもよい. return 0; } //実行結果 % test3a 1 2 3 4 ! 関数が配列を引数とすることを明示したい場合 ! ! 引数にポインタの形ではなく,配列の形で書く. //test3b.cpp void print(int ptr[], int n){ for(int i=0; i<n; i++){ cout << ptr[i] << endl; } } int main(void){ int a[4] = {1,2,3,4}; print(a, 4); //print(&a[0], 4)でもよい. //実行結果 % test3b 1 2 3 //test3b.cpp void print(int ptr[], int n){ サイズをもらわないと,どこまで 表示すればいいかわからない. for(int i=0; i<n; i++){ cout << ptr[i] << endl; } } int main(void){ int a[4] = {1,2,3,4}; 4 必要な値をサイズとして渡す. print(a, 4); //print(&a[0], 4)でもよい. return 0; return 0; } } ! ! 関数に配列を渡すと,配列内の値を自由に変更できる. 配列の値を関数内で変更させないようにするには? ! 引数の配列部分にconst宣言をする. //test4.cpp void print(const int ptr[ ], int n){ for(int i=0; i<n; i++){ cout << ptr[i] << endl; } } int main(void){ int a[4] ={1,2,3,4}; print(a, 4); //print(&a[0], 4)でもよい. return 0; } 関数に配列を渡す時,アドレスが渡されるだけで,配列 のサイズはわからないので,必要に応じてサイズも渡す. ! キーボードから配列への入力の復習. //input_array.cpp int main(void){ const int size = 10; const int ptr[] としているので,受け取った配列 の中身をこの関数内では変更でき ない. もし変更するようなプログラムを 書くと,コンパイルエラーを出し てくれる. int a[size] = {0}; int num =0; while(num < size && cin >> a[num]){ いくつ入力されるかわからない 配列に保存した要素数を保存 しておく変数を準備. num++; } print(a, num); return 0; } 短絡表現を利用. 要素数が配列のサイズ以上になる と,配列への入力を止める. 順番に注意!逆はダメ. ! 配列への入力に関数を利用する. ! //input_array2.cpp キーボードから入力を配列に保存 して,保存した要素数を返す. int input(int x[ ], int max){ int num = 0; 配列の最後尾に何かしらの終端記号がある場合は,それ を要素数の変わりに利用できる. //test4.cpp const int ptr[] としているので,受け取った配列 の中身をこの関数内では変更でき ない. もし変更するようなプログラムを 書くと,コンパイルエラーを出し てくれる. void print_string(const char str[]){ while(num < max && cin >> x[num]){ num++; } for(int i=0; str[i] != \0 ; i++){ return num; cout << str[i]; } int main(void){ input関数を呼び出す. 入力を格納するための配列とサイ ズを渡す. 入力された要素数が返ってくるの で,変数nで受け取る. const int size = 10; int a[size] = {0}; int n = input(a, size); print(a, n); return 0; } cout << endl; } } ! 配列の途中から最後尾を関数に渡すこともできる. //test5.cpp //実行結果 void print(const int x[ ], int size){ for(int i=0; i<size; i++){ cout << x[i] << cout << endl; } ;} % test5 12345 345 int main(void){ const int size = 5; int a[size] = {1, 2, 3, 4, 5}; print(a, size); print(&a[2], size-2); return 0; } print(a, size) ; print(&a[0], size) 配列の先頭アドレスと要素数を渡す. print(&a[2], size-2) 配列の2番目のアドレスとそこから 最後尾までの要素数を渡す. ! print(a, size); a[0] a[1] a[2] a[3] a[4] ! print(a, size-2); a[2] a[3] a[4] ,3 ,5 ! 配列内の重複した要素をすべて列挙する. //test6.cpp ! const int size = 10; for(int i=0; i<size; i++){ const int n = 2; } int i = 0 return size; while(i<size){ } ! i++; ! } (1) 3 1 2 4 } (8) i=9 : i+=find(&a[9], size-9, n) i += size-9 i=10 4 ! i=6 : i+=find(&a[6], size-6, n) ! iの値を表示して,i++ return 0; (5) i(=10)がsize以上なので,whileループから抜ける. i=1 i += 3 i=5 3 4 5 2 3 1 2 4 cout << ( << i << ) << endl; % test6 i=2 : i+=find(&a[2], size-2, n) ! iの値を表示して,i++ i += find(&a[i], size-i, n); //実行結果 i += 1 1 2 3 4 5 2 3 1 2 4 int a[size] = {1, 2, 3, 4, 5, 2, 3, 1, 2, 4}; if(x[i] == n){ return i; } ! ! iの値を表示して,i++ int main(void){ int find(const int x[ ], int size, int n){ i=0 : i+=find(&a[0], size, n) i += 2 i=8