• 締切済み

引数のポインタについて

関数で、アウトプット引数をポインタにするのはわかるのですが、 インプット引数をポインタにする理由って何かあるのでしょうか?

みんなの回答

回答No.10

#include <stdio.h> void zero(int* n) { *n = 0; } int main() { int n = 123; zero(&n); printf("n = %d\n", n); /* n = 0 */ return 0; } ポインタ無しにコレは書けない。

回答No.9

#7の回答を載せたものです。 > 長さに制限を付ければ可能ですが、長さ制限なしで実現できますか? 後出しで悪いと思っていますが、投稿してすぐにこのことに気づきました。 「文字列の長さに上限を設けてよいのであれば」という制限を付けるべきでした。

  • wormhole
  • ベストアンサー率28% (1621/5656)
回答No.8

#7の方へ >も、配列をメンバーとする構造体を作り、関数のパラメータだけでなく戻り値の型もその構造体にして、関数を引用するプログラム内の代入式で構造体オブジェクトを更新するという手法を使えば、さほどの労力を費やさなくても実現できます。 長さに制限を付ければ可能ですが、長さ制限なしで実現できますか? strcpy(),strcat(),strcmp(),memcpy()のいづれも長さの制限ありませんが。 C99で構造体の最後の要素だけ可変長配列を扱えるようにはなりましたけど引数として処理される場合は長さ0扱いですよ?

回答No.7

 C言語では、パラメータの渡し方は、値渡ししかありません。関数を引用するときは仮引数の型と同じ型の任意の式を実引数に指定することができます。ポインタ型の仮引数の時は任意のアドレス式を実引数に指定できます。実引数の値が仮引数の初期値になります。引数が構造体であれば、実引数の構造体オブジェクトのすべてのメンバーの記憶領域が仮引数の記憶場所にコピーされます。引数がポインタ型であれば実引数の値(アドレス値)が仮引数にコピーされてそれが仮引数の初期値になります。 ということで、#1の回答が的を射ていると思います。  配列名を式の中で使うと(例外はありますが)、配列名は先頭の配列要素へのポインタになります。配列名を実引数とするときは仮引数をポインタ型変数にします。(仮引数を配列として宣言しても関数内ではアドレス値を保存するためのポインタ変数のための記憶場所だけが確保されます。C言語の仕様としてそのように決められています。)したがって関数の中では要素の値の参照しかなされない配列であっても、仮引数はポインタ型の変数になります。  C++言語では値渡しに加えて参照渡しが追加されました。これは、仮引数の変数のための記憶場所を関数内に確保するのではなく、実引数の記憶場所を仮引数で宣言した名前で参照するという機能です。これにより実引数から仮引数への値のコピーは不要になるので、構造体オブジェクトを渡すときなどに使われています。  #4の回答で、参照渡しと「ポインター渡し」を対照していますが、そもそも「ポインター渡し」などという用語はありません。ポインタ型の参照変数を使うことはできます。 > 参照渡しでは、NULLポインターを渡せません。 と書かれていますが、これは誤っています。#4の回答の中で示された例には #include <iostream> #include <cstring> void testNULL( char *const &s ) { if ( s==0 ) std::cout << "NULL pointer\n"; else if ( std::strlen(s) == 0 ) std::cout << "Zero length\n"; else std::cout << s << "\n"; } int main(void) { testNULL(NULL); testNULL(""); testNULL("OK!"); } で反証できます。(もっとも、この例では仮引数を参照変数にする必要はありません。)  また、配列全体を値渡ししたいときは、配列をメンバーとする構造体を作ってそれを引数にすることで実現できます。構造体オブジェクトを引数にすると、メンバーが配列であっても、すべてのメンバーの記憶場所の値が実引数から仮引数にコピーされます。仮引数の構造体メンバーになっている配列の要素の値を変更しても実引数のメンバーの記憶場所が書き換えられることはありません。  #6の回答で示された > たとえばstrcpy()やstrcat()、strcmp()、memcpy()などと同等の動作をする関数を作ってみましょう。 > # もちろんポインタは使用禁止で。 も、配列をメンバーとする構造体を作り、関数のパラメータだけでなく戻り値の型もその構造体にして、関数を引用するプログラム内の代入式で構造体オブジェクトを更新するという手法を使えば、さほどの労力を費やさなくても実現できます。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.6

