web-dev-qa-db-ja.com

ポインターを使用することで最もよく解決されるプログラミングの問題は何ですか?

ええと、私は基本的にポインタの使い方を理解していますが、より良いプログラミングを行うためにポインタを使用するのが最善ではありません。

ポインタの使用を含む、それらをよりよく理解できるように解決するための良いプロジェクトまたは問題は何ですか?

58
dysoco

メモリ内の大量のデータを操作することは、ポインタが本当に役立つ場所です。

ラージオブジェクトを参照で渡すことは、単純な古い数値を渡すことと同じです。オブジェクトをコピーして変更し、元の場所の代わりにコピーを戻すのではなく、必要な部分を直接操作できます。

68
user7007

ポインターの概念により、データのストレージを複製することなく、アドレスでデータを参照できます。このアプローチにより、次のような効率的なアルゴリズムを作成できます。

  1. ソート
    ソートアルゴリズムでデータを移動する場合、データ自体ではなくポインタを移動できます。100文字の文字列で数百万の行をソートすることを考えてください。不要なデータ移動を大幅に節約できます。

  2. リンクされたリスト
    レコードに関連付けられているデータ全体ではなく、次および/または前のアイテムの場所を保存できます。

  3. パラメータを渡す
    この場合、データ自体ではなく、データのアドレスを渡します。繰り返しになりますが、何百万もの行で実行される名前圧縮アルゴリズムについて考えてみましょう。

この概念は、ポインタが 外部キー のようなリレーショナルデータベースなどのデータ構造に拡張できます。一部の言語では、C#やCOBOLなどのポインターの使用を推奨していません。

例は、次のような多くの場所にあります。

次の投稿は何らかの意味で関連性があるかもしれません:

44
NoChance

他の回答でこれについて言及していないことに驚きます:ポインターを使用すると、要素が他の複数の要素と複雑な方法で関連している可能性がある、非連続かつ非線形のデータ構造を作成できます。

リンクリスト(1つ、2つ、循環的にリンク)、ツリー(赤黒、AVL、トライ、バイナリ、空間分割...)、グラフはすべて、単なる値ではなく参照に関して最も自然に構築できる構造の例です。 。

29
Jon Purdy

簡単な方法の1つは、ポリモーフィズムです。ポリモーフィズムはポインターでのみ機能します。

また、動的メモリ割り当てが必要なときはいつでもポインタを使用します。 Cでは、これは通常、データを配列に格納する必要があるが、コンパイル時のサイズがわからない場合に発生します。次に、mallocを呼び出してメモリとそれにアクセスするポインタを割り当てます。また、あなたがそれを知っているかどうかにかかわらず、配列を使用するときはポインターを使用しています。

for(int i = 0; i < size; i++)
   std::cout << array[i];

と同等です

for(int i = 0; i < size; i++)
   std::cout << *(array + i);

この知識により、配列全体を1行でコピーするなど、本当にクールなことができます。

while( (*array1++ = *array2++) != '\0')

C++では、newを使用してオブジェクトにメモリを割り当て、それをポインターに格納します。これは、コンパイル時ではなく実行時にオブジェクトを作成する必要があるときにいつでも行います(つまり、メソッドが新しいオブジェクトを作成し、それをリストに格納します)。

ポインタをよりよく理解するには:

  1. 従来のc-stringと配列を操作するプロジェクトをいくつか見つけてください。
  2. 継承を使用するいくつかのプロジェクトを見つけます。

  3. ここに私が私の歯を切ったプロジェクトがあります:

ファイルから2つのn x n行列を読み取り、それらに対して基本的なベクトル空間演算を実行して、その結果を画面に出力します。

これを行うには、配列の2つの配列(多次元動的配列)があるため、動的配列を使用し、ポインターで配列を参照する必要があります。そのプロジェクトを完了すると、ポインタの使用方法がかなりわかります。

8
Jonathan Henson

ポインターが重要である理由を正確に理解するには、ヒープ割り当てとスタック割り当ての違いを理解する必要があります。

