構造体へのポインターを使用しています。使用せずに特定の位置に直接移動できるかどうか知りたい++
演算子。
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 10
struct dummy{
int id;
char buffer[10];
};
typedef struct dummy dummy_struct;
int main()
{
int i=0;
dummy_struct *ds = malloc(sizeof(dummy_struct)*ARRAY_SIZE);
dummy_struct *iterator = ds;
for(i=0;i<ARRAY_SIZE;i++)
{
iterator->id = i;
sprintf(iterator->buffer,"%d",i);
iterator++;
}
iterator = ds;
for(i=0;i<ARRAY_SIZE;i++)
{
printf("%d:%s:%p\n",iterator->id,iterator->buffer,iterator);
iterator++;
}
// I want to access directly to 5th position
iterator = ds + (sizeof(dummy_struct)*5);
printf("5th position %d:%s:%p\n",iterator->id,iterator->buffer,iterator);
return 0;
}
この文
iterator = ds + (sizeof(dummy_struct)*5);
動かない。私はどんな提案にも感謝します。
さて、ポインタ演算はデータ型を尊重します!!
_iterator = ds + 5;
_
仕事を成し遂げるでしょう。
詳述すると、上記の式は、ポインターを5回移動し、ds
の型のサイズをバイト単位で乗算することにより、ポインターを生成します。これは&(ds[5])
と同じです。
完全を期すために、iterator = ds + (sizeof(dummy_struct)*5);
が間違っている理由を説明するのは、ここでは、基本的に、インデックスが_(sizeof(dummy_struct)*5
_である要素へのポインタを移動しようとしているためです。注意してください、これは 未定義の振る舞い !!を呼び出します。 以下に注意してください
引用_C11
_、§6.5.6/ P8章
整数型の式がポインターに加算またはポインターから減算されると、結果はポインターオペランドの型になります。ポインタオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、結果は元の要素からオフセットされた要素を指し、結果の配列要素と元の配列要素の添え字の差が整数式に等しくなります。言い換えると、式
P
が配列オブジェクトのi
番目の要素を指している場合、式_(P)+N
_(同等にN+(P)
)および_(P)-N
_(ここで、N
の値はn
)は、それぞれ、配列オブジェクトの_i+n
_番目と_i−n
_番目の要素を指します。それらは存在します。 [....]
次に、上記の未定義の振る舞いに関して、
[....]ポインタオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素を1つ過ぎている場合、評価はオーバーフローを生成してはなりません。それ以外の場合、動作は定義されていません。結果が配列オブジェクトの最後の要素の1つ過ぎを指している場合、評価される単項_
*
_演算子のオペランドとして使用されないものとします。
そうは言っても、printf()
ステートメントも誤りです。 2つの変換指定子がありますが、3つの引数を指定しました。それは有害ではありませんが、役に立たない/意味がありません。
関連、§7.21.6.1/ P2の章から、
[...]引数が残っている間にフォーマットが使い果たされた場合、余分な引数は(いつものように)評価されますが、それ以外の場合は無視されます。 [...]
この場合、直接ご利用いただけます
_printf("5th position %d:%s:\n",ds[5].id,ds[5].buffer);
_
の動作
_iterator = ds + (sizeof(dummy_struct) * 5);
_
配列の最後の要素を超えてポインタを設定した場合はndefinedです。実際には、sizeof(dummy_struct)
の係数で、配列内のさらに多くの要素にiterator
を設定しています。そうしないでください。
この言語では、表記_iterator = ds + 5;
_を使用できます。この慣用的なポインタ演算アドレスiterator
に_5
_たくさんのsizeof(dummy_struct)
を追加します。言い換えれば、コンパイラーがsizeof
調整を行います。これが、ポインタ演算が非常に強力である理由の1つです。
最後に、*(ds + 5)
は_ds[5]
_と同等であることに注意してください。後者の方が、配列を操作するときに、より明確になります。
iterator
配列の_5th
_要素を指すds
ポインタを作成しようとしているようです。しかし、このステートメントはあなたに間違った結果を与えるでしょう:
_iterator = ds + (sizeof(dummy_struct)*5);
_
sizeof(dummy_struct)*5
の結果は、構造体_dummy_struct
_のすべての要素の合計サイズに5を掛けたものになり、ds
によって参照されるアドレスに追加され、iterator
に割り当てられます。したがって、iterator
は、プログラムが所有していないメモリ位置を指している可能性があります。あなたがする必要があります:
_iterator = ds + 5;
_
または、次のこともできます。
_iterator = &ds[5];
_