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 j;

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

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

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;

}



変更して


次のように書き換えても


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


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


#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[]を()内にかきこみました*/


int main (void){

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

newmadefunction(newhairetu);

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

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


int j;

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

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

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;

}


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



アレサ「


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



ポインタ変数をつかった

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


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


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


アレサ「


よって


*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倍になります。


このように


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



ソーラー「つまり こういうことかな?


ポインタ変数を使った

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


格納した時点で


配列変数

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 <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は定義されていないからです。


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


ポインタ変数を使った

*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で共有
  • はてなブックマークでブックマーク

作者を応援しよう!

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

応援したユーザー

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