Bir işaretçi adresi ve işaretçi değeri nasıl artırılır?


96

Farz edelim,

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

Aşağıdaki kod aslında ne yapacak ve nasıl yapacak?

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

Biliyorum, bu kodlama açısından biraz dağınık, ama böyle kodladığımızda aslında ne olacağını bilmek istiyorum.

Not: adresi varsayalım Sağlar a=5120300, bu pointer saklanır pkimin adresidir 3560200. Şimdi, p & aher bir cümlenin çalıştırılmasından sonra değeri ne olacak ?


3
neden onu hata ayıklayıcıda çalıştırmıyorsunuz?
AndersK

24
Peki .. neden sadece deneyip görmüyorsunuz? printf% p ile bir işaretçi yazdıracak
Brian Roach

Davranışı merak ediyorsanız, onunla oynayın. Sadece tüm bu kullanım durumlarından geçen basit bir c programı yazın ve sizin için mantıklı olup olmadığına bakın.
Cyrus

@AndersK. Belki de OP tanımlanmamış davranışlar beklemektedir? ... Ya da olmayabilir.
Mateen Ulhaq

Yanıtlar:


178

İlk olarak, ++ operatörü * operatörüne göre ve () operatörleri diğer her şeyden önceliklidir.

İkinci olarak, herhangi bir şeye atamıyorsanız, ++ sayı operatörü sayı ++ operatörüyle aynıdır. Aradaki fark sayı ++ 'nın sayıyı döndürmesidir ve ardından sayıyı artırır ve ++ sayı ilk olarak artar ve sonra onu döndürür.

Üçüncüsü, bir işaretçinin değerini artırarak, onu içeriğinin boyutuna göre artırırsınız, yani onu bir dizide yineliyormuşsunuz gibi artırmış olursunuz.

Yani, hepsini özetlemek gerekirse:

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

Burada çok fazla vaka olduğu için bazı hatalar yapmış olabilirim, lütfen yanlışsam düzeltin.

DÜZENLE:

Bu yüzden yanılmışım, öncelik yazdığımdan biraz daha karmaşık, buraya bakın: http://en.cppreference.com/w/cpp/language/operator_precedence


6
* ptr ++, değer artırılmaz, işaretçi. Bu tekli operatörler aynı önceliğe sahiptir ancak sağdan sola olarak değerlendirilirler. Kod "içeriği ptr'yi gösterdiği yerden al, sonra ptr'yi artır" anlamına gelir. Çok yaygın bir C kodudur (ve evet, oldukça kafa karıştırıcıdır). Lütfen bunu düzeltin, olumsuz oyu kaldıracağım. * (Ptr) ++ için aynıdır, parantez hiçbir şey yapmaz.
Lundin

Çok teşekkür ederim Lundin, başka bir şey özledim mi?
felipemaia

@Lundin Merhaba, yukarıdaki cevap şimdi düzeltildi mi? Teşekkürler.
Unheilig

4
@Unheilig İlk cümle hala tamamen yanlış, postfix ++, önek ++ ile aynı önceliğe sahip olan tekli * yerine önceliklidir. Bunun dışında iyi görünüyor.
Lundin

4
@felipemaia Segfault olacağından emin misiniz? Belki sadece tanımlanmamış bir davranıştır?
jotik

14

programı kontrol etti ve sonuçlar şöyle:

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 kullanın, örneğin, düşünün ifadesi, 'int * a = p ++;' Burada 'p' işaretçisinin ilk değeri kullanılacak ve bundan sonra p bir sonraki konuma geçecektir. Dolayısıyla, yukarıdaki 'a' ifadesi çalıştırıldıktan sonra, 'p' ile gösterilen önceki konumun adresine sahip olacak ve 'p' bir sonraki konumu işaret edecektir. Bu, ilk önce yukarıdaki gibi atama ifadesi için 'p' değerini kullanın ve ardından bir sonraki konuma işaret etmek için 'p' değerini
artırın

Kısacası, daha resmi bir terim olan "atama" için "kullan" ifadesini kullandığını düşünüyorum. Hepsi bu.
Apekshik Panigrahi

4

Aşağıda, çeşitli "sadece yazdırın" önerilerinin bir örneği verilmiştir. Öğretici buldum.

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

Döner

(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

intKolayca karşılaştırılabilmeleri için işaretçi adreslerini s'ye çevirdim.

Bunu GCC ile derledim.


1
Bunu işlemden sonra x ve p değerlerini içerecek şekilde değiştirirdim.
NetJohn

3

İle ilgili olarak "Nasıl bir işaretçi adresi ve işaretçinin değeri arttırmak için?" Bunun ++(*p++);aslında iyi tanımlandığını ve istediğiniz şeyi yaptığını düşünüyorum , örneğin:

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

Aynı şeyi bir sıralama noktasından önce iki kez değiştirmiyor. Çoğu kullanım için iyi bir stil olduğunu düşünmüyorum - beğenime göre biraz fazla gizli.


Aslında parantezler gereksizdir: ++*p++hem değeri hem de işaretçiyi başarılı bir şekilde artırır (sonek ++, referansa göre daha güçlü bağlanır *ve bu ++, sıraya bağlı olarak önekten önce gerçekleşir ). Parantezler, yalnızca değeri artırmadan önce ihtiyacınız olduğunda gereklidir (*p++)++. All-prefix'e giderseniz, ++*++pparantez olmadan da gayet iyi çalışacaktır (ancak işaretçi artışından sonra gösterilen değeri artırın).
cmaster - reinstate monica

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

İlişkisellik nedir?
71GA

1
kodda * str ++ görebilirsiniz, şimdi burada hem * hem de ++ aynı önceliğe sahiptir (layman'ın teriminde aynı önceliğe sahiptir) ve ayrıca * str ++, * (str ++) veya (* str) ++ gibi parantezler kullanılarak ayrılmaz, bu yüzden nasıl değerlendirilmesi gerektiği gerekli hale gelir. yani sağdan sola, (x = str ++) ve sonra (y = * x)
Abhishek DK
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.