以下は、スタック割り当ての例です。

_struct Foo {
  int bar, baz
};

void foo(void) {
  struct Foo f;
}
_

スタックに割り当てられたオブジェクトは、現在の関数の実行中にのみ存在します。 fooの呼び出しが範囲外になると、変数fも範囲外になります。

これが問題になる1つのケースは、関数から整数型以外のもの(たとえば、上記の例のFoo構造体)を返す必要がある場合です。

たとえば、次の関数は、いわゆる「未定義の動作」になります。

_struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  struct Foo f;
  return &f;
}
_

関数から_struct Foo *_のようなものを返したい場合、本当に必要なのはヒープ割り当てです。

_struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  return malloc(sizeof(struct Foo));
}
_

関数mallocは、オブジェクトをヒープに割り当て、そのオブジェクトへのポインターを返します。ここで「オブジェクト」という用語は大まかに使用されていることに注意してください。オブジェクト指向プログラミングの意味で、オブジェクトではなく「何か」を意味します。

ヒープに割り当てられたオブジェクトの存続期間は、プログラマーによって制御されます。このオブジェクトのメモリは、プログラマが解放するまで、つまりfree()を呼び出すまで、またはプログラムが終了するまで予約されます。

編集:この質問がC++の質問としてタグ付けされていることに気付かなかった。 C++演算子newおよび_new[]_は、mallocと同じ機能を実行します。演算子deleteおよび_delete[]_はfreeに類似しています。 newdeleteはC++オブジェクトの割り当てと解放にのみ使用する必要がありますが、mallocfreeの使用はC++コードでは完全に合法です。

8
Mike Steinert

Cで重要なプロジェクトを作成すると、ポインタをいつどのように使用するかを理解する必要があります。 C++では、ほとんどの場合、内部でポインターを管理するRAII対応オブジェクトを使用しますが、Cでは、生のポインターがはるかに一般的な役割を果たします。どのようなプロジェクトを実行する必要があるかについては、それは簡単なことではありません。

  • 小さくてシンプルなWebサーバー
  • Unixコマンドラインツール(less、cat、sortなど)
  • 学習のためだけでなく、自分のためにしたい実際のプロジェクト

最後の方をお勧めします。

4
Viktor Dahl

ポインタで解決できるほとんどすべてのプログラミングの問題は、他のより安全なタイプの referencesC++参照 を参照しない)で解決できますが、変数を参照するという一般的なCSの概念他の場所に格納されているデータの値に)。

ポインタ 参照の特定の低レベル実装であるため、メモリアドレスを直接操作できますが、非常に強力ですが、使用するのが少し危険です(たとえば、プログラムの外部のメモリ位置を指す)。

ポインタを直接使用することの利点は、安全性チェックを行う必要がないため、ポインタがわずかに高速になることです。 Javaのような、Cスタイルのポインタを直接実装しない言語は、パフォーマンスにわずかに影響しますが、デバッグが困難な多くのタイプの状況を減らします。

間接参照が必要な理由については、リストはかなり長いですが、基本的に2つの重要なアイデアは次のとおりです。

  1. 大きなオブジェクトの値のコピーは遅く、オブジェクトはRAMに2回保存される可能性があります(潜在的に非常にコストがかかります)が、参照によるコピーは、ほんの数バイトのRAM(アドレス用)たとえば、メモリに〜1000個の大きなオブジェクト(それぞれ約1MBのRAM)があり、ユーザーは現在のオブジェクト(処理対象)を選択できる必要があるとしますユーザーによって)変数selected_objectオブジェクトの1つへの参照は、現在のオブジェクトの値を新しい変数にコピーするよりもはるかに効率的です。
  2. リンクリストやツリーなどの他のオブジェクトを参照する複雑なデータ構造があり、データ構造内の各項目がデータ構造内の他の項目を参照している。データ構造内の他のアイテムを参照することの利点は、新しいアイテムをリストの中央に挿入しただけでメモリ内でリスト内のすべてのアイテムを移動する必要がないことを意味します(一定時間の挿入が可能)。
