web-dev-qa-db-ja.com

ポインター式:* ptr ++、* ++ ptrおよび++ * ptr

最近、私は自分で理解できないこの問題に遭遇しました。

これら3つの式REALLYはどういう意味ですか?

*ptr++
*++ptr
++*ptr

私はリッチーを試しました。しかし、残念なことに、これらの3つの操作について彼が言ったことをフォローできませんでした。

私はそれらがすべてポインタ/ポイントされた値をインクリメントするために実行されることを知っています。また、優先順位と評価の順序について多くのことがあるかもしれません。最初にポインターをインクリメントしてからそのポインターのコンテンツをフェッチするように、単にコンテンツをフェッチしてからポインターなどをインクリメントします。ご覧のように、実際のについて明確な理解がありません操作、私はできるだけ早くクリアしたいと思います。しかし、プログラムでそれらを適用する機会を得たとき、私は本当に失われます。例えば:

int main()
{
    const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
    return 0;
}

私にこの出力を与えます:

Ello

しかし、私の期待はHelloを出力することでした。最後の1つのリクエスト-各式が特定のコードスニペットでどのように機能するかの例を教えてください。ほとんどの場合、理論の単なるパラグラフだけが私の頭の上を飛んでしまいます。

115
allocated

ptrが配列arrのi番目の要素を指しているとします。

  1. *ptr++arr[i]と評価され、ptrの(i + 1)番目の要素を指すようにarrを設定します。 *(ptr++)と同等です。

  2. *++ptrは、ptrの(i + 1)番目の要素を指すようにarrを設定し、arr[i+1]と評価します。 *(++ptr)と同等です。

  3. ++*ptrarr[i]を1つ増やし、その増加した値を評価します。ポインターptrはそのままです。 ++(*ptr)と同等です。

もう1つありますが、それを書くには括弧が必要です。

  1. (*ptr)++arr[i]を1増加させ、増加する前にその値を評価します。ポインタptrは再び触れられません。

残りの部分は自分で理解できます。 @Jaguarも回答しました。

43
nickie

*ptr++ : post increment a pointer ptr

*++ptr : Pre Increment a pointer ptr

++*ptr : preincrement the value at ptr location

here インクリメント前およびインクリメント後の演算子について読む


これにより、Helloが出力されます。

int main()
{
    const char *p = "Hello";
    while(*p)
         printf("%c",*p++);//Increment the pointer here 
    return 0;
}
13
Jainendra

ループの状態が悪いです:

while(*p++)
    printf("%c",*p);

と同じです

while(*p)
{
    p++;
    printf("%c",*p);
}

そしてそれは間違っています、これは次のようになります:

while(*p)
{
    printf("%c",*p);
    p++;
} 

*ptr++*(ptr++)と同じです。

const char  *ptr = "example";
char  value;

value = *ptr;
++ptr;
printf("%c", value); // will print 'e'

*++ptr*(++ptr)と同じです。

const char  *ptr = "example";
char  value;

++ptr;
value = *ptr;
printf("%c", value); // will print 'x'

++*ptr++(*ptr)と同じです。

const char  *ptr = "example";
char  value;

value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)
7
nouney

優先順位については、*が接頭辞の増分より優先されますが、接尾辞の増分より優先されないことに注意してください。これらの内訳は次のとおりです。

*ptr++-左から右に移動し、ポインターを逆参照してから、ポインター値をインクリメントします(逆参照に対する後置の優先順位のため、ポインターの値ではありません)

*++ptr-ポインターをインクリメントしてから逆参照します。これは、プレフィックスと逆参照の優先順位が同じであるため、右から左の順に評価されるためです。

++*ptr-優先順位の点で上記に似ていますが、再び右から左に向かってポインターを逆参照し、ポインターが指すものをインクリメントします。読み取り専用変数(char* p = "Hello";)を変更しようとしているため、このケースでは未定義の動作につながることに注意してください。

4
Nobilis

テイクを追加します。他の答えは正しいが、何かが欠けていると思うからです。

 v = *ptr++

手段

 temp = ptr;
 ptr  = ptr + 1
 v    = *temp;

どことして

 v = *++ptr

