• ベストアンサー

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

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

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

  • ベストアンサー
回答No.3

お疲れ様です。 >>関数は、ポインタを引き数として元から設計されているので仕方がないとしても、、、、、、 意味が分かりません。 私が今まで勉強して来た観点から見て以下を挙げます。 まず、C言語で挙げれる利点として (1)文字列操作の簡素化 (2)自己参照構造体とメモリ動的確保による可変長データの操作 (3)標準的な関数として用意されているqsort等へ渡す関数へのポインタ (4)構造体などの大きなデータを別関数へ渡す際のスタック領域節約かつ高速化 そして、C++で挙げれる利点として (1)継承クラスのインスタンスのポインタを親クラスのポインタへ格納する事によるポリモーフィズムの実現 他にもあるかもしれませんが、私は上記しか知りません。

eiji_0035
質問者

お礼

>>関数は、ポインタを引き数として元から設計されているので仕方がないとしても、、、、、、 意味が分かりません。 #関数の引数がポインタ型をしていされていということですが。  多分そんな関数があったような。

その他の回答 (9)

  • train45
  • ベストアンサー率0% (0/1)
回答No.10

1.処理の高速化。 関数に引数を渡す時はコピーが必要です。例えば10Mbyteものデータをコピーするのはとても時間がかかります。構造体を引数にすることを考えてください。構造体のデータを渡すのには時間がかかりますが、ポインタを使えばアドレスだけを渡すので時間が少なくてすみます。 2.デバイスドライバを書く時に必須となる。 デバイスドライバ等では、決められたアドレス(ハードウェア等の設計に依存)にアクセスしてプログラムを実装する必要があります。このようなプログラムを書く場合はポインタのようにアドレスを指定してアクセスする機能が必須となります。 その他、プログラム上の都合でポインタは便利と感じることがたくさんあります。ポインタは最初はわかりにくいのはそうなのですが、実際に使っていくことでその便利さが実感できると思います。

eiji_0035
質問者

お礼

皆さん、多数の貴重なご回答有り難うございます、大変勉強になりました。 やはり初心者にとってはポインタはかなりハードルが高いのですが、 皆さんのご意見で励みになりました、もっともっと勉強して苦手意識をかえていきます。 今後とも宜しくお願いします。

回答No.9

>ポインタを使用する理由  C言語のローカル変数はスタック上に作成されます。  で、関数コールを行う際は引数をスタック上において(コピーして)から実行します。    呼ばれた関数は呼ばれる直前にコピーされたものを引数として使用するため、  その値を変更しても呼び出し元にリターンした際は消えてしまうことになります。  これでは返値だけでしか値を返せないことになります。  scanf()等のように、一つの関数で複数の変数に値を返したい場合は  ポインタを使用した値の受け渡しは必須になります。    またeiji_0035さんも質問の中にかかれていますが、引数に大きな構造体を  渡そうとすると、それ全てをスタック上にコピーすることになります。  これもポインタを使用すると アドレス指定に必要なサイズ(4~8バイト程度)で  済むことになり、効率的になります。 >逆にポインタを使わないと書けないプログラムとかはあるのでしょうか。  一つの関数で複数の値を書き換えるには先に述べたようにポインタが  必須です。  逃げ道としてはグローバル変数を使用....なんてこともできますが、  変数引き渡しがうまくできないから....が理由では邪道です。  大規模なプログラムになればなるほどバグを生む原因になります。  あと普通は使用しませんが、関数もポインタに割り当てることができ、  そのポインタを使用して動的に関数を実行したりすることができます。  複数の関数をポインタの配列に定義することで、配列要素で使用する関数を  変更する、なんてこともできます。  「関数ポインタ 配列」で検索するといろいろ出てくるかと思います。

  • oldman50
  • ベストアンサー率29% (8/27)
回答No.8

>一体何故ポインタというものがあるのでしょうか。  Cの前身のBでポインタが使われていたからです。  Cは、アセンブラでUNIXを開発していたケン・トンプソンが、開発労力を減らすために開発したBが遅くて使えなかったため、見かねた同僚のデニス・リッチーが、ケン・トンプソンのために、Bを修正するところからスタートした言語です。  昔はメモリが物凄く高価であり、かつCPUも遅かったため、如何に少ないメモリで高速にプログラムを動作させるかが課題であった訳です。 http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.7