3
dr jimbob

ピクセルレベルの画像操作は、ほとんどの場合、ポインターを使用すると簡単かつ高速になります。場合によっては、ポインタを使用することのみが可能です。

2
Dave Nay

ポインタは、Cでのデータ構造の実装に不可欠な部分であり、データ構造は、重要なプログラムの重要な部分です。

ポインタが非常に重要である理由を知りたい場合は、リンクリストとは何かを学び、ポインタを使用せずにリストを作成することをお勧めします。私はあなたに不可能な挑戦を設定しませんでした(ヒント:ポインターはメモリ内の場所を参照するために使用されます、配列内のものをどのように参照しますか?)。

1
dan_waterworth

ポインターは、ユーザーを悩ませることなく、表面下の非常に多くのプログラミング言語で使用されています。 C/C++はそれらにアクセスするだけです。

それらをいつ使用するか:データのコピーは非効率的であるため、可能な限り頻繁に。それらを使用しない場合:個別に変更できる2つのコピーが必要な場合。 (基本的に、object_1のコンテンツをメモリ内の別の場所にコピーし、ポインタを返します-今回はobject_2を指します)

1
mmlac

さまざまなStackExchangeサイトを熟読して、このような質問をするのはかなり流行していることがわかりました。批判や反対投票のリスクがあるので、私は正直になります。これは、荒らしや炎上を意味するものではなく、質問を正直に評価することで、助けるという意味です。

そして、その評価は次のとおりです。これは、Cプログラマーに尋ねるのは非常に奇妙な質問です。 「Cのことは知らない」とだけ書かれています。もう少し皮肉に分析すると、この「質問」へのフォローアップのほのめかしがあります。独立した研究のために?」誰かが与えることのできる「答え」は、基礎となる概念とその使用法を理解するための最終的な作業に取って代わるものではありません。

Webに行ってこれを人々に尋ねるよりも、直接Cをよく学ぶほうが建設的だと思います。 Cをよく知っていると、このような質問をする手間を省くことができます。「歯ブラシを使用することによってどの問題を最もよく解決できるか」と質問するようなものになります。

0
asveikau

大きなメモリオブジェクトを操作しているときにポインタは本当に輝きますが、ポインタなしで同じことを行う方法はまだあります。

ポインタは、いわゆる動的プログラミングに不可欠です。プログラムを実行する前に必要なメモリ量がわからない場合です。動的プログラミングでは、実行時にメモリチャンクを要求し、そこに独自のデータを配置できます。そのため、これらのデータチャンクを操作するには、ポインターまたは参照(ここでは違いは重要ではありません)が必要です。

実行時に特定のメモリを要求し、データを新しく取得したメモリに配置できる限り、次のことができます。

  1. 自己拡張データ構造を持つことができます。これらは、容量が不足している限り、追加のメモリを要求することで拡張できる構造です。すべての自己拡張型構造の重要な特性は、小さなメモリブロック(構造に応じてノード、リストアイテムなどと呼ばれます)で構成され、すべてのブロックに他のブロックへの参照が含まれていることです。この「リンクされた」構造は、グラフ、ツリー、リストなどの最新のデータ型の大部分を構築します。

  2. OOP(オブジェクト指向プログラミング)パラダイムを使用してプログラミングできます。OOP全体は、直接変数ではなく、クラスインスタンス(オブジェクトと呼ばれる)への参照に基づいています)とそれらの操作ポインターなしでは単一のインスタンスは存在できません(たとえポインターなしでも静的のみのクラスを使用することは可能ですが、それはむしろ例外です)。

0

おかしい、私はC++についての質問に答え、ポインタについて話しました。

ショートバージョンは、1)使用しているライブラリが強制的に使用する場合を除いて、ポインタが必要になることはありません。2)null可能な参照が必要です。