手段

 ptr = ptr + 1
 v   = *ptr

ポストインクリメント(およびポストデクリメント)が意味することを理解することが重要です

 temp = ptr       // Temp created here!!!
 ptr  = ptr + 1   // or - 1 if decrement)
 v    = *temp     // Temp destroyed here!!!

なぜ重要なのですか? Cでは、それはそれほど重要ではありません。ただし、C++ではptrは反復子のような複合型である場合があります。例えば

 for (std::set<int>::iterator it = someSet.begin(); it != someSet.end(); it++)

この場合、itは複合型であるためit++temp作成のために副作用がある可能性があります。もちろん、運がよければ、コンパイラは不要なコードを捨てようとしますが、イテレータのコンストラクタまたはデストラクタが何かを行うと、it++tempを作成するときにそれらの効果を示します。

私が言おうとしているのは、Write What Meeanです。 increment ptrの場合、++ptrではなくptr++と書きます。 temp = ptr, ptr += 1, tempの場合は、ptr++と書きます

3
gman
*ptr++    // 1

これは次と同じです:

    tmp = *ptr;
    ptr++;

したがって、ptrが指すオブジェクトの値が取得され、ptrが増分されます。

*++ptr    // 2

これは次と同じです:

    ++ptr;
    tmp = *ptr;

したがって、ポインターptrがインクリメントされ、ptrが指すオブジェクトが読み取られます。

++*ptr    // 3

これは次と同じです:

    ++(*ptr);

したがって、ptrが指すオブジェクトはインクリメントされます。 ptr自体は変更されていません。

0
David R Tribble

接尾辞と接頭辞は逆参照よりも優先順位が高いため、

* ptr ++は、インクリメントptrをポストし、ptrの新しい値をポイントします

* ++ ptrはここでPre Increment fistしてから、ptrの新しい値を指します

ここで++ * ptrは、最初にポイントするptrの値を取得し、そのvlaueをインクリメントします

0
Kiran Padwal

ポインタ式:* ptr ++、* ++ ptrおよび++ * ptr:

:ポインターは初期化され、有効なアドレスを持っている必要があります。プログラム(a.out)とは別にRAMには、より多くのプログラムが同時に実行されているため、つまり、OSがセグメンテーションフォールトを介して予約されていないメモリにアクセスしようとすると。

これを説明する前に、簡単な例を考えてみましょう。

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;//uninitialized pointer.. must be initialized
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr = *ptr + 1;//*ptr means value/data on the address.. so here value gets incremented
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        /** observe here that "num" got changed but manually we didn't change, it got modified by pointer **/
        ptr = ptr + 1;//ptr means address.. so here address got incremented
        /**     char pointer gets incremented by 1 bytes
          Integer pointer gets incremented by 4 bytes
         **/
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

上記のコードの出力を分析し、上記のコードの出力を得ることを望みます。上記のコードから明らかなことの1つは、ポインター名(ptr)がaddressおよび* ptrについて話していることを意味することです。 /データ。

ケース1* ptr ++、* ++ ptr、*(ptr ++)および*(++ ptr):

上記の4つの構文はすべてaddress gets incrementedで類似していますが、アドレスの増分方法は異なります。

:式を解くには、式に含まれる演算子の数を調べてから、演算子の優先度を求めます。同じ優先順位を持つ複数の演算子を使用して、進化の順序または結合性をチェックします。右(R)から左(L)または左から右へ。

* ptr ++:ここには、de-reference(*)と++(increment)の2つの演算子があります。両方とも同じ優先度を持っているので、RからLの結合性をチェックします。したがって、最初に来る演算子が何であれ、右から左へと解き始めます。

* ptr ++:RからLへの解決中に最初の++が来たため、アドレスは増加しますが、ポストは増加します。

* ++ ptr:最初のアドレスと同じですが、アドレスもインクリメントされますが、事前にインクリメントされます。

*(ptr ++):ここには3つの演算子があり、それらの中でグループ化()が最も優先度が高いため、最初にptr ++が解決しました。

*(++ ptr):上記の場合と同じですが、アドレスもインクリメントされますが、事前にインクリメントされます。

ケース2++ * ptr、++(* ptr)、(* ptr)++:

