• ベストアンサー

値を返り値に返すのと参照渡しした引数に格納することの違い

プログラミングをしていて、次のような2種類の形式の関数をみることがあります。 void sum(int a, int b, int& c); //aとbの和をcに格納する int sum(int a, int b); //aとbの和を返す 上の例のint &cは参照渡しされる引数という意味で、CやC++、PHPなどで同様です。 この、計算結果を参照渡しした引数に格納するのと、返り値に返すことの違いがよく分かりません。計算結果が複数ある場合は、前者の方が便利でしょう。しかし計算結果が1つだけなのに前者の方法を採っている関数も多く見かけます。個人的には、計算結果を返り値として返す後者の方法の方が感覚的に自然だと思うのですが、なぜ前者のような関数が存在するのか、教えていただきたく存じます。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

・複数の値を返したい ・↑の応用) 値とエラー等の情報を返したい if ( MySqrt(a,b) ) { printf( "ERROR" ); } // a>0ならb=√a,戻り値0, a<=0ならbは無効で戻り値1 ・戻り値として返すとパフォーマンスが悪い(C/C++の構造体等) あるいは、関数内で変数に代入→戻ってきて呼出し側の変数に代入、というわずかな処理でも速くしたい。 ・↑と関係して、同様の関数と引数の形を揃えた 構造体用が MyFunc1(a,b) / 数値用が b = MyFunc2(a) と見た目が変わらないように。 ・戻り値の型を厳密に指定したい double c = sum(a,b) ;等と暗黙の型変換をしないようにしたい。 ・戻り値を返すサブルーチンが書けなかった言語からのなごり 以上、思いついたものを書いてみました。

その他の回答 (3)

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.4

一つのプログラム中で混在していると、気まぐれとしかいいようがないですね。 関数によっては、「結果」と呼ぶべきものと、「処理が正常であったか」を返す必要があります。たとえば、fopen() は「ファイルポインタ」も返さないといけないし、「オープンが正常だったか」も返さないといけない。そこで、ファイルポインタがNULLにならないことを利用して、エラー時にはNULLを返すという決めにすることで、返り値一つで済ませているわけです。でも、これではエラーの理由を返せません。 システム関連の関数では、グローバル変数 errno を使って理由を返すことが多いです。理由を知りたい場合は、#include <errno.h> した上で、errnoを参照します。 ユーザが書くプログラム中で定義する関数のうちの少なからずのものが「正常かどうか」を返す必要がある場合、グローバル変数などは使わず、返り値で「正常かどうか、エラーならどんなエラーか」を返すということに統一して、「結果」は必ず引数で返す。「正常かどうか」を返す必要のない関数でも、0でも返すことにしておいて必ず「結果」を引数で返すことにするのがよく行われるようです。 このルールのメリットとしては、「最初は正常かどうかを返す必要がなかったが、処理の中身が増えて正常かどうかおよびエラー理由を返す必要が出てきた」場合に、修正が楽なことです。

  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.3

#1で書かれていること以外でよく使うのは、値の参照と代入を同時に行いたい場合ですね。 例えば、aにbを加算するというような場合や、複数のエラーチェックで最大のエラーレベルを調べたい場合など。

回答No.2

> 前者のような関数が存在するのか それはプログラム言語の仕様としてですか? 言語仕様として存在させなきゃ自由度が下がるじゃないですか。 C言語などは、とても自由度の高い言語なので、 関数をどう実現するかは、プログラマーの勝手です。 あまりに自由度の高いのでバグがとっても出やすいです。 なので、バグが少なくなるように、 コーディング規約を会社や部署ごとに決めます。 コーディング規約で前者を禁止すれば、書きませんし、 禁止しなければ書いても良いというだけでしょう。

