LotosLabo

プログラミング技術とか気になった情報を載せていきます

C++について4

アドレス


C++ のアドレスはメモリの場所を直接表すために使われる、メモリの住所です。
16進数で表すことになっています。


変数のアドレスを調べる


アドレス演算子

& 演算子


例: 変数のアドレスを出力する

int main()
{
 int a = 5;
 
 cout << "変数aの値は" << a << "です。\n";
 cout << "変数aのアドレスは" << &a << "です\n";
 
 return 0;
}



出力結果

変数aの値は5です
変数aのアドレスは0030FA40です。

このアドレスの部分は個人のコンピュータのアドレスですので、人それぞれです。


ポインタ

アドレスを格納する特殊な変数

ポインタの宣言


型名* ポインタ名

例:

int* pA;



ポインタpAを宣言


int型の変数のアドレスを格納できるポインタpA
ポインタには指定した型以外の型は指定できません。


例:

int main()
{
 int a;
 int* pA; // ポインタpAを宣言します
 
 a = 5;
 pA = &a; // 変数aのアドレスをpAに格納する
 
 cout << "変数aの値は" << a << "です\n";
 cout << "変数aのアドレス(&a)は" << &a << "です。\n";
 cout << "ポインタpAの値は" << pA << "です\n";
 
 return 0;
}


出力結果

変数aの値は5です。
変数aのアドレス(&a)は0x00F4です。
ポインタpAの値は0x00F4です。


ポインタpAに変数aのアドレスを格納する。
変数aとポインタpAの間には何かしらの関係ができた。pAは変数aをさす。
pA(の値)が、変数a(場所)を指し示すようになった。

ポインタから変数の値を知る

ポインタから逆に辿って元の変数の値を知ることが出来ます。
*演算子は間接参照演算子と呼ばれています。


* ポインタ名

この演算子を使うとポインタに格納されているアドレスに対応する変数の値を知ることが出来ます。
たとえば、ポインタpAに変数aのアドレスが格納されているときは

*pA

と記述すれば、変数aの値を間接的に知ることが出来る。


例:

int main()
{
 int a;
 int* pA;
 
 a = 5;
 pA = &a;
 
 cout << "変数aの値は" << a << "です\n";
 cout << "変数aのアドレスは" << "です。\n";
 cout << "ポインタpAの値は" << "です\n";
 cout << "pAの値は" << *pA << "です\n";
 
 return 0;
}



出力結果:

変数aの値は5です
変数aのアドレスは0050FF08です
ポインタpAの値は0050FF08です。
*pAの値は5です。

つまり、*pA → aと同じ値なのです。


引数とポインタ


★誤った関数の定義


例:

void swap(int x, int y)
{
int tmp;
 
tmp = x;
x = y;
y = tmp;
}



①xの値をtmpに代入
②yの値をxに代入
③tmpの値をyに代入


例:

int main()
{
 int num1 = 5;
 int num2 = 10;
 
 swap(num1,num2);
 }
 
 void swap(int x, int y)
{
 int tmp;
 
 tmp = x;
 x = y;
 y = tmp;
 }


この方法だと値は交換されない。


<値渡しと参照渡し>

関数に実引数を渡すには実引数の「値」だけが関数内に渡されます。

そしてポインタをうまく使うことで関数の呼び出し時に指定した
引数の値を変更することが出来ます。

このために指定した関数の仮引数をポインタとして定義することが必要です。

例:

void swap(int* pX, int* pY)
{
int tmp;
 
 tmp = *pX;
 *pX = *pY;
 *pY = tmp;
}


この方法を使うことでうまく値が渡されます。
なお、関数が呼び出されるときに、実引数のアドレスが関数に渡されることを、参照渡し
と呼んでいます。

引数と参照


参照とは

型名& 参照名 = 変数;

int a;
int& rA = a;

参照rAを変数aで初期化します。


例:

int main()
{
 int a = 5;
 int& rA = a;
 
 cout << "変数aの値は" << a << "です。\n";
 cout << "参照rAの値は" << rA << "です\n";
 
 rA = 50;
 
 cout << "rAに50を代入しました\n";
 cout << "参照rAの値は" << rA << "に変更されました\n";
 cout << "変数aの値も" << a << "に変更されました\n";
 cout << "変数aのアドレスは" << &a << "です\n";
 cout << "参照rAのアドレスも" << &rA << "です\n";
 
 return 0;
}



