web-dev-qa-db-ja.com

++演算子を使用せずに直接ポインタ位置に移動するにはどうすればよいですか?

構造体へのポインターを使用しています。使用せずに特定の位置に直接移動できるかどうか知りたい++演算子。

#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);

動かない。私はどんな提案にも感謝します。

10
Rubén Pozo

さて、ポインタ演算はデータ型を尊重します!!

_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);
_
30
Sourav Ghosh

の動作

_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]_と同等であることに注意してください。後者の方が、配列を操作するときに、より明確になります。

8
Bathsheba

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];
_
2
H.S.