[C言語]値渡しと参照渡し(ポインタ渡し)を解説してみる[初心者]

C言語

どうも〜シュモクザメです。
いきなりですがC言語を書いていてこんな場面ありませんでしたか?

main関数内で扱っている変数を、外部の関数で計算してそのまま値を保持してほしい、、

てことでこの悩みを解決する考え方、値渡し参照渡しを解説します
このような悩みがまだない方にもかなり有用なテクニックなので是非ご覧ください!
もちろん参考のコードも貼ってありますので活用してください!

またこの記事ではゴリゴリにポインタを用います!
ポインタについて不安な方はこちらの記事で解説しているので是非呼んでください!

C言語における関数の使用

C言語の関数ってこんな感じですよね

int SAME(int a, int b){
    printf("%d  %d",a,b);
    return a+b;
}

これが基本ですよね。
何らかの処理を関数で行なって、その計算によって出た値を取り扱いたい時はreturnでその値を返すことで、他の関数でも扱える!!って感じですよね。
ただここで思うことは、

あれ?returnでしか値を取り出せないの?

だとしたら一つしか値を取り出せない、、などとさらに疑問が出てきますね。
今日はここら辺についての記事です。

値渡し

とりあえず値渡しについて説明します。
まあこれはほとんどの人がこれまで使ってきた関数の扱い方だと思います。
コードです。

void add(int a, int b, int c){
    c = a + b;
}

int main(int argc, const char * argv[]) {
    int a = 1;
    int b = 2;
    int c = 0;
    printf("a = %d\nb = %d\n",a,b);
    add(a,b,c);
    printf("c = %d\n",c);
    return 0;
}

実行した結果が以下です

あれ?関数addでc = a+b としたのにcが0のままじゃん

そうです。これが値渡しの特性です。
仮引数に渡した変数は関数内で変更されても、渡した側では変更されていない。ということです。

あくまで関数に渡したのは変数の値のデータで、変数自体を渡していないんです。

なので関数内で色々しようと渡した側ではなんの影響もないんですよね。
まあ今のパターンだったら

int add(int a, int b, int c){
    c = a + b;
    return c;
}

とすれば関数の返り値でa+bの値が取り出せます。
ですがcに限らず他の値も一度にmainに持っていきたい時はどうしようってなりますよね。(a-bとかa*bとか)

参照渡し

先ほどのコードを参照渡しにしてみます。

void add(int a, int b, int *c){
    *c = a + b;
}

int main(int argc, const char * argv[]) {
    int a = 1;
    int b = 2;
    int c = 0;
    printf("a = %d\nb = %d\n",a,b);
    add(a,b,&c);
    printf("c = %d\n",c);
    return 0;
}

仮引数がint cからint *cになってる!!

はい、参照渡しでは変数の値ではなく、ポインタ。つまりアドレスを仮引数とします。
渡されるのはあくまで変数が格納されているアドレスの値そのものであり、変数や、変数の値が渡されるわけではありません。
このアドレスを渡すことを参照渡しって呼んでるんですね。

アドレスがわかればそのアドレスの地点にダイレクトでアクセスできますよね?
これを利用して値を扱っていきます。関数本文で

*c = a + b;

としてアドレスにある変数(この場合はc)を実体化してそこに値を代入、
という操作を行っています。

実行した結果がこうです。

うん、いけてる。

参照渡しの応用

関数内で値を変更することはわかりました。
ここからはさらに、一つの関数で複数の値を取り出すことを考えましょう。
途中でも述べた通り、returnだけだと一つしか値を取り出せなくて不便ですからね。
コードです。

void cal(int a, int b, int *c1, int *c2, int *c3){
    *c1 = a + b;
    *c2 = a - b;
    *c3 = a * b;
}

int main(int argc, const char * argv[]) {
    int a = 1;
    int b = 2;
    int c1 = 0;
    int c2 = 0;
    int c3 = 0;
    printf("a = %d\nb = %d\n",a,b);
    cal(a, b, &c1, &c2, &c3);
    printf("a + b = %d\n",c1);
    printf("a - b = %d\n",c2);
    printf("a * b = %d\n",c3);
    
    return 0;
}

複数の値を変更したい時、取りだしたい時は上のコードの関数のように仮引数にポインタ型をその分だけ追加すれば良いのです。
簡単ですね。
何かの値を変更したい時はその値のアドレスを渡せばおkです。
新しく値を取りだしたい時は、一旦関数外で宣言と初期化を行なって、その値のアドレスを渡すって感じですね。

まとめ

いかがでしたか?
ポインタの知識さえあれば使える超有用な考え方です。
というより、参照渡しがないと不便なレベルで使ってますね。

よければポインタの記事も書いたのでみてください!
ではまた

コメント

タイトルとURLをコピーしました