では……関数の引数でポインタを使わないように設計&実装してみればよいかと。 文字列を渡すことはできなくなりますが、そんなのはグローバル変数を多用すれば無問題です。 作った関数のウチ1つを別プロジェクトでも使いたい。 というときにそのグローバル変数も用意する必要がありますし、他で使ってるグローバル変数と名前が衝突するかもしれませんが、 文字列を渡すのにポインタを使うよりソースコード中の変数名を修正すればいいのですから無問題です。 もれなく、食い違いなく変更する必要がありますがそんなミスはアリエナイでしょう。 たとえばstrcpy()やstrcat()、strcmp()、memcpy()などと同等の動作をする関数を作ってみましょう。 # もちろんポインタは使用禁止で。 『意地でも引数にポインタを使用しない。』 というのを徹底できるか試してみましょう。 メンバ変数が大量にある構造体を引数で渡してみたりとか。 ポインタなら数バイトのローカル変数領域の消費。構造体自体を渡すとなったら構造体サイズ分のローカル変数領域の消費とコピーが必要になります。 が、ポインタなんていう意味不明なもののやりとりよりは健全で理解しやすいでしょう? # 効率?メモリ容量? # 今時のパソコンなんて速いしメモリもたっぷりなんですからそんなの考えるのは無駄無駄無駄ァ!! ま、そんなプログラミングだと組み込み系とかじゃやってられないでしょうけどね。

  • wormhole
  • ベストアンサー率28% (1621/5656)
回答No.5

「レジスタ」とかの話が出てるのは真に受けないように。 引数の値がレジスタ渡しかどうかは処理系によりますし引数にポインタを使うのとは全くの無関係の話です。

回答No.4

C・C++についての質問なのでポインター渡しと値渡しの違いについて聞いているのか、C++での参照渡しとポインター渡しの使い分けについて聞いているのか、どっちなのか今ひとつわかりませんでした。 ポインター渡しと値渡しの違いについては既に先に回答がある通りです。おおまかに言って次の2つでしょう。 1. 容量が大きい物を手早く渡したい 2. ポインター型のものを渡したい 1について、 構造体を関数の引数とする場合、構造体のなか見すべてをコピーするので例えば1024バイトの構造体を値渡しすると、1024バイトの値をそこでコピーします。関数の呼び出しごとにコピーが起きて、無駄にCPUを消費します。 既に他の方が書いているとおり、これがポインター渡しならアドレスを表すのに十分な容量 (sizeof(void*)の大きさ)をコピーするだけです。多くの場合はこちらのほうが容量が少ないのではないでしょうか。 また、関数の引数が大量にある場合や関数の引数が後で増える可能性がある場合、関数の引数に全てをだらだら書くのではなく、一旦構造体に入れて渡すということもされます。 2について、 C言語やC++で配列というのは事実上、配列の先頭番地へのポインター変数です。よって、配列を渡す場合は必然的にポインター渡しとなります。 C++での参照渡しとポインター渡しの使い分けについては、次の2つでは無いでしょうか。 a. NULLポインターを使いたい場合 b. C言語と共用する関数である場合 aについて、 参照渡しでは、NULLポインターを渡せません。例えば、空文字列と無効値を区別したい場合、""とNULLとするのが簡単だと思いますが、これを参照渡しで渡すことはできません。 この場合、NULLポインターを渡せるようにするためにポインター渡しにする必要があるでしょう。 bについて C言語には参照渡しという概念がありません。C言語と共用する関数のインタフェースやC言語から呼び出す窓口となる関数には参照渡しではなく、ポインター渡しを使う必要があるでしょう。 1、2、a、b いずれの場合でも、インプット引数が関数内で破壊されないことを保証するために、可能ならばconst修飾子をつけたほうがよいでしょうね。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.3

引数の受け渡しはレジスタで行われます。 レジスタに収まらないものはポインタで渡すしか無いわけです。 アウトプットもレジスタを書き換えたとしても、復帰した時にレジスタが元に戻されるので、呼び出し側に引き渡すことが不可能なため、メモリ上に書き込む必要があるわけです。 実際にはちと違うけど、説明の都合上単純化ということで。 今は64bitが主流なので、文字列も8文字も入るわけですが、8文字までの文字列ならレジスタで渡せるか、という訳にはいきません。 文法がややこしくなるというか、マシン依存、OS依存が激しくなるので統一という意味でも、文字数や配列数での例外が無いわけです。 プログラムで属性を変えて受け渡しは出来ますが、この場合もアプリがマシン依存、OS依存が発生し好ましくありません。 コードが長くなるのも面白くありません。 因みに、私が作ったWindows95のゲームがWindows7 64bitでもバイナリのままで動いていますよ。 依存性の乏しいコードにすると寿命が長くなります。

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

