ポインタのメリット・デメリットとは?なぜポインタを使うのか?

このQ&Aのポイント
  • ポインタのメリットは、メモリを多く確保しなければならないオブジェクトについて、省メモリでインタフェースできることです。
  • ポインタのデメリットは、アクセス可能な場所が多くなり、値が変更されやすくなること、可読性が低くなることです。
  • なぜならば、熟練のC言語プログラマが昔ながらの記述を踏襲しているため、ポインタを使うことが多いからです。
回答を見る
  • ベストアンサー

【なぜポインタを使うのか】

私は、ポインタのメリット・デメリットを以下のように考えています。 ◆メリット メモリを多く確保しなければならないオブジェクトについて、コピー処理を行うことなく省メモリでインタフェースできる。 ◆デメリット ・関数内でしか使用しない非ポインタのローカル変数に比べ、  アクセス可能な場所が多くなってしまい、色んな箇所から値が変更されうる。(影響範囲の限定がしずらい) ・可読性が低くなる。(若いエンジニアはCの経験者は少なくっていくと思われるため、保守コストが若干割高になる) そのため、よっぽどメモリを多く使うようなオブジェクトでなければ、 (もしくは速度を重視する必要があるプログラムでなければ) 値渡しにしても良いのではと考えています。 しかし、度々目にするソースは、何でもかんでもポインタで処理しているものも多々見受けられます。 特に、int型のようなメモリを大量に使用しないものでも、ポインタで変数宣言しているケースもよく見ます。 なぜなのでしょうか? (熟練のC言語プログラマが、昔ながらの記述を踏襲しているというのはあるのかなと考えていますが)

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

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

> 今の時代で、なぜメモリに介入するようなレベルから部品を作るのか? > それは企業から見て、投資対効果は得られているのか? なら「Cを使わない」という選択肢もあります。 おっしゃる通り、昨今のPC事情を考えれば、ポインタのような低次元な操作をしなくても、十分に実用的な速度で動作します。 ですから、必要が無いなら、C言語ではなく、もっと「高級」な言語を使えばいいのです。 しかし、Cが有効な場面はあります。 ・効率をもっと上げたい ・ハードウェアを直接操作したい そういうときには、やはり、ポインタを使わざるをえない場面が出てきます。 あと。 ポインタが無い言語でも、内部ではポインタ的なものが使われています。 例えば、Javaのオブジェクトは、オブジェクトの場所を表わす参照値が使われています。 メソッド呼び出しでは、参照値が渡されます。 これは、直接操作はできないものの、「ポインタ」そのものです。

souken_200
質問者

お礼

ありがとうございます。 処理スピードを追及したり、ハードウェアを直接操作したいときに使うというご回答、すごくしっくりきました。 ありがとうございます!

その他の回答 (13)

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.3

>特に、int型のようなメモリを大量に使用しないものでも、ポインタで変数宣言しているケースもよく見ます。 あなたの「よく見かける」というのは 関数内の変数でint型1個分のために int *a = malloc(sizeof(int)); のようなポインタを使ってるのをよく見かけるということでしょうか? 私はintオブジェクトを簡易的にあらわすのに使うときもありますが、そういうケース以外でただ1個分のint型を使うのにわざわざポインタで扱うのを私は見たことありませんけど。 もしかして変数といってるのは仮引数のことで void foo(int *a); のようなものを、よく見かけるだったりしませんか?

souken_200
質問者

お礼

No.9での回答、とても参考になりました。 ありがとうございます!

souken_200
質問者

補足

int *a = malloc(sizeof(int)); のケースも見ます。 ただこれに関しても、理由はあまりわかっていません。 intは、32767 ~ -32768 と決まっているのだから、サイズの確保のため、なぜわざわざmallocで書くのでしょうか? 宜しくお願いいたします。

回答No.2

たとえばこんなの↓、ポインタなくては書けません。 #include <stdio.h> /*  *nに1を加える関数  */ void increment(int* n) { ++(*n); } int main() { int n = 123; increment(&n); printf("%d\n", n); return 0; }

souken_200
質問者

お礼

とりあえず、私が参画するようなプロジェクトは、 期間内・予算内で、企業の利益につながるシステムを作ることが目的であるため、 インクリメント等は、別に1行でなくてもよかったり、 多少、使用メモリが多くても、まったく問題ないため、 このケースに関してはですが、ポインタにこだわる必要はないさそうです。 しかし、ポインタを使うと、色々簡潔にかけたりするのでしょうね。 ありがとうございます。

souken_200
質問者

補足

※まだ勉強中の身なので、自信はないのですが、 void increment(int &n) { n = n + 1; } int main() { int n = 123; increment(n); printf("%d\n", n); return 0; } でも可能ですか? また、ポインタで書く場合と、参照で書く場合で、どのようなメリット・デメリットの差があるのでしょうか?

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

