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

アレサ


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


#include <stdio.h>


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 (void){


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


newmadefunction(newhairetu);


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

ポインタ変数newhairetuが自作関数の引数int hairetu[]に渡されています*/


int j;

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

printf("%d\n",newhairetu[j]);

return 0;

}


コンパイル結果


2

4

6

8

10


アレサ「


ここで

このプログラムの


自作関数newmadefunctionの定義を


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;


}



変更して


次のように書き換えても


同じコンパイル結果を得ることができます。


ソーラーさん(*´▽`*)」


#include <stdio.h>


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 (void){

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

newmadefunction(newhairetu);

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

ポインタ変数newhairetuが自作関数の引数のint hairetu[]に渡されています*/


int j;

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

printf("%d\n",newhairetu[j]);

return 0;

}


コンパイル結果


2

4

6

8

10



ソーラー「

なんか自作関数newmadefunctionの定義が


大分ちがうね。


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;

}


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



アレサ「


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



ポインタ変数をつかった

*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の配列変数のアドレスを格納しているポインタ変数newhairetuが

配列hairetuのアドレスを格納しているポインタ変数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;


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


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


アレサ「


よって


*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]

の管理しているメモリに

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



(ここは重要なポイントですね


                   solarplexussより)



ですので


*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倍にすることができるのですね。」



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


自作関数newmadefunctionの定義が

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

👇

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が代入された時点で


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


配列変数

newhairetu[0]

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]

は同じメモリにアクセスすることになります


配列変数

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 <stdio.h>



void newmadefunction(int* ptx) {

*ptx = *ptx * 2;

}



int main() {

int a = 1;


newmadefunction(&a);


printf("%d\n", a);


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 <stdio.h>


void newmadefunction(int* ptx) {

x = x * 2;

}



int main(void) {

int a = 1;


newmadefunction(&a);


printf("%d\n", a);


return 0;

}


コンパイル結果


EAZY IDECの場合


ファイル「C:/Users/solarplexuss/AppData/Local/EasyIDEC/project/hhhhhhhh/main.c」の

「4行目」で記述エラーを発見しました。

「x」が定義されていません。

名前が間違っていないかどうか確認してください。



Visual Studioの場合

ビルド実行結果



エラー C2065 'x': 定義されていない識別子です。

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



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


そもそも


コンパイルができません。


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


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



確かに


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


自作関数newmadefunctionが実行されるとき


newmadefunction(newhairetu);


のように


int hairetu[]に


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


        💖newhairetuを💖


格納しても


自作関数newmadefunctionの定義内で


ポインタ変数を使った

*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]

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

(👆間違っています


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

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



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


配列newhairetuの

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

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


とおもうはずだね。」



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


なぜ


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;

}


と記述する


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


なぜかというと


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;

}



アレサ「


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


例えば

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行で済んでしまうのです。


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


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

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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