main関数内で定義された配列に格納されている数値データを自作関数を使って変更してみましょう。自作関数の引数が(int hairetu[])となっている場合 その2

てんC


「ここでもう1度先ほどのプログラムに戻ります。」


#include <iostream>


using namespace std;



void newmadefunction(int hairetu[]) {


*hairetu = *hairetu * 2;

*(hairetu + 1) = *(hairetu + 1) * 2;

*(hairetu + 2) = *(hairetu + 2) * 2;

*(hairetu + 3) = *(hairetu + 3) * 2;

*(hairetu + 4) = *(hairetu + 4) * 2;


}

/*int hairetu[]をnewmadefunction(int hairetu[])のように引数として()内にかきこみました*/


int main() {

int newhairetu[5] = { 1,2,3,4,5 };

newmadefunction(newhairetu);


/*配列newhairetuのアドレスを格納している

ポインタ変数newhairetuが自作関数の引数として渡されています*/


int j;

for (j = 0; j<5; j++)

cout << newhairetu[j]<< "\n";


return 0;

}


ビルド実行結果


2

4

6

8

10


てんC「


ここで

このプログラムの


自作関数の定義を


void newmadefunction(int hairetu[]){


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

から


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}



変更して


次のように書き換えても


同じビルド実行結果を得ることができます。」


マックス「


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

から


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}


か・・・


う~む おくゆかしい」





#include <iostream>


using namespace std;



void newmadefunction(int hairetu[]) {

hairetu[0] = hairetu[0] * 2;

hairetu[1] = hairetu[1] * 2;

hairetu[2] = hairetu[2] * 2;

hairetu[3] = hairetu[3] * 2;

hairetu[4] = hairetu[4] * 2;

}


/*int hairetu[]を自作関数 newmadefunction()の()内にかきこみました*/


int main() {

int newhairetu[5] = { 1,2,3,4,5 };

newmadefunction(newhairetu);


/*配列newhairetuのアドレスを格納している

ポインタ変数newhairetuが自作関数の引数として渡されています*/


int j;

for (j = 0; j<5; j++)

cout << newhairetu[j]<< "\n";


return 0;

}


ビルド実行結果


2

4

6

8

10



ソーラー「

なんか自作関数の定義が


大分ちがうね。


void newmadefunction(int hairetu[]){


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

から


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}




変更されているのに


ビルド実行結果は同じなんだね。


こちらの変更された自作関数の定義


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}

for文を使って


void newmadefunction(int hairetu[]){

int i;

for(i=0;i<5;i++)

hairetu[i]=hairetu[i]*2;

}


のように書き換えることができるかな(*^▽^*)



てんC「


ここで注目すべき点はどこかというと・・・」


マックス「どこ? どこ?」


てんC「


ポインタ変数をつかった

*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;


でなく


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;



がつかわれていることにあるのですの。


このプログラムでは


void newmadefunction(int hairetu[])


のint hairetu[]に


配列newhairetuのアドレスを


格納しているポインタ変数newhairetu


が渡されています。


参照渡し(ポインタ渡し)ですね。


このとき


int hairetu[]に

よって生成される


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスを格納しているポインタ変数

newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4が


代入されています。


つまり


配列newhairetuの配列変数のアドレスを格納しているポインタ変数が

配列hairetuのアドレスを格納しているポインタ変数に


hairetu=newhairetu;

(hairetu+1)=(newhairetu+1);

(hairetu+2)=(newhairetu+2);

(hairetu+3)=(newhairetu+3);

(hairetu+4)=(newhairetu+4);

代入されています。


ですので


この状態で


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

が行われるということは


*newhairetu=*newhairetu*2;

*(newhairetu+1)=*(newhairetu+1)*2;

*(newhairetu+2)=*(newhairetu+2)*2;

*(newhairetu+3)=*(newhairetu+3)*2;

*(newhairetu+4)=*(newhairetu+4)*2;


が行われるということになります


