* ptr + = 1とCの* ptr ++の違い


122

Cの勉強を始めたばかりで、関数のパラメーターとしてポインターへのポインターを渡すことについて1つの例を実行すると、問題が見つかりました。

これは私のサンプルコードです:

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

int* allocateIntArray(int* ptr, int size){
    if (ptr != NULL){
        for (int i = 0; i < size; i++){
            ptr[i] = i;
        }
    }
    return ptr;
}

void increasePointer(int** ptr){
    if (ptr != NULL){
        *ptr += 1; /* <----------------------------- This is line 16 */
    }
}

int main()
{
    int* p1 = (int*)malloc(sizeof(int)* 10);
    allocateIntArray(p1, 10);

    for (int i = 0; i < 10; i++){
        printf("%d\n", p1[i]);
    }

    increasePointer(&p1);
    printf("%d\n", *p1);
    p1--;
    free(p1);
    fgets(string, sizeof(string), stdin);
    return 0;
}

この問題は、16行目でに変更する*ptr+=1と発生し*ptr++ます。期待される結果は配列全体と数値1になるはずですが、使用*ptr++すると結果は0になります。

間の任意のdiffirenceあります+=1とは++?どちらも同じだと思いました。


2
宣言していないため、指定したコードはコンパイルされないことに注意してくださいstring
Spikatrix 2016

6
その他の注意事項:1)関数からの配列のallocateIntArrayように見えますがmalloc、そうではありません。fillIntArray代わりに提案します。2)の戻り値を利用しないallocateIntArray。戻り値の型をに変更することをお勧めしますvoid。3)すべきではないif (ptr != NULL)機能でincreasePointerあることif (*ptr != NULL)?4)キャストインmallocは不要です。上記のSouravのコメントを参照してください。5)これ:で囲む必要がfor (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }ありprintf("%d\n", *p1); p1--;ますif(p1 != NULL)。6)string.h未使用です。
Spikatrix 2016

9
p+=1のようなもの++pではなくp++
コス

5
この質問は4年前に尋ねられました:++はポインターの+ = 1と同じですか
ren

3
@renほぼ、しかし完全ではない。リンクされた質問には、OPの問題の核心である間接参照演算子は含まれていません。
Jason C

回答:


289

違いは、演算子の優先順位によるものです。

ポストインクリメント演算子++は、逆参照演算子よりも優先され*ます。したがって、*ptr++と同等*(ptr++)です。言い換えると、ポストのインクリメントは、それが指しているものではなく、ポインタを変更します。

代入演算子+=は、逆参照演算子よりも優先順位が低い*ため、*ptr+=1と同等(*ptr)+=1です。つまり、代入演算子はポインターが指す値を変更し、ポインター自体は変更しません。


3
初心者のために、ニーモニック間の類似性である*p++*++p。後者の演算子の優先順位は明らかで、前者の演算子は次のとおりです。
Walter Tross

21

質問に関係する3つの演算子の優先順位は次のとおりです。

ポストインクリメント++>逆参照*>割り当て+=

このページで詳細を確認できます

式を解析するとき、ある行にリストされている演算子は、その下にある行にリストされている演算子よりも、(括弧によって)引数に強くバインドされます。たとえば、式*p++はとして*(p++)ではなくとして解析され(*p)++ます。

要するに、*ptr+=1ポストインクリメント演算子を使用してこの割り当てを表現するには、逆参照演算子に括弧を追加し++て、このように操作を優先させる必要があります。(*ptr)++


3
興味深いことに、これは現在、ソリューションを含む唯一の回答です...(* ptr)++
hyde

7

括弧を適用して操作順序を示しましょう

a + b / c
a + (b/c)

もう一度やってみましょう

*ptr   += 1
(*ptr) += 1

そして再び

*ptr++
*(ptr++)
  • では*ptr += 1、ポインターが指す変数の値をインクリメントします。
  • では*ptr++、私たちは、ポインタをインクリメントした後に行われ、当社の文全体(コードの行)、および変数への私たちのポインタ参照を返すに。

後者では、次のようなことができます。

for(int i = 0; i < length; i++)
{
    // Copy value from *src and store it in *dest
    *dest++ = *src++;

    // Keep in mind that the above is equivalent to
    *(dest++) = *(src++);
}

これは、src配列を別のdest配列にコピーするために使用される一般的な方法です。


「そして、ポインターが指す変数への参照を返します。」Cには参照がありません。
Miles Rout、2016

@MilesRoutおそらくそれを左辺値と呼ぶほうが正確かもしれません。しかし、私は専門用語を追加せずにそれを置く方法がわかりません。
Mateen Ulhaq、2016

3

非常に良い質問です。

K&R「Cプログラミング言語」「5.1ポインターとアドレス」では、これに対する答えを得ることができます。

「単項演算子*および&は、算術演算子よりも強く結合します」

*ptr += 1      //Increment what ptr points to.

「*や++などの単項演算子は、右から左に関連付けられます。」

*ptr++        //Increment prt instead of what ptr point to.

// *(ptr ++)のように機能します。

正しい方法は次のとおりです。

(*ptr)++      //This will work.

Stack Overflowについてコメントするのはこれが初めてです。コードのフォーマットを更新しました。^^ご提案ありがとうございます。
Nick.San

2

* ptr + = 1:ptrが指すデータを増分します。* ptr ++:ポインターが指すデータではなく、次のメモリー位置を指すポインターを増分します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.