>データー構造をリスト型にする(あるいはツリー構造にする)とかは、 >そもそも、ユーザー(プログラマ)が指定できるものでしょうか。 ある問題をプログラムで解決するとき、 どのようなデータ構造(やアルゴリズム)を用いるか、 事前に吟味する必要があります。 配列を使えば解決できるのか、他のデータ構造でないとダメなのか、 といった具合です。 吟味の結果、例えばリスト構造が最適であると判断したとき、 その構造を「自分で」考えます。 だれかがいつの間にか作ってくれているわけではありません。 >(プログラムの書き方でそのようなデーター構造ができる?) 発想が逆です。 適切なデータ構造(とアルゴリズム)をもとに、プログラムを書きます。

eiji_0035
質問者

お礼

 asuncionさん、回答有り難うございます。  >適切なデータ構造(とアルゴリズム)をもとに、プログラムを書きます。  #具体的に例えばこのようなデータ構造にしたい場合には、このようにプログラムをかくとか紹介しているサイトとかはあるのでしょうか。  探したんですが、データ構造の解説をしているサイトは山ほどあるのですが、このようにして、プログラムを書くとうサイトが見つからないのですが。

  • buriburi3
  • ベストアンサー率44% (353/792)
回答No.6

アセンブラの間接参照 MOV [IX],A とかの実装だと思います。 C言語は高級言語ではなく超高級マクロ・アセンブラだと思ったほうが理解が簡単です。

回答No.5

概念的で、申し訳ないです・・・。 > 変数(アドレス)を参照する事で、メモリの節約とか動作が速くなるとか、 > そのようなものが主な理由でしょうか。 おっしゃるとおり、効率的なプログラムが一番の理由だと思いますよ。 Cで書かれたソースはコンパイルを経てアセンブラに近い形に変化していきます。アセンブラ・コードのほとんどが、メモリから読み出し、計算や加工を施し、メモリに格納します。この時、メモリサイズやアドレスやらを考慮した書き方をすると、高速かつ効率的なアセンブラ・コードを吐き出してくれます。そのメモリサイズやアドレスやらを表現するのに必要な機構がポインタとなります。C言語が可読性が高い、低級レベルの言語と言われるゆえんでは無いかと、僕は考えます。 組み込み型の機器に搭載するプログラムもCで書かれる時代ですが、高効率なコードを生成しなければならない場合、可読性を犠牲にしてでも、ポインタを使ったトリッキーなコードをよく見てきました。 あるメモリ領域を0埋めしていくコードを考えてみたとき、下記のようなプログラムが書けそうです。func1はポインタを使っていません。func2はポインタを使っています。 ---------- ここから ---------- static int buf[256]; void func1(void) {   int i;   for( i=0 ; i<256 ; i++ ) buf[i] = 0; } void func2(void) {   int *p;   p = buf;   for( i=0 ; i<256 ; i++ ) *p++ = 0; } ---------- ここまで ---------- 最近のコンパイラは非常に優秀ですし、CPU自体の性能が高く、高効率のアセンブラ・コードをはいてきます。しかしながら、おそらくfunc2の方がコードの長さ、コードの実行スピード共に優れていると思われます。 ここから先はアセンブラコードやCPUの知識が必要になります。buf[i]=0というのは、bufが指すアドレスを示す箱(レジスタと呼びます)の値に、その位置を示すiの値を入れる箱の値を毎回足して、0を保管すべきアドレスを計算します。このアドレスに0を保管します。これに対し、*p++=0は、アドレスを入れる箱(レジスタと呼びます)にます、その先頭アドレスを入れておきます。その指し示すアドレスに0を格納して、アドレスを定数分増加させます。似ている様に感じますが、多くのCPUやコンパイラで*p++=0が楽に処理できるでしょう。 C言語のもっとも特筆すべき特徴がポインタであると考えています。ポインタを使う事で可読性が悪くなったり、逆にまどろっこしくなったりする事もありますから、好みに合わせて使えればいいと思います。

  • ymmasayan
  • ベストアンサー率30% (2593/8599)