ソーラー「なるほどぉ~」


てんC「


よって


*newhairetu=*newhairetu*2;

*(newhairetu+1)=*(newhairetu+1)*2;

*(newhairetu+2)=*(newhairetu+2)*2;

*(newhairetu+3)=*(newhairetu+3)*2;

*(newhairetu+4)=*(newhairetu+4)*2;

が行われることにより



*newhairetu

*(newhairetu+1)

*(newhairetu+2)

*(newhairetu+3)

*(newhairetu+4)


に格納される値は2倍になります。


ここで

*newhairetu

*(newhairetu+1)

*(newhairetu+2)

*(newhairetu+3)

*(newhairetu+4)



配列newhairetuの配列変数


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


に格納されている


数値データをあらわすので


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


に格納されている数値データの値は2倍になります。


このように


newmadefunction(newhairetu);


が実行された場合


int hairetu[]に

よって生成される

ポインタ変数

hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスを格納しているポインタ変数

newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4が


代入されています。


つまり

main関数内で配列宣言された配列変数


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


に格納されている数値データを


2倍にすることができる



       参照渡し(ポインタ渡し)が行われているというわけです。


そして


int hairetu[]に

よって生成される

ポインタ変数

hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスを格納しているポインタ変数

newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4が


代入されると


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


のアドレスのメモリにアクセスして


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスのメモリに

納されている数値を表すことになりますので💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;


の代わりに


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;


をもちいて


main関数内で配列宣言された配列変数


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


に格納されている値を


2倍にすることができます。」








ところで次のように考える方もおられるのではないでしょうか?



newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4が


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4


代入された状態にもかかわらず


ポインタ変数

hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

を使って


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;


を行わず


つまり

ポインタ変数を使わず


ただ単に



配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

を用いて


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

実行されても


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


がアクセスしているメモリに格納されている数値データは


2倍に変更されても



main関数内で配列宣言された


配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

に格納された数値データは2倍になるということはないのではないか?


と・・・






もう1度繰り返して述べますと


配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスを格納しているポインタ変数

newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4が


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4


代入されると💖💖💖💖💖


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


のアドレスのメモリにアクセスして💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスのメモリに

格|納されている数値データを表すことになります《💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖》


ですので


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;


の代わりに


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;


をもちいて


main関数内で配列宣言された配列変数


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


に格納されている数値データを


2倍にすることができます。」



ソーラー「つまり こう思っている人がいるということかな?


自作関数の定義が

以下のように設定されているのを見て

👇

void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

👆ここの部分に注目したということかな?


ポインタ変数を使った

*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

実行せず


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

をつかった

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;


を実行しても


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

のアドレスのメモリにアクセスするので