「文字列」や配列は、ポインタで渡すしかありません。

回答No.1

引き渡したいモノがどんなに大きくても、そのポインタなら数バイト。

関連するQ&A

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

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

  • ポインタのポインタが引数にある関数の使い方。

    ポインタのポインタが引数にある関数の使い方。 現在、このポインタのポインタが引数にある関数の動きがわからず困っています。 int test(int ** head) { int * pTail = (int *)*head; pTail = pTail + 1; } もし、この関数を呼び出して使用した場合どのような動きをするのでしょうか? int * comm_msg; これをグローバルポインタ変数として宣言させて、 test((void **)&comm_msg); このように呼び出したとした場合とさせていただきます。

  • 関数の引数でポインタのポインタを渡したいのですが・・・

    関数の引数でポインタのポインタを渡したいのですが、 渡す前後でアドレスが壊れてしまっています。 もし、なにか思い当たることがある人がいましたら、 必要事項があれば補足します。 よろしくお願いします。

  • ポインタを引数で使用する場合

    初心者です。 ローカル関数でポインタを引数で使用する場合の定義で int A (int *x,int *y) とする場合の*はポインタの宣言としての*なのでしょうか? これまでの例題ではメイン関数のなかでポインタを宣言しアドレスを代入し・・・という使い方だったのですがローカル関数で引数を使用するさいはメイン関数内ではポインタの宣言はないので関数の定義と同時にint *x とint *yを宣言するという事なのでしょうか? それ以降の*は間接参照演算子ですね。

  • ポインタのポインタを引数にもった関数から値を得たい

    すいません。 似たような題も多かったのですが、初心者のため、わかりませんでした。 質問させてください。  ポインタのポインタを引数にもった関数を作りたいのですが、まったくわかりません。 (ポインタであれば、何とかできたのですが…) 例を作ってみました。下記で、dd[2][2]にtest2関数から値を得るとします。 ?1と?2、?3に何を入れたらよいでしょうか?  (?1で得られる値は何でもかまいません。) きわめて抽象的で、申し訳ないのですが、どうぞよろしくお願い致します。 void test2(double **d1) { ?1 } void C_testDlg::OnBnClickedButton1() { // TODO: ここにコントロール通知ハンドラ コードを追加します。 double dd[2][2]; ?2 test2(?3); CString cs; cs.format("%g", dd[1][2]) ::AfxmessageBox(cs); }

  • ポインタを使うことのメリットとは??

     こんばんは、Cの初心者です宜しくお願いします。  Cでポインタの記述を良く見るのですが、色々と本とかサイトとかで調べましたが、ポインタを使うことのメリットとか、使う理由を書いてるものに巡り合いません。  一体何故ポインタというものがあるのでしょうか。  変数(アドレス)を参照する事で、メモリの節約とか動作が速くなるとか、そのようなものが主な理由でしょうか。  逆にポインタを使わないと書けないプログラムとかはあるのでしょうか。  関数は、ポインタを引き数として元から設計されているので仕方がないとしても、、、、、、  以上初心者としての非常に素朴な疑問です、宜しくお願いします。

  • ポインタを利用する理由とは?

    C言語には「ポインタ」というものが出てきますよね。 テキストで「ポインタ」の章をずらすら~と読んでいるうちになんでこんなめんどい事しなきゃならないのかなぁと思ってきて疑問に思ってきました。 関数で引数として「アクセス番号」にしなくても、直接「値」を渡せばいいと思うのですが。 ポインタの利用する理由と、その利用法をおしえてください。

  • 関数の引数と戻り値

    度々すいません。 関数に引数として配列のポインタを渡して、戻り値として配列のポインタを返したいのですが、やり方がよく分かりません。 お願いします。

  • コマンドライン引数 *argv[]はなぜポインタ?

    C言語初心者です。 コマンドライン引数、 int main(int argc, char *argv[]) というのを最近勉強しましたが、引数2番目がポインタになっている理由について、 どなたか教えて下さい。 そういう仕様なんだから、それに従いましょう、ということでしょうか? int main(int argc, char argv[]) では、ダメなのでしょうか? このポインタでの引数渡しについて、 なんらかの納得のいく考え方をご存知の方がいらしたら、教えて下さい。 宜しくお願い致します。

  • 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()); のようなやり方がしたいのですが。

専門家に質問してみよう