C'de * ptr + = 1 ve * ptr ++ arasındaki fark


123

C'yi incelemeye yeni başladım ve işaretçiyi bir işlevin parametresi olarak işaretçiye geçirme hakkında bir örnek yaparken bir sorun buldum.

Bu benim örnek kodum:

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

I ve değişiklikler bu sorun, hat 16 oluşur *ptr+=1için *ptr++. Beklenen sonuç tüm dizi ve 1 numara olmalıdır, ancak kullandığımda *ptr++sonuç 0 olur.

Arasında herhangi ı artışlar var mıdır +=1ve ++? İkisinin de aynı olduğunu düşündüm.


2
Belirtilen kodun sizin açıklamadığınız gibi derlenmeyeceğini unutmayın string.
Spikatrix

6
Diğer notlar: 1) işlevdeki dizi allocateIntArraygibi göründüğü için kötü bir isimdir malloc, ancak siz değilsiniz. Onun fillIntArrayyerine öneririm . 2) Dönüş değerini kullanmıyorsunuz allocateIntArray. Dönüş türünü olarak değiştirmenizi öneririm void. 3) if (ptr != NULL)İşlevsel increasePointerolmamalı if (*ptr != NULL)mı? 4) mallocAlçıya alma gereksizdir. Sourav'ın yukarıdaki yorumuna bakın. 5) Bu: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }ve printf("%d\n", *p1); p1--;kapatılması gerekiyor if(p1 != NULL). 6) string.hkullanılmıyor.
Spikatrix

9
p+=1gibi ++p, değil gibip++
Kos

5
bu soru 4 yıl önce sorulmuştu: Is ++ işaretçiler için + = 1 ile aynı
ren

3
@ren Neredeyse, ama tam olarak değil. Bağlantılı soru, OP'nin buradaki meselesinin özü olan dereference operatörünü içermiyor.
Jason C

Yanıtlar:


290

Fark, operatör önceliğinden kaynaklanmaktadır.

Arttırma sonrası operatörü ++, referans kaldırma operatöründen daha yüksek önceliğe sahiptir *. Yani *ptr++eşdeğerdir *(ptr++). Başka bir deyişle, gönderi artışı işaretçiyi işaret ettiği şeyi değiştirmez.

Atama operatörü +=, referans kaldırma operatöründen daha düşük önceliğe sahiptir *, bu *ptr+=1nedenle eşdeğerdir (*ptr)+=1. Başka bir deyişle, atama operatörü işaretçinin işaret ettiği değeri değiştirir ve işaretçinin kendisini değiştirmez.


3
Başlayanlar için, bir anımsatıcı arasındaki benzerlik *p++ve *++p. İkincisinin operatör önceliği açıktır, birincisi takip eder.
Walter Tross

21

Sorunuza dahil olan 3 operatör için öncelik sırası aşağıdaki gibidir:

artım sonrası ++> başvuru *> atama+=

Konuyla ilgili daha fazla ayrıntı için bu sayfayı kontrol edebilirsiniz .

Bir ifadeyi ayrıştırırken, bir satırda listelenen bir operatör, argümanlarına, daha altındaki bir satırda listelenen herhangi bir operatörden daha sıkı (parantez gibi) bağlanır. Örneğin, ifade *p++olarak *(p++)değil, olarak ayrıştırılır (*p)++.

Uzun lafın kısası, bu atamayı *ptr+=1artım sonrası operatörünü kullanarak ifade etmek için, bu işlemin önceliğini burada ++olduğu gibi vermek için özümleme operatörüne parantez eklemeniz gerekir.(*ptr)++


3
Interesringly, bu çözümü içeren tek cevap ... (* ptr) ++ şu anda
Hyde

7

İşlem sırasını göstermek için parantez uygulayalım

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

Tekrar yapalım

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

Ve yine

*ptr++
*(ptr++)
  • ' *ptr += 1Da işaretçimizin işaret ettiği değişkenin değerini arttırıyoruz .
  • Olarak *ptr++biz işaretçiyi artırmak sonra yapılır eden tüm deyimi (kod çizgi) ve değişken için işaretçi bir referans dönüş noktaları için.

İkincisi, aşağıdaki gibi şeyler yapmanıza izin verir:

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

Bu, bir srcdiziyi başka bir diziye kopyalamak için kullanılan yaygın bir yöntemdir dest.


"ve işaretçimizin işaret ettiği değişkene bir referans döndürün." C'nin referansı yok.
Miles Rout

@MilesRout Belki ona bir lvalue demek daha doğru olabilir mi? Ama jargon eklemeden nasıl söyleyeceğimi bilmiyorum.
Mateen Ulhaq

3

Çok güzel soru.

K&R "C programlama dilinde" "5.1 İşaretçiler ve Adresler" de bunun cevabını alabiliriz.

"Tek terimli operatörler * ve & aritmetik operatörlerden daha sıkı bağlanır"

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

"* Ve ++ gibi tekli operatörler sağdan sola ilişkilendirir ."

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

// * (ptr ++) gibi çalışır.

Doğru yol şudur:

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

Stack Overflow hakkında ilk kez yorum yapıyorum. Kodun formatını güncelledim. ^^ Öneriniz için teşekkürler.
Nick.Sang

2

* ptr + = 1: ptr'nin işaret ettiği verileri artırın. * ptr ++: İşaretçinin işaret ettiği veriler yerine bir sonraki bellek konumuna işaret eden artış işaretçisi.

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.