-3

重複の可能性:
ポインター演算:++*ptrまたは*ptr++?

違いがわかりませんか?*ptr++を実装するコードの例を次に示します。

#include <stdio.h>
int my_array[] = {1,23,17,4,-5,100};
int *ptr;
int main(void)
{
int i;
ptr = &my_array[0]; /* point our pointer to the first
element of the array */
printf("\n\n");
for (i = 0; i < 6; i++)
{
printf("my_array[%d] = %d ",i,my_array[i]);
printf("ptr + %d = %d\n",i, *ptr++);

}
return 0;
}

出力は

my_array[0] = 1 ptr + 0 = 1
my_array[1] = 23 ptr + 1 = 23
my_array[2] = 17 ptr + 2 = 17
my_array[3] = 4 ptr + 3 = 4
my_array[4] = -5 ptr + 4 = -5
my_array[5] = 100 ptr + 5 = 100

2番目のprintfステートメントをprintf( "ptr +%d =%d \ n"、i、*(++ ptr));に変更すると、これが出力になります:

my_array[0] = 1 ptr + 0 = 23
my_array[1] = 23 ptr + 1 = 17
my_array[2] = 17 ptr + 2 = 4
my_array[3] = 4 ptr + 3 = -5
my_array[4] = -5 ptr + 4 = 100
my_array[5] = 100 ptr + 5 = -1881141248

私が理解できるように、誰かが違いを詳しく説明してください。

4

3 に答える 3

3

この質問はとにかく閉じられようとしているので、これは賛成のチャンスはありませんが、とにかくここにそれを置くことを余儀なくされています。

使用*ptr++すると、次のようになります。

  1. の既存の値のコピーを作成しますptr
  2. ptrタイプ幅バイトごとにインクリメントします(この場合charは1バイトなので、1バイトです)
  3. (1)で作成したコピーから以前の値を区別する

使用*++ptrすると、次のようになります。

  1. ptrタイプ幅バイトごとにインクリメントします(この場合charは1バイトなので、1バイトです)
  2. ptr`の新しい値を逆参照します。

ポストインクリメントの基本的なコピー後インクリメントの要件は、一時コピーが非常に高価になる可能性があるC++オブジェクトで前述の演算子をオーバーライドする場合のパフォーマンスにとって不可欠です。


ポストインクリメント

以下は、これを疑う人のためのインクリメント後の動作を示しています。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

static char test[] = "AB";
static const char *ptr = test;

void myprintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    printf("myprintf: %c\n", *ptr);
    vprintf(fmt, args);
}

int main(int argc, char *argv[])
{
    myprintf("main: %c\n", *ptr++);
    return EXIT_SUCCESS;
}

出力

myprintf: B
main: A

の値は、ほとんどの人が考えていることとは反対に、またほとんどのC / C ++のインストラクターや本が明らかに教えていることとは反対に、の呼び出しの前にptrすでに増分されていることに注意してください。これを分解すると、これが当てはまることが証明されます。main()myprintf()

movq    _ptr(%rip), %rsi     ; ptr value moved into rsi
movq    %rsi, %rcx           ; ptr value moved into rcx
addq    $1, %rcx             ; increment value by one
movq    %rcx, _ptr(%rip)     ; ** store incremented address back into ptr **
movsbl  (%rsi), %esi         ; old pointer value still in rsi dereferenced here.
movq    %rax, %rdi           
movb    $0, %al              
callq   _myprintf
movl    $0, %eax

プレインクリメント

上記と同じコードですが、プリインクリメントを使用しています。つまり、単一の呼び出しを次のように変更しますmain()

myprintf("main: %c\n", *++ptr);

出力

myprintf: B
main: B
于 2012-12-22T02:13:37.577 に答える
3

1つは、ポインタが指すものをフェッチする前にポインタをインクリメントし、もう1つは、ポインタからフェッチした後にインクリメントします。

2番目の例では、最後の反復で配列の終わりを超えて、配列の直後のメモリ位置にあるポインタ(またはランダムなガベージ)を出力しています(おそらく)

于 2012-12-22T00:55:42.450 に答える
1

1つはインクリメント前の演算子で、もう1つはインクリメント後の演算子です。

printf("%d", i++);と同じです:

printf("%d", i);
i += 1;

printf("%d", ++i);と同じですが:

i += 1;
printf("%d", i);
于 2012-12-22T00:59:39.613 に答える