10

arr[i]C のように配列の要素にアクセスする場合、要素に としてアクセスすることもできるというのはかなり一般的な知識i[arr]です*(arr + i)。私の質問は、なぜこれがより大きいデータ型で機能するのかというcharことsizeof(char)です.1であるためです.私にとっては、ポインタを1文字だけ進める必要があります.

おそらく、この例はそれをより明確にします:

#include <string.h>
#include <stdio.h>

struct large { char data[1024]; };

int main( int argc, char * argv[] )
{
    struct large arr[4];
    memset( arr, 0, sizeof( arr ) );

    printf( "%lu\n", sizeof( arr ) ); // prints 4096

    strcpy( arr[0].data, "should not be accessed (and is not)" );
    strcpy( arr[1].data, "Hello world!" );

    printf( "%s, %s, %s\n", arr[1].data, 1[arr].data, (*(arr+1)).data );
    // prints Hello world!, Hello world!, Hello world!
    // I expected `hold not be accessed (and is not)' for #3 at least

    return 0;

}

では、なぜ配列ポインタに 1 を追加すると だけ進むのsizeof( struct large )でしょうか?

4

5 に答える 5

11

C では、ポインター演算が定義されているため、次のように記述します。

ptr + k

ポインタを kバイトではなく、k 個のオブジェクトだけ進めます。したがって、整数配列へのポインターがあり、書き込みを行う場合

*(myIntArrayPointer + 3)

オブジェクトの先頭から 3 バイト後に始まる整数ではなく、配列内のインデックス 3 の要素へのポインターを逆参照しています。

同様に、2 つのポインターを減算すると、合計バイト数ではなく、それらの間の要素の論理数が得られます。このように書く

(myIntArrayPointer + 3) - myIntArrayPointer

3 * sizeof(int)間にバイトがあっても、値は 3 になります。

お役に立てれば!

于 2011-08-24T20:01:14.247 に答える
7

それがポインタ演算です。あなたが書くとき

some_pointer + i 

次のようにコンパイルされます

some_pointer + (i * sizeof(*my_pointer))

(そのことについてiint:))

于 2011-08-24T20:01:57.120 に答える
2

この種の質問は、C仕様を読むことでいつでも答えることができます。それを試してみてください!

§6.5.6加法演算子、パラグラフ8:

整数型の式がポインターに加算またはポインターから減算されると、結果はポインターオペランドの型になります。ポインタオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、結果は元の要素からオフセットされた要素を指し、結果の配列要素と元の配列要素の添え字の差が整数式に等しくなります。

于 2011-08-24T20:03:59.897 に答える
1

配列/ポインタが型付けされます。コンパイラは、この場合は構造体の「もの」の大きさを知っています。

そして、C はそのように定義されています。ポインターを「1」進めると、配列内の次のものに移動します。コンパイラは、そのためにどこまで行くかを知っています。これは、関連する同等の構文のいずれにも適用されます。

*(arr + i)
arr[i]
i[arr]

コンパイラが認識しているすべての型。

これは「ポインター算術」と呼ばれ、もう 1 つ楽しいプロパティがあります。配列内の項目へのポインターが 2 つある場合、それらを減算して、それらの間の項目の数をオブジェクト (つまり、バイトではありません) で取得できます。

于 2011-08-24T19:59:43.830 に答える
0

arr は、4 つの構造体の配列として宣言され、各構造体は 1024 文字の char 配列で構成されます。

arr は、この構造体配列の最初の要素へのポインターとして解決されます。arr を 1 ずつインクリメントすると、この新しいポインターは構造体全体 (それが指す型) を 1 つスキップし、配列内の次の要素を指します。

要するに、ポインターが指す型をコンパイラーが認識し、配列をインクリメントすると、連続したメモリ位置にある同様の型の次の要素を指すようになります。

この場合、配列のベース アドレスが XYZ の場合、arr+ i = XYZ + i* sizeof(arr)/sizeof(struct large)

于 2011-08-24T20:06:50.527 に答える