ここで述べられているのは、関数の引数としてポインタを使う場合のことですね? > ・関数内でしか使用しない非ポインタのローカル変数に比べ、 >  アクセス可能な場所が多くなってしまい、色んな箇所から値が変更されうる。(影響範囲の限定がしずらい) > ・可読性が低くなる。(若いエンジニアはCの経験者は少なくっていくと思われるため、保守コストが若干割高になる) 関数にポインタを渡しても、アクセス可能な場所は限られます。 funcA(&x) としたら、xにアクセスできるのは funcAと、funcAの中で呼ばれる関数だけです。無関係な関数まで気にする必要はありません。 funcAの中でfuncBに渡され...となるとわからなくなる、というのなら、まずは、関数の仕様だけに注目することです。 funcBの実装はとりあえず置いといて、期待通りに動作したら、ポインタとその実体がどう変化するか、それだけを考えて funcAを作成.確認します。 *x += 3 ; とあったら、 実際にどんなアセンブリコードになっているか、なんて考えないですよね?それと同様に funcB(x) とあったら、funcBの中身を考えずに、funcBの動作だけを考えます。 また、Cとポインタだけで発生することではなく、他の言語でも同じことが起きます。 例えば、Javaのオブジェクトは、メソッドの引数で渡すときには、「参照値」というポインタのような値が使われます。 JavaでmethodA(Object objA) の中で methodB(objA)を実行している のと Cで funcA(int * p) の中で funcB(p) を実行している のとで、参照値/ポインタの扱いはまったく一緒です。 他にも ・Cには、いわゆる「参照渡し」がありません。ポインタ(の値)渡しで代用します。 ・Cでは、配列とポインタは密接に関係しています。 例えば、void func(int * a) ; と void func(int a[]) ; は等価です。

souken_200
質問者

お礼

こちらの回答も、ありがとうございます。

souken_200
質問者

補足

回答ありがとうございます。 >関数にポインタを渡しても、アクセス可能な場所は限られます。 >funcA(&x) としたら、xにアクセスできるのは funcAと、funcAの中で呼ばれる関数だけです。 funcAの中で呼ばれる関数に、そのまま&xを渡したら、内部の関数の、さらのその内部の関数内でポインタ渡しになっていたとき、アクセスは不可能という解釈で良いでしょうか?

