C では、一方を他方よりも使用することが望ましいのはいつですか?
6 に答える
これは実際には、スタイルとコーディング規約の問題です。C では、はwhereと同じであるとp[i]
定義されており、ポインタと整数インデックスです。知る限り、書くこともできますが、それは醜いです。*(p+i)
p
i
i[p]
これは、C++ では常に当てはまるとは限りません (これにより、定義operator []
などの機能が提供されます)。
私は個人的にハンドコーディングが嫌いで、その場合&p[i]
の方が好きです。p+i
通常、状況によって異なります。経験則はないと思います。
場合によっては、配列インデックスの方が優れています。たとえば、配列を割り当てた場合
char* ptr = malloc(SIZE);
ptr
後で解放したいので、値を変更しないようにする必要があります。その後、インデックスを操作できます。
または、関数の引数としてポインターを取得する場合
void func(char* ptr)
配列を実行する必要がある場合は、ポインター自体をインクリメントすることができ、インデックスとして使用する新しい変数を作成する必要はありません。
ただし、ほとんどの場合、それは自分の好みに依存します。
「配列インデックス」は、「ポインター演算」をラップする構文糖衣にすぎません。これは純粋に表面的なものであり、別の表記法であり、どちらを使用するかは個人的な好みの問題であることを意味します。
通常、あなたが尋ねたことの背後に隠れている本当の問題は、いつランダムアクセスを使用し、いつシーケンシャルアクセスを使用するかです(「ポインター演算」は、ポインターのシーケンシャルインクリメント/デクリメントを1以下で意味します)。答えは、可能な場合はシーケンシャル アクセスを使用し、必要な場合にのみランダム アクセスを使用することです。
パフォーマンスが低下しない限り、最小限の要件セットに依存してアルゴリズムを実装することを常にお勧めします。ランダム アクセスはシーケンシャル アクセスよりも強力な要件です。つまり、シーケンシャル アクセスは可能な限り避けるべきです。
パフォーマンスの観点からは、配列を反復処理するときに別の変数をインクリメントする必要がないため、(少なくともコンパイラの最適化を無効にして) ポインター演算を使用する方が良い場合があります。K&R 97 ページ (第 2 版) も参照してください。
それ以外の場合は、単にコーディング スタイルの問題です。
ポインターは、コンパイル時にデータ構造のサイズがわからない場合に役立ちます。たとえば、文字列の長さがわからない場合や、予想される整数の数などがわからない場合などです。このような状況では、要件に応じてポインターに動的にメモリを割り当てることができます。
一方、配列は柔軟性を低下させます。
ただし、この違い以外にも多くの違いがあります。
MISRA C++ 2008 (ルール 5-0-15) によると、配列のインデックス付けは、ポインター演算の唯一の形式でなければなりません。
ただし、このルールには例外があります。
インクリメント/デクリメント演算子は、配列へのポインターによって実装される反復子で使用できます
template < typename IterType >
uint8_t sum_values ( IterType iter, IterType end )
{
uint8_t result = 0;
while ( iter != end )
{
result += *iter;
++iter; // Compliant by exception
}
return result;
}
void my_fn ( uint8_t * p1, uint8_t p2[ ] )
{
uint8_t index = 0;
uint8_t * p3;
uint8_t * p4;
*p1 = 0;
++index;
index = index + 5;
p1 = p1 + 5; // Non-compliant – pointer increment
p1[ 5 ] = 0; // Non-compliant – p1 was not declared as array
p3 = &p1[ 5 ]; // Non-compliant – p1 was not declared as array
p2[ 0 ] = 0;
p2[ index ] = 0; // Compliant
p4 = &p2[ 5 ]; // Compliant
}
uint8_t a1[ 16 ];
uint8_t a2[ 16 ];
my_fn ( a1, a2 );
my_fn ( &a1[ 4 ], &a2[ 4 ] );
uint8_t a[ 10 ];
uint8_t * p;
p = a;
*( p + 5 ) = 0; // Non-compliant
p[ 5 ] = 0; // Compliant
sum_values ( &a1[ 0 ], &a1[ 16 ] );