配列、リスト、文字列などが必要な場合は、それをスタックに置いて、stlオブジェクトを使用します。 stlオブジェクトを返すか渡すのは高速です(チェックされていない事実)。オブジェクトの代わりにポインターをコピーする内部コードがあり、書き込む場合にのみデータをコピーするためです。これは通常のC++であり、新しいC++ 11でもないため、ライブラリの作成が容易になります。

あなたの質問はこの部分で答えられるかもしれません

ポインターを使用する場合は、これらの2つの条件のいずれかにあることを確認してください。 1)null可能である可能性のある入力を渡しています。例はオプションのファイル名です。 2)所有権を譲渡したい場合。ポインターを渡すか返す場合と同様に、ポインターのコピーは残っておらず、渡したポインターを使用しません。

_ptr=blah; func(ptr); //never use ptr again for here on out.
_

しかし、私は非常に長い間ポインターまたはスマートポインターを使用しておらず、アプリケーションのプロファイルを作成しました。それは非常に高速で実行されます。

追記:私は自分の構造体を書き、それを渡していることに気づきました。では、ポインタを使用せずにこれを行うにはどうすればよいですか?これはSTLコンテナではないため、参照渡しは遅くなります。私は常にデータリスト/デック/マップなどをロードします。何らかのリスト/マップでない限り、オブジェクトを返すことを覚えていません。文字列すらありません。私は単一のオブジェクトのコードを見て、私はこのような{ MyStruct v; func(v, someinput); ... } void func(MyStruct&v, const D&someinput) { fillV; }をしていることに気づきました。

今あなたがあなたが自分の両端キューやマップなどを書いているなら、ポインタを使う必要があります。しかし、その必要はありません。 STLに任せて、おそらくその心配を後押ししましょう。データとソリューションを作成するだけです。それらを保持するコンテナではありません;)

私はあなたが今ポインタを使用しないことを望みます:D。あなたに強制するライブラリを扱う幸運

0
user2528

私は人差し指としてポインターを見て、私たちはいくつかのことをするために使用します:

  1. どこにあるかなど、持ち運べないものを誰かに尋ねられた場合、私はこの通りを「指し示す」ことになります。これは、参照による議論の場合に行うことです。
  2. 何かを数えたりトラバースしたりするときは、同じ指を使います。それが配列で行うことです。

この悪い答えを許してください

0
A.Rashad

あなたの質問にはC++のタグが付いているので、その言語の質問に答えます。

C++では、ポインターと参照に違いがあるため、特定の動作を容易にするためにポインター(またはスマートポインター)が必要なシナリオは2つあります。これらは他の状況でも使用できますが、「どのように使用するのが最善」かを質問します。他のすべての状況では、より良い代替手段があります。

1.ポリモーフィズム

基本クラスポインターを使用すると、ポインターが指すオブジェクトの種類に依存する仮想メソッドを呼び出すことができます。

2.永続オブジェクトを作成する

オブジェクトを動的に(スタックではなくヒープ上に)作成する場合、ポインターが必要です。これは、オブジェクトの有効期間を、それが作成されたスコープよりも長くしたい場合に必要です。

「良いプロジェクトまたは解決すべき問題」に関しては、他の人がすでにここで述べているように、重要なプロジェクトはすべてポインタを利用します。

0
dangerousdave

ポインタは、メモリマップされたデバイスでの作業に非常に役立ちます。制御レジスタを反映する(たとえば)構造を定義し、それをメモリ内の実際の制御レジスタのアドレスに割り当てて、直接操作することができます。 MMUによってシステムのメモリ空間にマップされている場合は、カードまたはチップ上の転送バッファを直接指すこともできます。

0
TMN

実際の例として、指値注文帳を作成します。

たとえば、ITCH 4.1フィードには、「交換」注文という概念があり、価格(したがって優先度)が変更される可能性があります。注文を取り出して別の場所に移動できるようにしたい。ポインター付きの両端キューを実装すると、操作が非常に簡単になります。

0
Foo Bah