関連するQ&A

  • C言語:関数の返り値と引数について

    C言語:関数の返り値と引数について C言語の関数を作るとき、ほしい値とかを引数にして渡す場合と、そのまま返り値で渡す場合の二種類がありますよね? 例えば、 ・void Smooth( Image *src, Image *dst, int param ); ・Image *Smooth( Image *src, int param ); みたいな感じで mallocとかは返り値で渡してますけど、opencvの関数(例えばcvSmooth)とかは引数にしてます これって使い分けとかあるんでしょうか?

  • 戻り値と返り値の違い

    タイトルの通りの質問内容です。 僕が調べた限りは「同じ」と言う意見が多数でした。 中には ・参照渡しした引数の関数通過後の結果が戻り値、  関数自体が返すのが返り値 とか ・引数なしの関数で戻るのが戻り値、引数ありの関数で  戻るのが返り値 とかはたまたその逆とか、混沌としています。 気になります。

  • 関数の引数と実引数の取り扱いについて

    C言語初心者です. 関数の引数と実引数の取り扱いについて,教えていただきたいことがあります. 例えば,2変数の和を求める関数を考えると,以下のようになると思います. #include <stdio.h> double sum(double x, double y); int main(void) { double a, b, wa; a=2.0; b=3.0; wa=sum(a,b); return 0; } double sum(double x, double y) { double total; total=x+y; return total; } このとき,mainプログラムでは,a,bふたつの変数を定義しておいて,関数sumに入れて計算させているわけですが,mainプログラムで変数x,yを定義しておいて,以下のようなプログラムにするのはありでしょうか? 参考書などをみると,前者のように取り扱っているようなのですが,試しに後者で実行させてみても同じ結果となりました. #include <stdio.h> double sum(double x, double y); int main(void) { double a, b, wa; a=2.0; b=3.0; wa=sum(a,b); return 0; } double sum(double x, double y) { double total; total=x+y; return total; }

  • 関数 左辺値 参照 返り値 

    こんにちは。宜しくお願い致します。 > たとえば,下のサンプルプログラムでは関数fが参照を返すようになっているため,この関数fを代入の左辺においた,f(a, n) = 10;のような式が許される. > > #include <iostream> > using namespace std; > > int& f(int* a, int n) > { (2)~ return a[n]; > } > > int main(void) > { > const int n = 5; > int arr[n] = { 1, 2, 3, 4, 5 }; (1)~ f(arr, 3) = 10; > for (int i = 0; i < n; ++i) > cout << arr[i] << endl; > return 0; > } 上のサンプルプログラムで左辺値に参照を返す関数が(1)~あるのですが 動作が分りません。 関数内部の(2)~return a[n];というところで、関数の返り値int&の参照はa[n]という変数になるので、(1)~の結果としてa[n]に10が代入されるのでしょうか?教えてください。

  • 参照型の変数をポインタ引数を持つ関数に引数を書く方法

    C++の参照を使って以下のソースを試したのですが、 memmoveの引数のところでエラーが出ます。 memmoveの引数はポインタ型で合いません。 実体コピーしたい場合、どのようにすればよいのでしょうか? const AA &aとすれば、a自体が関数内で書き換わる心配がないので、 C++の参照型は、ポインタより安全と理解しているのですが その認識は間違っていないでしょうか? struct aa{ int x; int y; }AA; void test(AA &a) { AA b; memmove(b, a, sizeof(AA)); } void main(){ AA c; test(c); }

  • PHPの参照わたしについて

    PHPの参照わたしについて質問です。 例えば、ユーザー定義関数の引数を参照渡しとする場合 function test(&$string){ $string .="参照渡し"; } $aaa = "文字列"; test($aaa); print $aaa; 等とすると、一切値のコピーがおこなわれませんよね? 次に function test($string){ $string . ="参照渡し"; return $string; } $bbb ="文字列"; $ccc = test($bbb); print $ccc; と上記のようにした場合、値のコピーが行われるのは 関数の引数に渡すときと 返り値を返すときの2回行われてるんですかね? もし、値のコピーが二回行われているとするなら 次のようにしたら値のコピーは一度だけ・・・少なくとも上の例よりPHPの動作より 軽い?ものになるのでしょうか・ function &test($string){ $string .= "参照わたし"; return $string; } $ddd = "文字列"; $eee =& test($ccc); //ここで関数の返り値を参照渡しする この場合、値のコピーが行われるのは関数に引数を渡すときの1回だけでしょうか? copy on write による動きは無視しておいて、 オブジェクト指向なプログラムでなくユーザー定義関数であれば このように関数の返り値を参照わたしにした方が、理論的?には早いのでしょうか? この場合、引数も参照渡しにすると破壊的関数になるのでそれは避けたいが、 なるべく値のコピーは防ぎたいという状況だと考えてください。 実際、こんな風にすべてのユーザー定義関数の返り値を参照にして定義するなんてこと おそらくないとおもうのですが、単純にコピーの回数がきになったのです。 よろしく御願いします。

    • ベストアンサー
    • PHP
  • C++ 関数プロトタイプと値渡し・参照渡しについて

    次のコードは、入門書にあった値渡しのサンプルです。 値渡しなので、a=5 ,b=10が出力されます。 void swap(int x,int y); //←抜けていた int main(){ int a=5; int b=10; swap(a,b); cout<<"a="<< a << "\n"; cout<<"b="<<b<<"\n"; } void swap(int x,int y){ int tmp=x; x=y; y=tmp; } しかし、自分で入力したところ何故かa=10,b=5が出力されました。 (VisualC++2008で実行しました。) よく見てみると、上記1行目の関数プロトタイプが抜けていました。 入門書を読んだ限りでは、次の2点が理解できません。 (1)main関数の後ろにswap関数があり、関数プロトタイプが無いのでコンパイルエラーになるはずなのにならない (2)値渡しのはずなのに参照渡しと同じ結果になる よろしくお願いします。

  • const参照をポインタ引数として渡すには?

    Aというクラスがあって、BはAを継承しているとします。 そこで、Bのconst参照を返却する以下の関数定義があったとします。 const B& getB() { return b; //bはB型 } さらに次の関数があります。 void C(A* a) { //適当な処理 } ここでCを以下のように呼ぼうとするとコンパイルエラーになります。 C(getB()); Cは引数として型Aを求めていますが、BはAを継承しているので、 そのまま渡しても問題ないと思います。 次に、Cは引数としてポインタを求めているのにgetBの戻り値の参照をそのまま 渡しているからまずいのだと思い、以下のようにしました。 const B& hoge = getB(); C(*hoge); //参照をポインタに変換 しかし、さらに型が違うとエラーになります。 どこがまずいのでしょうか? それと、上では参照をポインタに変換するために変数hogeを宣言していますが、 それを省略して一気にやる方法はないでしょうか? C(*getB()); のようなやり方がしたいのですが。

  • 関数の引数に 値を入れることを 渡す その関数が結

    関数の引数に 値を入れることを 渡す その関数が結果を出すことを 返す とか 返り値戻り値 という この認識であっていますか?

  • ポインタ引数をさらにポインタ引数に渡す方法

    ポインタ引数をさらに関数のポインタ引数として設定するには、 どうしたらよいのでしょうか? イメージとしては、 int 関数A(*a *b) { *a = 5; *b =3; 関数B(*a *b) } またポインタ引数の関数内で、 ポインタ指定せずに変数を使えるのでしょうか? int 関数A(*a *b) { a = 5; b =3; 関数B(*a *b) }

専門家に質問してみよう