[]演算子の代わりにポインター演算を介して配列要素にアクセスすることは悪いことですか?


12

私はCでプログラミングすることを学び始めたばかりで、ポインターと配列の理解を深めるために、ポインターをまったく作成せずに配列の要素を参照しようとしました:

for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}

コード全体がコンパイルされ、問題なく実行されます。

大きなソースコード内のすべての単一配列に対してポインターを作成する必要があることは、非常に非効率的であると思われます。

したがって、ポインタを使用して配列のアドレスを保存および取得するのではなく、上記のように、配列のアドレスを直接使用するのは悪いプログラミング習慣ですか?


使用printf "[%d][%d] = %d\n", k1, k2, array[k1] [k2]));すると、ポインタの算術演算が回避され、理解しやすくなります。
キャスパーヴァンデンバーグ

1
ハハ、あなたは私を得た。これは、ポインターと配列がどのように機能するかをよりよく理解するための実験としてのみ行ったものです。
ニコギャム

ポインター演算は、実際には配列インデックスを使用するよりも約30%高速です。
アンディ

回答:


16

読みにくい程度にのみ「悪い」。a[x]はと同じものな*(a+x)ので、効率や動作に違いはありません(実際にx[a]は機能します)。それa[x]は通常、私たち人間にとってより直感的です。

しかし、それは読みやすさが大したことではないということではありません。これらの2つの式をコードで見た場合にどのように「読む」かを考えてみましょう。

  • *(a+x)=「ポインタaと整数の合計が指すものx
  • a[x]=「x配列のth番目のメンバーa

同様に、配列要素のアドレスを参照する必要がある場合:

  • (a+x)=「ポインターaと整数の合計x
  • &a[x]=「x配列のth番目のメンバーのアドレスa

ほとんどの[]場合、いくつかの異なる配列(特に配列の配列)で動作する重要なコードを見ると、バージョンがわかりやすくなります。[]そもそも演算子が存在する理由です。

PS学習課題としてこの種のことを厳密に行うことは非常に良い考えです。配列は実際には単なるポインタとオフセットであることを理解することが重要です。


この。ありがとうございました。私が本当に知りたいのは、配列要素のアドレスを参照する必要があるかどうか、そして別の要素のアドレスを参照する必要があるかどうかですポインタを使用せず、代わりに、私がやったように直接配列を使用しますか?私のこの質問を特定するのは本当に難しいです。だからこそ、OPでそれを入力しなかったのです。とにかく、私はそれを尋ねなかったので、あなたの答えは満足です。
ニコガンブ

1
@NikoGambtいつでも別の質問をすることができます=)
Ixrec

1
範囲だけでどういう意味ですか...?プログラミング言語の全体的なポイントは、人間がコードを読みやすくすることです。それを気にしなければ、16進数でopコードを書くことになります。
ソロモンスロー

2
配列はポインターではなく、暗黙的にポインターに減衰します。
CodesInChaos

4

はい、それは悪い習慣ですが、非効率的な理由のためではありません。

配列演算子は、フードの下で算術ポインターを使用するため、同等に効率的です。

ポインター演算の問題は、非常にエラーが発生しやすく、読みにくいことです。

経験則:必要な場合を除き、ポインター演算を使用しないでください。


1
とにかくポインター演算を使用するので、ポインターも同様にエラーが発生しやすく、読みにくいことを意味しませんか?
ニコガンブ

1
@NikoGambtコンパイラーは、内部でポインター演算を行うのに非常に優れており、「間違い」を起こすことはほとんどありません。結果として厄介なバグでミスを犯すのはプログラマーです。
キャスパーヴァンデンバーグ

@KaspervandenBergはい、同意します。しかし、私はプログラマーが犯したエラーに興味があり、配列のアドレスを参照する必要がある場合に、上でやったことを行うのが悪いプログラミング慣行であるかどうかはわかりません、そのようなケースが存在する場合。
ニコガンブ

1
@NikoGambtパフォーマンスの目的で読みにくいものを書くことはほとんど常に悪い習慣ですが、ゲインなしで読みにくいものを書くことは明白に悪い習慣です。
ニール

@Neil私の小さな実験は無意味ではありません。そうすることで、コンパイラが多次元配列を参照するポインターの配列を作成しているように見えることを学びました。ただし、パフォーマンスよりも読みやすさが重要であるとおっしゃっていたので、プログラミングの習慣としてはまだ悪いと思います。
ニコギャム

0

あなたの学習をクールにc、あなたはc個の小さな舌のねじれの1つを発見しました。配列に対してポインター演算を行うのではなく、ポインターの配列に対して行います。配列でポインター演算を行うことはできません。配列はポインターに減衰しますが、それ自体がポインター型ではありません。私が持っているもの(cmasterによるコメントを参照)は

int *array[]; //This is a array to pointers of type *int. 

array[k1] + k2; //This is pointer arithmetic on one pointer stored in the array  

このポインターを逆参照すると、計算されたばかりのポインターが指す値が得られます。一般に、あなたがしていることをする意味はありません。ただし、このように配列を線形化してから、その中を一気に進めることができます。

int array[y_dim*x_dim]; 
int index = x_dim*y + x; 
array[index]; //Gives you the element in x, y!

ストライドはx_dimです。私の答えが明確になることを願っています!


それが使用するかどうかはOPからのはっきりしない、または。これら3つの定義のいずれかをOPのコードで使用できます。int* array[ROW];int array[ROW][COLUMN];int (*array)[COLUMN];
cmaster-モニカの復元

はい、私はそれを知っています、私の答えはその点で少し不器用です。修正しました、ありがとう!
fhtuft
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.