(👆ここが間違っています


int hairetu[]にnewhairetuが代入された時点で


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしているメモリにアクセスすることになります


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

を用いても


main関数内で配列宣言された


配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

に格納されている数値データを変更できないのではないか?


ということだよね。


int hairetu[]に


配列newhairetuのアドレスを格納したポインタ変数


        💖newhairetuを💖


格納した時点で


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


のアドレスのメモリにアクセスして💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアドレスのメモリに

格|納されている数値データを表すことになるんだね《💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖》




もしかしたら


そのように考える人は


次のプログラムを想定しているんじゃないかな。


#include <iostream>


using namespace std;


void newmadefunction(int* ptx) {

*ptx=*ptx * 2;

}



int main() {

int a=1;


newmadefunction(&a);

cout << a<< "\n";


return 0;

}


ビルド実行結果


2



ソーラー「このプログラムでは


自作関数の引数となっているポインタ変数ptxに


main関数内で変数宣言された変数aのアドレス&aが代入されているね。


そうすると


*ptxは変数aのアドレス&aのメモリに格納されている数値をあらわすことになり


*ptx=*ptx * 2;


が実行されると


*ptxに格納されている数値データは1から2へ


2倍になる。


つまり


変数aのアドレス&aのメモリに格納されている数値データは2倍になる。

変数aに格納されている数値データは2倍になる。


わけだね。


でも

*ptx=*ptx * 2;


ではなく


x=x*2;


と記述してあると


x=x*2;


は変数xと名づけられたメモリに格納されている数値データを


2倍にすることになるよね。


だから


変数aのアドレス&aのメモリに格納されている数値データ

つまり

変数aに格納されている数値は2倍にならないはずだよね。




試しに


*ptx=*ptx * 2;


ではなく


x=x*2;


とプログラムを記述すると


#include <iostream>


using namespace std;



void newmadefunction(int* ptx) {

x = x * 2;

}



int main() {

int a=1;


newmadefunction(&a);

cout << a<< "\n";


return 0;

}


ビルド実行結果



エラー (アクティブ) E0020 識別子 "x" が定義されていません



ソーラー「このプログラムは


そもそも


ビルド実行ができません。


ポインタ変数ptxは定義されていても


変数xは定義されていないからです。


確かに


この例を思い浮かべている人は



ポインタ変数を使った

*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

実行せず


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

をつかった

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;


を実行しても


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

のアドレスのメモリにアクセスするので

(👆間違っています)

main関数内で配列宣言された


配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

に格納されている数値データを変更できないのではないか?


とおもうはずだね。


ここが


int hairetu[]に


配列newhairetuのアドレスを格納したポインタ変数


newhairetuを


格納したときの特徴かな」




🌞 🌞 🌞 🌞 🌞 🌞 予告 🌞 🌞 🌞 🌞 🌞 🌞


なぜ


void newmadefunction(int hairetu[]){


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

から


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}



と表記法を変えることができるのかは後のエピソードでも


語られます


                       お楽しみに!


🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞



てんC「


そして


自作関数の定義は


void newmadefunction(int hairetu[]){


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

のように記述されるのでなく


void newmadefunction(int hairetu[]){


hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}


と記述する


こちらの表現方法が一般にもちいれます。


なぜかというと


void newmadefunction(int hairetu[]){


*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

}

はこれ以上簡略化して記述できないのに対し


void newmadefunction(int hairetu[]){

hairetu[0]=hairetu[0]*2;

hairetu[1]=hairetu[1]*2;

hairetu[2]=hairetu[2]*2;

hairetu[3]=hairetu[3]*2;

hairetu[4]=hairetu[4]*2;

}

さらにfor文を用いて


次のように簡略化することができるからなのです。」




void newmadefunction(int hairetu[]){

int i;

for(i=0;i<5;i++)

hairetu[i]=hairetu[i]*2;

}



てんC「


これは何を意味するのかというと


例えば

main関数内で

配列宣言

int hairetu[10000];

が行われたとします。


すると


配列変数が次のように


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[9999]


10000個生成されます。


もし


この10000個の配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[9999]


に格納されている値を


自作関数を使って


2倍にしたい場合


ポインタ変数を使った場合では簡略化した表現ができないため


自作関数の定義を


この10000個の配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[9999]


にあわせて


次のように記述しなければならなくなります


void newmadefunction(int hairetu[]){

*hairetu=*hairetu*2;

*(hairetu+1)=*(hairetu+1)*2;

*(hairetu+2)=*(hairetu+2)*2;

*(hairetu+3)=*(hairetu+3)*2;

*(hairetu+4)=*(hairetu+4)*2;

*(hairetu+9998)=*(hairetu+9998)*2;

*(hairetu+9999)=*(hairetu+9999)*2;

}


自作関数の定義を

記述するのに10002行かかっています。


それに対し


ポインタ変数を用いない表現の場合は



void newmadefunction(int hairetu[]){

int i;

for(i=0;i<10000;i++)

hairetu[i]=hairetu[i]*2;

}


と5行で済んでしまうのです。


こちらの表現のほうが便利なので


一般にはこちらの表現が用いられています。」


  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る