上記の4つの構文はすべてすべての値/データがインクリメントされますで似ていますが、値がどのように変更されるかは異なります。

++ * ptr:RからLへの解決中に最初の*が来たため、値は変更されますが、事前にインクリメントされます。

++(* ptr):上記の場合と同じ、値が変更されます。

(* ptr)++:ここには3つの演算子がありますが、それらの中で最も優先度の高い()をグループ化しています。Inside()* ptrがあります。したがって、最初に* ptrが解決されます。

:++ * ptrと* ptr = * ptr + 1は両方とも同じで、どちらの場合も値が変更されます。 ++ * ptr:1つの命令(INC)のみが使用され、値はシングルショットで直接変更されます。 * ptr = * ptr + 1:ここでは、最初の値がインクリメント(INC)され、次に割り当てられます(MOV)。

ポインタのインクリメントの上記のすべての異なる構文を理解するには、簡単なコードを考えてみましょう。

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//address changed(post increment), value remains un-changed
//      *++ptr;//address changed(post increment), value remains un-changed
//      *(ptr)++;//address changed(post increment), value remains un-changed
//      *(++ptr);//address changed(post increment), value remains un-changed

//      ++*ptr;//value changed(pre increment), address remains un-changed
//      (*ptr)++;//value changed(pre increment), address remains un-changed
//      ++(*ptr);//value changed(post increment), address remains un-changed

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

上記のコードでは、コメントをコメント化/コメント解除して、出力を分析してみてください。

定数としてのポインター:ポインターを定数として作成する方法はありません。ここで言及しているものはほとんどありません。

1)const int * p OR int const * p:ここでvalue is constantaddress is定数ではないすなわち、pが指している場所?いくつかのアドレス?そのアドレスで値は何ですか?何か価値がありますか?その値は一定であり、その値を変更することはできませんが、ポインターはどこを指しているのですか?住所は正しいですか?他のアドレスを指すこともできます。

これを理解するには、以下のコードを検討してください。

#include<stdio.h>
int main()
{
        int num = 300;
        const int *ptr;//constant value, address is modifible
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//
//      *++ptr;//possible bcz you are trying to change address which is possible
//      *(ptr)++;//possible
//      *(++ptr);//possible

//      ++*ptr;//not possible bcz you trying to change value which is not allowed
//      (*ptr)++;//not possible
//      ++(*ptr);//not possible

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

上記のコードの出力を分析してみてください

2)int const * p:「**constant pointe**r」と呼ばれるaddress is constant but value is not constant。ここでは、アドレスを変更することはできませんが、値を変更できます。

:定数ポインタ(上記の場合)は、宣言中に初期化する必要があります。

これを理解するには、簡単なコードを確認してください。

#include<stdio.h>
int main()
{
        int x = 300;
        int* const p;
        p = &x;
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

上記のコードで、++ * pまたは* p ++がないことを確認した場合、アドレスまたは値を変更していないのにエラーが発生するため、これは単純なケースであると考えるかもしれません。どうして ?コメントで言及した理由。

#include<stdio.h>
int main()
{
        int x = 300;
        /** constant pointer must initialize while decaring itself **/
        int* const p;//constant pointer i.e its pointing to some address(here its pointing to garbage), it should point to same address(i.e garbage ad
dress only 
        p = &x;// but here what we are doing ? we are changing address. we are making p to point to address of x instead of garbage address.
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

この問題の解決策は何ですか?

     int* const p = &x;

このケースの詳細については、以下の例を検討してください。

#include<stdio.h>
int main()
{
        int num = 300;
        int *const ptr = &num;//constant value, address is modifible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
//      *++ptr;//not possible bcz you are trying to change address which is not possible
//      *(ptr)++;//not possible
//      *(++ptr);//not possible

//      ++*ptr;// possible bcz you trying to change value which is allowed
//      (*ptr)++;// possible
//      ++(*ptr);// possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

3)const int * const p:ここではアドレスと値の両方が定数

これを理解するには、以下のコードを確認してください

#include<stdio.h>
int main()
{
        int num = 300;
        const int* const ptr = &num;//constant value,constant address 
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
        ++*ptr;//not possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
0
Achal