ポインタアドレスとポインタの値をインクリメントする方法は?


96

仮定しましょう、

int *p;
int a = 100;
p = &a;

次のコードは実際に何をどのように実行しますか?

p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

これはコーディングの面でやや面倒ですが、このようにコーディングすると実際に何が起こるか知りたいです。

注:のアドレスを想定してみましょう。アドレスが。のa=5120300ポインタに格納されています。さて、各ステートメントの実行後の値はどうなりますか?p3560200p & a


3
デバッガーで実行しないのはなぜですか?
AndersK 2011年

24
さて..なぜそれを試して見てませんか?printf%pでポインタを出力します
Brian Roach

行動に興味がある場合は、それをいじってみてください。これらすべてのユースケースを通過する単純なcプログラムを作成し、それが自分にとって意味があるかどうかを確認するだけです。
Cyrus

@AndersK。たぶん、OPは未定義の動作を期待していますか?...またはそうでないかもしれません。
Mateen Ulhaq 2011年

回答:


175

まず、++演算子は*演算子よりも優先され、()演算子は他のすべてよりも優先されます。

次に、++ number演算子は、何にも割り当てていない場合はnumber ++演算子と同じです。違いは、number ++はnumberを返し、次にnumberをインクリメントし、++ numberは最初にインクリメントしてからそれを返すことです。

第3に、ポインターの値を増やすことにより、その内容のサイズだけポインターをインクリメントします。つまり、配列で反復しているようにポインターをインクリメントします。

それで、それをすべて要約すると:

ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value of ptr is incremented
++(*ptr); // The value of ptr is incremented
++*(ptr); // The value of ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value of ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then get's accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then get's accessed, with your code, segfault

ここはケースが多いので、間違えたかもしれませんが、間違っていたら訂正してください。

編集:

だから私は間違っていました、優先順位は私が書いたものより少し複雑です、ここでそれを見てください:http//en.cppreference.com/w/cpp/language/operator_precedence


6
* ptr ++、値はインクリメントされません、ポインタはインクリメントされます。これらの単項演算子の優先順位は同じですが、右から左に評価されます。このコードは、「ptrが指す場所からコンテンツを取得し、ptrをインクリメントする」ことを意味します。これは非常に一般的なCコードです(もちろん、かなり混乱します)。これを修正してください。反対票を削除します。*(ptr)++の場合と同じように、括弧は何もしません。
Lundin 2011年

ランディン、どうもありがとうございました、他に何か恋しいですか?
felipemaia 2011年

@Lundinこんにちは、上記の答えは今修正されていますか?ありがとう。
ウンハイリッヒ2014年

4
@Unheilig最初の文はまだ完全に間違っています。接尾辞++は、接頭辞++と同じ優先順位を持つ単項*よりも優先されます。それを除けば、それは大丈夫のようです。
Lundin 2014年

4
@felipemaiaセグメンテーション違反になると確信していますか?たぶん、その未定義の振る舞い?
jotik 2016

13

プログラムをチェックすると、結果は次のようになります。

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value

2
@alexは、たとえば、ステートメントを検討することを意味します。'int* a = p ++; ' ここでは、ポインタ 'p'の最初の値が使用され、その後、pは次の位置に移動します。したがって、実際には、上記のステートメントを実行した後、「a」は「p」が指す前の場所のアドレスを持ち、「p」は次の位置を指します。つまり、最初に上記のように代入式に「p」の値を使用し、次に「p」の値をインクリメントして次の位置をポイントします
Sujith R Kumar 2015

要するに、彼はより正式な用語「割り当て」に「それを使用する」というフレーズを使用していると思います。以上です。
ApekshikPanigrahi19年

4

以下は、さまざまな「印刷するだけ」の提案のインスタンス化です。私はそれが有益だと思いました。

#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

戻ります

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

ポインタアドレスをにキャストします int簡単に比較できるようにs。

GCCでコンパイルしました。


1
これを変更して、操作後にxとpの値を含めます。
NetJohn

3

「ポインタアドレスとポインタの値をインクリメントする方法」に関しては私はそれ++(*p++);が実際に明確に定義されており、あなたが求めていることを実行すると思います。

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

シーケンスポイントの前に同じものを2回変更することはありません。私はそれがほとんどの用途にとって良いスタイルだとは思いません-それは私の好みには少し謎めいたものです。


実際には、括弧は不要です。++*p++値とポインターの両方を正常にインクリメントします(後置++バインドは逆参照よりも強力*であり、++順序により接頭辞の前に発生します)。括弧は、値をインクリメントする前に値が必要な場合にのみ必要です(*p++)++。all-prefixを使用++*++pすると、括弧なしでも問題なく動作します(ただし、ポインターのインクリメント後にポイントされる値をインクリメントします)。
cmaster - REINSTATEモニカ

1
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);

結合性とは何ですか?
71GA

1
コードでは* str ++を見ることができますが、ここでは*と++の両方が同じ優先順位(素人の用語では同じ優先順位)を持ち、* str ++は*(str ++)や(* str)++のような括弧を使用して区切られていません。どのように評価するかが必要になります。つまり、右から左は(x = str ++)、次に(y = * x)を意味します
Abhishek DK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.