関連するQ&A

  • int型のポインタ

    int型のようなメモリを大量に使用しないものでも、ポインタで変数宣言しているのをよく見かけますが、 なぜでしょうか? 私はCに慣れていないため、int型くらいのサイズだったら、なるべくならポインタを使わないで書いてもらった方が可読性が良いので、ポインタにするメリットがあまり感じられません。

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

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

  • 関数で値渡しと参照渡しではどっちがメモリを使うのか

    クラスAの大きなサイズのオブジェクトを、 クラスBで処理するメソッドを書こうとしています。 ◆質問 このとき、クラスBでは、byval で記載するのと、byrefで記載するのでは、 どちらの方がメモリを食わないのでしょうか? ◆自分の想定 (1)byrefで記載した場合、そのオブジェクトのポインタを受け取って処理するため、あんまりメモリは食わない。 (2)byvalで記載した場合、ある意味、.clone のような処理がされて、渡されたオブジェクトと同じサイズのメモリを食う? ※処理しようとしていることは、特に参照渡しされた変数の値を修正するような類ではないです。 なので、「オブジェクトを不用意にいじってしまう危険性」などの観点は無視し、メモリの観点の話です。 ちなみに、メソッドを、shareで宣言しようが、インスタンス化してからじゃないと使えないように宣言しようが、その関数のために使用されるメモリのサイズ(※クラスBのインスタンス化のためのメモリではないという意味)は変わらないということで合っていますでしょうか? .

  • 【C++】メンバ変数をポインタで宣言するデメリット

    クラスAが、メンバーとして、 クラスXと、クラスYを持っているとします。 そのようなとき、 【ケース1】  クラスAを定義する際、  メンバである、クラスX、クラスYは、ポインタで宣言させる。 【ケース2】  クラスAを定義する際、  メンバである、クラスX、クラスYは、ポインタではなく、クラスX/クラスYの型として宣言させる。 があると思いますが、それぞれどのようなデメリットがあるでしょうか? ----------------------------- 私は、ケース1は、 メリット:   クラスXを継承したクラスChild_Xや、クラスYを継承したクラスChild_Yを、   クラスAで扱えるようになる。   デメリット:   クラスXのポインタで宣言していると、クラスXを派生したクラスが格納可能であるため、   開発時に、そのメンバーに、実際にはどの型のクラスが格納されているかがわからず、   Visual Studio で追いかけられない。   (※そのメンバーに対して、右クリック⇒定義で見ても、どの型のポインタ変数かはわかっても、     どの型がそこに突っ込まれているかは、代入されているところを探して確認しないとわからない。) 私は、処理を確認する際、『どの型の値がそこに突っ込まれているかは、代入されているところを探して確認しないとわからない。』というのが、可読性は悪いわ、確認に時間が取られるわで、 非常に大きなデメリットと考えています。 このデメリットを解消する方法はあるのでしょうか?

  • 関数ポインタの利点

    こんにちは。 C言語初心者ですが今勉強中です。 その中でポインタについては理解できたのですが、 関数ポインタの利点、使うべき所などが理解できません。 ポインタの基本は理解しています。 値渡し、アドレス渡しも理解しています。 関数ポインタを使うと何がいい、またはどんなとき使わなければならないのか 教本を読んでいてもさっぱりわかりません。 サンプルプログラムを打っても何のために使ってるのかわからないです。 どなたか教えていただけませんでしょうか? よろしくお願いします。

  • ポインタに関する質問

    int v; int *p=&v ポインタ変数pに変数vのアドレスを代入して、次からは、pからvの値を操作したいのですが、「*p++」としたところ、変数vの値がインクリメントされずに、pに格納されるアドレスその物がインクリメントされてしまいました 「*p+=1」とする事でvの値をインクリメントすることができましたが、 「*p+=1」このように書かれる処理は望ましい物ではないのでしょうか

  • ポインタに含まれる情報は [C言語]

    ポインタに含まれる情報は代入した変数のアドレスですが、アドレス元の変数の大きさは含まれないのでしょうか?ポインタの中の情報を見てみても、参照できる変数が使用しているメモリの先頭アドレスしか入っていません。変数の大きさはどうやって知るのでしょか?回答よろしくお願いします。

  • ポインタはどんな時に使うものなの?

    僕は最近C++の勉強をしている高校生です。 さっそくですが質問です。最近、ポインタを覚えました。 ポインタはメモリの番地を指定できるから低レベル処理に使えると聞きましたが その他ではいったい何に使えるのか想像がつきません。 具体的にどんな処理に使うのでしょうか? お暇があればご回答ください。

  • ◆コピコンを実装しないと、returnでエラー?

    ポインタを持ったクラスで、 コピーコンストラクタを実装していないと、 newを使用した際にエラーになるそうですが、 なぜなのでしょうか? 値渡しの関数などで、 コピーコンストラクタを実装していないと、 デフォルトコピーコンストラクタで、ポインタ型のメンバ変数の値もコピーするため、 return する前に、 「一時的な変数としてコピーされていた値渡しの引数」が、 関数の終了時に解放され、 「アドレスを指しているポインタ」が指し示す先の領域に「delete」が走ってしまうため、 呼び元の変数で持っているポインタが指し示す先の領域も、 解放されてしまうとかでしょうか?? そもそも、 ポインタ pMem=NULL は、アドレスの指し示す値のリセットで、 Delete pMem は、アドレスが指し示す先頭から、そのクラスで必要としている分のメモリ量進んだアドレスまでを、解放する。 ということで合っているでしょうか? それとも、 「ポインタ」を削除しても、ポインタの指し示す先のアドレス自体は存在していて、 「呼び元」のアドレス格納用領域と、 「関数の呼び出し時にコピーコンストラクタで作られるアドレス格納用領域」は別であり、 ポインタ自体を削除しても、ポインタの先にあるメモリ領域は残っているのでしょうか?

  • PHPの参照渡しについて

    以下のようなコードがあったとき $obj = new stdClass(); $foo = $obj; この場合、動作は いわゆる【参照の値渡し】というとらえかたでよいのでしょうか? 変数$obj には、 new stdClass();という記述によって 新規に作成されたオブジェクトの参照(※正確には別のメモリ内に保持されたオブジェクトのアドレス) が保持されるわけですよね? そのとき $foo = $obj; というコードは$objが保持するオブジェクトのアドレス値を$fooという変数にも コピーするという動作を意味するわけですよね。 この場合、両変数を用いて生成されたオブジェクトのプロパティなどの状態を 共有することとができます。 しかしながら変数$fooに別の値、例えば文字列を代入すうると $foo = "文字列"; とすると$fooの値が変更され$objの値は変更されません。 対して、次のようなコードがあった場合 $foo = &$obj; というコード、これはPHPにおける参照渡しですが、 この場合は$objが指し示す、オブジェクトが保持されているメモリ上のアドレスではなく そのメモリ上に確保された変数$objそのもののアドレスが$fooという変数にコピー? されるのでしょうか? この明示的な参照渡しだと、オブジェクトの状態を共有するのはもちろん $foo = "オブジェクト破棄"; と片方に文字列を代入すると print $obj; 同様に文字列にかわってしまいます。 この本来の意味?であろう参照渡しとは実際 $fooに変数$objそのもののアドレスが保持されるという 解釈でよいのでしょうか? おくわしいかたご教授ください。

    • ベストアンサー
    • PHP