出力結果

変数aの値は5です。
参照rAの値は5です。

rAに50を代入しました
変数aの値も50に変更されました

変数aのアドレスは0x00F4です。
参照rAのアドレスも0x00F4です。

つまりrA = aとなるのです。

また実引数を変更したくない場合には
const を引数の前に付けます。


配列

同じ型の値を複数まとめて記憶する。


配列の宣言


型名 配列名[要素数];

int test[5];
test[0] = 10;
test[1] = 20;
test[2] = 30;
test[3] = 40;
test[4] = 50;


配列の要素は 配列名[添字] =式;
となる。


例: 配列要素の値を出力する

int main()
{
 int test[4];
 
 test[0] = 10;
 test[1] = 20;
 test[2] = 30;
 test[3] = 40;

for(int i=0; i<5; i++){
cout << i+1 << "番目の人の点数は" << test[i] << "です\n";
}
  
return 0;
}




出力結果

1番目の人の点数は10です。
2番目の人の点数は20です。
3番目の人の点数は30です。
4番目の人の点数は40です。

配列の初期化


型名 配列名[要素数] = {値0,値1・・・・};

int test[3] = {10,20,30};

{}の中に指定する値は初期化子と呼ばれています。

また要素数を指定しなくても5つの配列要素が用意されます

int test[] = {10,20,30};


配列の応用


<キーボードからの入力>

int main()
{
const int num = 4; // 人数の指定に定数を使う
int test[num];
 
cout << num << "人の点数を入力してください\n";
for(int i=0; i<num; i++){
cin >> test[i]; // キーボードから人の点数を入力
}
  
for(int j=0; j<num; j++){
cout << j+1 << "番目の人の点数は" << test[j] << "です\n";
}
   
return 0;
}





多次元配列


型名 配列名[要素数][要素数];

int test[2][3];

test[0][0] = 10;
test[0][1] = 20;
test[0][2] = 30;
test[1][0] = 40;




と入力していきます。


出力には forでint iと指定し、test[0][i] と test[1][i]で出力できます。


またこのように複数行にわたって書くと面倒なので

int test{2][3] = {
{10,20,30},{40,50,60}
};

このように書くことをおすすめします。


配列とポインタの関係


配列とポインタを組み合わせることで要素が格納されているアドレスを知ることが出来ます。


&test[0]
&test[1]

さらに配列では、特別な書き方で配列要素のアドレスを表すことが出来ます。

test

配列名を書くだけで先頭要素のアドレスを表すことが出来ます。



例:

int main()
{
  int test[3] = {10,20,30};
  
  cout << "test[0]の値は" << test[0] << "です\n";
  cout << "test[0]のアドレスは" << &test[0] << "です\n";
  cout << "testの値は" << test << "です\n";
  cout << "つまり*testの値は" << *test << "です\n";
  
  retrun 0;
}



出力結果

test[0]の値は80です。
test[0]のアドレスは0x00E4です
testの値は0x00E4です
つまり*testの値は80です。


ポインタ演算

  1. p + 1      pがさしている要素の次の要素のアドレスを得る
  • p - 1      pがさしている要素の前の要素のアドレスを得る

    p1 - p2    p1とp2の間の要素数を得る
   
   

    1. p++      pがさしている次の要素のアドレスを得る
    • p--      pがさしている前の要素のアドレスを得る


int test[3] = {10,20,30}

test → 値は10

*(test +1) → 値は20


引数と配列


配列の要素の指定を引数を渡します。

例:

double avg(int t[]); // 配列を関数の引数として使う

int main()
{
 int test[3];
  
 cout << "3人のテストの点数を入力してください\n";
 for(int i=0; i<3; i++){
 cin >> test[i];
}
 double ans = avg(test); // 配列名を実引数として渡す
 cout << "3人の平均点は << ans << "点です\n";
  
 return 0;
}
 
double avg(int t[])
{
double sum = 0;
for(int i=0; i<3; i++){
sum += t[i];
}
return sum/3;
}