回答No.4

最も大きなメリットは高級言語でありながらアドレスが扱えることですね。 アセンブラではアドレスが扱えて当然なのですが。 具体的な例としてはA,B,Cという別々の構造体とポインタPに関連付けられたXという構造体を ダイナミックに重ねて一律にXという構造体としてで扱えるということです。 つまり、A,B,Cのいずれかの先頭アドレスをPに代入すればそれぞれのエリアがその時々で Xというひとつの構造体で扱えるということです。 リスト構造が書きやすいというのもそれが理由です。 あとC言語ではポインターの演算ができますので実行時間の短いプログラムが書けます。 余談ですが、 1.C言語はOSのUNIXを書くために作られたのでアドレスやアドレス計算はできて当たり前なのです。 2.ポインターは難しいのでC言語の習得に苦労します。   元々CはOSを書くようなプロが使う言語でしたから。   エラーチェックやエラーメッセージが極端に不親切なのもそれが関係しています。   ちなみにCから派生したJAVAにはポインターが有りません。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.2

ポインタなしには実装できないデータ構造があります。 リスト構造などです。

eiji_0035
質問者

お礼

>リスト構造などです。 #リスト構造については、参考書で読んだことがありますが、データー構造をリスト型にする(あるいはツリー構造にする)とかは、 そもそも、ユーザー(プログラマ)が指定できるものでしょうか。 (プログラムの書き方でそのようなデーター構造ができる?)

  • yamaj_biz
  • ベストアンサー率71% (10/14)
回答No.1

色々メリットはあると思いますが…。 まずプログラムを組んでいて初めに出てきそうなのが「参照渡し」ではないでしょうか。 複数の値を関数から受け取りたい場合どうするかとなると、手っ取り早く変数の参照渡しをして値を受け取る事になると思います。 あとは…勉強としてポインタの概念を理解すると、コンピュータの基礎を理解できる…かもしれません。 上記は一例で色々あると思いますが、あとは他の方におまかせします。

関連するQ&A

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

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

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

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

  • int型のポインタ

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

  • 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 test(int ** head) { int * pTail = (int *)*head; pTail = pTail + 1; } もし、この関数を呼び出して使用した場合どのような動きをするのでしょうか? int * comm_msg; これをグローバルポインタ変数として宣言させて、 test((void **)&comm_msg); このように呼び出したとした場合とさせていただきます。

  • 引数のポインタについて

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

  • 参照型で受け取った引数をポインター型に渡す方法

    参照型で受け取った引数をポインター型に渡す場合は、 どのようにすればよいのでしょうか? 私は参照型の理解がすっぽりぬけています。 参照型はC++で導入された方法で、何がメリットで何がデメリットでしょうか? void pointer_test(AA *b) { ... } void test(AA &a) { pointer_test( ??? ); }

  • C言語のポインタの利点がわかりません

    C言語を始めたばかりですが、 ポインタで間接参照するメリットが今一つわかりません。。。 特に、関数ポインタを使う場合には、 単なる関数ではだめなのでしょうか。 どなたか、かみ砕いて教えていただけないでしょうか。

  • 多次元配列のポインタ渡し

    C++を使用しています。 多次元配列を関数の引数として渡したいとき、関数側では void A::Func(int a[10][20][30])~ 呼びだし側では Finc(a); とやればいいのはわかります。 お聞きしたいのは、仮引数として呼び出された配列(上でいうa)をクラスのメンバ変数として保持したい場合の方法です。 aは先頭アドレスなのでそこを差すポインタを受ければいい、っていうことはわかりますが、 この方法ですと、受けたメンバ変数が配列みたいに[]を使ってアクセスできません。 (メンバ変数のポインタは配列じゃないから当然ですよね) これを通常の配列みたいに扱えるようにするにはどうしたらいいでしょうか。

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

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

専門家に質問してみよう