...

ポインタ変数は変数の値がアドレスになっている. 配列のアドレスは連続

by user

on
Category: Documents
1

views

Report

Comments

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
Fly UP