İşaretçi ifadeleri: * ptr ++, * ++ ptr ve ++ * ptr


128

Son zamanlarda kendi başıma anlayamadığım bu problemle karşılaştım.

Bu üç İfade GERÇEKTEN ne anlama geliyor?

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

Ritchie'yi denedim. Ancak bu 3 operasyonla ilgili söylediklerini maalesef takip edemedi.

İşaretçiyi / işaret edilen değeri artırmak için bunların hepsinin yapıldığını biliyorum. Öncelik ve değerlendirme sırası hakkında pek çok şey olabileceğini de tahmin edebilirim. Biri artırmak gibi, önce işaretçiyi sonra o işaretçinin içeriğini alır, biri basitçe içeriği alır ve sonra işaretçiyi artırır vb. Gördüğünüz gibi, gerçek işlemleri hakkında net bir anlayışa sahip değilim, bunu yapmak istiyorum mümkün olan en kısa sürede temizleyin. Ama onları programlara uygulama şansı bulduğumda gerçekten kayboluyorum. Örneğin:

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

bana şu çıktıyı veriyor:

ello

Ama benim beklentim basacağıydı Hello. Son bir istek - Lütfen her bir ifadenin belirli bir kod parçacığında nasıl çalıştığına dair örnekler verin. Çoğu zaman kafamın üzerinden sadece bir paragraflık bir teori uçuyor.


6
Dördüncü olanı kaçırdınız: (*ptr)++(belirsizliği *ptr++
gidermek

15
Çünkü yazdırmadan önce işaretçiyi artırdınız. (* P) ​​ve printf ("% c", * p ++) iken istediniz;
dcaswell

Röportaj için harika sorular. Sınırlı pratik kullanım. Keşke C bu işaretlere sahip olmasaydı :)
Himanshu

5
@Himanshu Eğer görüştüğünüz kişinin eriştesini pişiriyorsa şunu deneyin: Geçerli sonlandırılmış benzersiz karakter dizisini gösteren global bir işaretçi edinin char* p. Daha sonra bir işlevi vardır fn(char ch)baskılar bu ikich parametre ve mevcut karakter ile gösterilen p. Şimdi S'yi çağırın fn(*p++);: fnAynı karakteri iki kez yazdırıyor mu ? Kaç profesörün bu soruyu yanlış anladığına şaşıracaksınız .
WhozCraig

1
p, yazmanız gereken bir dizgeyi gösterdiğindenconst char* p = "Hello";
hetepeperfan

Yanıtlar:


275

İşte yardımcı olacağını umduğum ayrıntılı bir açıklama. Açıklaması en basit olan programınız ile başlayalım.

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

İlk ifade:

const char* p = "Hello";

pbir işaretçi olarak ilan eder char. "Bir işaretçisi" dediğimizde char, bu ne anlama geliyor? Değerinin pa'nın adresi olduğu anlamına gelir char; pbize hafızanın neresinde a tutmak için ayrılmış bir boşluk olduğunu söyler char.

İfade ayrıca pdize değişmezindeki ilk karakteri gösterecek şekilde başlatılır "Hello". Bu alıştırma uğruna p, tüm dizeyi değil, yalnızca ilk karakteri işaret ettiğini anlamak önemlidir 'H'. Sonuçta , tüm dizeye değil, pbirine bir göstericidir char. Değeri padresidir 'H'in "Hello".

Ardından bir döngü oluşturursunuz:

while (*p++)

Döngü koşulu ne anlama *p++geliyor? Burada bunu şaşırtıcı kılan üç şey var (en azından aşinalık oluşana kadar):

  1. İki operatörün önceliği, postfix ++ve indirection*
  2. Bir sonek artış ifadesinin değeri
  3. Bir sonek artış ifadesinin yan etkisi

1. Öncelik . Operatörler için öncelik tablosuna hızlı bir bakış, sonek artışının dereference / indirection'dan (15) daha yüksek bir önceliğe (16) sahip olduğunu söyleyecektir. Karmaşık ifadesi olduğunu Bu araçlar *p++gidiyor olarak gruplandırılabilir için: *(p++). Yani *parça , parçanın değerine uygulanacaktır p++. Öyleyse önce p++bölümü ele alalım .

2. Sonek ifade değeri . Değeri p++değeridir p arttırmadan önce . Eğer varsa:

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

çıktı:

7
8

çünkü i++artımdan iönce değerlendirir . Benzer şekilde p++şu anki değeri de değerlendirilecek p. Bildiğimiz gibi şu anki değeri padresidir 'H'.

Yani şimdi p++parçası *p++değerlendirildi; şu anki değeridir p. Sonra *bölüm gerçekleşir. *(current value of p)anlamı: tutulan adresteki değere erişmektir p. Bu adresteki değerin olduğunu biliyoruz 'H'. Yani ifade olarak *p++değerlendirilir 'H'.

Şimdi bir dakika dur diyorsun. Olarak *p++değerlendirilirse 'H', bu neden 'H'yukarıdaki kodda yazdırılmıyor? Yan etkiler burada devreye girer.

3. Postfix ifadesi yan etkileri . Sonek ++, geçerli işlenenin değerine sahiptir , ancak bu işleneni artırmanın yan etkisine sahiptir. Ha? Bu intkoda tekrar bir göz atın :

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

Daha önce belirtildiği gibi çıktı şu şekilde olacaktır:

7
8

Ne zaman i++birinci değerlendirilir printf(), bu 7'ye değerlendirir Ama bir noktada, ikinci daha önce C standart garanti printf()yürütmeye başlar, yan etki arasında ++operatör yerini almış olacaktır. Yani, ikinci printf()gerçekleşmeden önce , ilkinde operatörün ibir sonucu olarak artmış olacaktır . Bu arada, bu, standardın yan etkilerin zamanlamasıyla ilgili verdiği birkaç garantiden biridir.++printf()

Kodunuzda, daha sonra ifade *p++değerlendirildiğinde, olarak değerlendirilir 'H'. Ama buna vardığınızda:

printf ("%c", *p)

bu sinir bozucu yan etki meydana geldi. partırıldı. Oha! Artık işaret etmiyor 'H', geçmiş bir karaktere işaret ediyor 'H': 'e'diğer bir deyişle. Bu, doğal çıktınızı açıklar:

ello

Bu nedenle, diğer cevaplardaki yardımcı (ve doğru) öneriler korosu: Alınan Telaffuz'u basmak için "Hello", onun kokain karşılığı değil, gibi bir şeye ihtiyacınız var.

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

Bunun için çok fazla. Gerisi ne olacak? Bunların anlamlarını soruyorsunuz:

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

Biz sadece bu yüzden saniyede Bakalım, ilk hakkında konuştuk: *++ptr.

Önceki açıklamamızda son ek artışının p++belirli bir önceliğe , bir değere ve bir yan etkiye sahip olduğunu gördük . Önek artışı ++p, sonek karşılığıyla aynı yan etkiye sahiptir : işleneni 1 artırır. Ancak, farklı bir önceliği ve farklı bir değeri vardır .

Önek artışının önceliği, sonekten daha düşüktür; 15 önceliğine sahiptir. Başka bir deyişle, referans / dolaylı yönlendirme operatörü ile aynı önceliğe sahiptir *. Gibi bir ifadede

*++ptr

önemli olan öncelik değildir: iki operatör öncelik bakımından aynıdır. Böylece ilişkilendirilebilirlik devreye giriyor. Önek artışı ve dolaylama operatörü sağ-sol ilişkilendirilebilirliğe sahip. Bu ilişkilendirilebilirlik nedeniyle, işlenen ptr, operatörden ++önce en sağdaki operatörle daha çok solda gruplanacaktır *. Başka bir deyişle, ifade gruplanacak *(++ptr). Öyleyse, olduğu gibi, *ptr++ancak farklı bir nedenle, burada da *parça parçanın değerine uygulanacaktır ++ptr.

Peki bu değer nedir? Önek artış ifadesinin değeri, artıştan sonra işlenenin değeridir . Bu, onu sonek artırma operatöründen çok farklı bir canavar yapar. Diyelim ki sahipsin:

int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);

Çıktı şu şekilde olacaktır:

8
8

... postfix operatörüyle gördüğümüzden farklı. Benzer şekilde, eğer varsa:

const char* p = "Hello";
printf ("%c ", *p);    // note space in format string
printf ("%c ", *++p);  // value of ++p is p after the increment
printf ("%c ", *p++);  // value of p++ is p before the increment
printf ("%c ", *p);    // value of p has been incremented as a side effect of p++

çıktı:

H e e l                // good dog

Nedenini anlıyor musun?

Şimdi sorduğunuz üçüncü ifadeye geliyoruz ++*ptr. Aslında en zor olanı bu. Her iki operatör de aynı önceliğe ve sağ-sol ilişkilendirilebilirliğe sahiptir. Bu, ifadenin gruplanacağı anlamına gelir ++(*ptr). ++Parçası değerine uygulanacak *ptrparçası.

Yani eğer sahipsek:

char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);

şaşırtıcı derecede egoist çıktı şöyle olacak:

I

Ne?! Tamam, yani *pbölüm olarak değerlendirilecek 'H'. Sonra ++oyuna giriyor, bu noktada, 'H'göstericiye değil, işaretleyiciye uygulanacak ! 1'i eklediğinizde ne olur 'H'? 1 artı ASCII değeri 'H', 72 elde edersiniz ; Eğer 73. Bir şekilde bu Temsil olsun charve sen olsun char73 ASCII değeri: 'I'.

Bu, sorunuzda sorduğunuz üç ifadeyle ilgilenir. İşte sorunuza yapılan ilk yorumda bahsedilen bir başkası:

(*ptr)++ 

Bu da ilginç. Eğer varsa:

char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);

size şu coşkulu çıktıyı verecektir:

HI

Neler oluyor? Yine, bu bir öncelik , ifade değeri ve yan etkiler meselesidir . Parantezler nedeniyle, *pparça birincil ifade olarak kabul edilir. Birincil ifadeler diğer her şeyi gölgede bırakır; önce değerlendirilirler. Ve *pbildiğiniz gibi değerlendiriyor 'H'. İfadenin geri kalanı olan ++kısım bu değere uygulanır. Yani, bu durumda (*p)++olur 'H'++.

Değeri nedir 'H'++? Eğer 'I'dediyseniz, sonek artışıyla değer ve yan etki tartışmamızı (zaten!) Unuttunuz. Unutmayın, şu anki değeri ile'H'++ değerlendirilir . Böylece ilk önce basılacak . Sonra, bir yan etki olarak , bu artacak . İkincisi bunu yazdırır . Ve neşeli selamınız var. 'H'printf()'H''H''I'printf()'I'

Pekala, ama bu son iki durumda neden ihtiyacım var

char q[] = "Hello";
char* p = q;

Neden böyle bir şeye sahip olamıyorum

/*const*/ char* p = "Hello";
printf ("%c", ++*p);   // attempting to change string literal!

Çünkü "Hello"bir dize değişmezidir. Eğer denerseniz ++*p, 'H'dizeyi olarak değiştirmeye çalışıyorsunuz 'I've tüm dizeyi oluşturuyorsunuz "Iello". C'de dize değişmezleri salt okunurdur; bunları değiştirmeye çalışmak, tanımlanmamış davranışa neden olur. "Iello"İngilizcede de tanımsız, ama bu sadece tesadüf.

Tersine, sahip olamazsın

char p[] = "Hello";
printf ("%c", *++p);  // attempting to modify value of array identifier!

Neden olmasın? Çünkü bu örnekte pbir dizidir. Bir dizi değiştirilebilir bir l-değeri değildir; pÖnceden veya artarak artırma veya azaltma ile noktaları değiştiremezsiniz , çünkü dizinin adı sabit bir işaretçi gibi çalışır. (Aslında öyle değil; bu, ona bakmanın uygun bir yolu.)

Özetlemek gerekirse, sorduğunuz üç şey şunlardır:

*ptr++   // effectively dereferences the pointer, then increments the pointer
*++ptr   // effectively increments the pointer, then dereferences the pointer
++*ptr   // effectively dereferences the pointer, then increments dereferenced value

Ve işte dördüncü, her biri diğer üçü kadar eğlenceli:

(*ptr)++ // effectively forces a dereference, then increments dereferenced value

ptrAslında bir dizi tanımlayıcısıysa birinci ve ikinci çökecektir . Üçüncü ve dördüncü, ptrbir dizgeye işaret ediyorsa çökecektir.

İşte aldın. Umarım artık hepsi kristaldir. Harika bir seyirci oldunuz ve bütün hafta burada olacağım.


22
Bu foruma gelmeden önce sahip olduğum 3 "C" kitabını araştırdım. Ayrıca bazı önemli çevrimiçi eğitimleri de denedim. Ancak hiçbiri açıklamanıza yaklaşmaz (özellikle de hepsini bir araya getirme biçiminiz). Sadece sorduğum soruyu yanıtlamakla kalmadınız, aynı zamanda tabandan gelen çok daha fazla şeyi tartıştınız. Aslında bugün bana daha önce eksik olduğum birçok temel şeyi öğrettiniz. Yardım edemedim ama kabul edilen cevabımı değiştirdim. :) Tekrar teşekkürler.
tahsis edildi

26
+1 Sanırım bu SO'da okuduğum en iyi uzun cevap. Bence bu cevaptan herkes çok şey öğrenebilir.
Shafik Yaghmour

9
Bayım, C hakkında bir kitap yazmalısınız
Dillon Burton

1
İyi bir soruya ne güzel bir cevap! Aferin @verbose!
benka

7
@verbose siz efendim, adınıza kadar yaşadınız .. :)
sleeping_dragon

44

ptrDizinin i'inci elemanına işaret ettiğini varsayalım arr.

  1. *ptr++(i + 1) öğesinin (i + 1) -ci öğesini işaret edecek şekilde değerlendirir arr[i]ve ayarlar . Eşdeğerdir .ptrarr*(ptr++)

  2. *++ptrptröğesinin (i + 1) -ci öğesini gösterecek şekilde ayarlar arrve değerlendirilir arr[i+1]. Eşdeğerdir *(++ptr).

  3. ++*ptrbir artar arr[i]ve artan değeri ile değerlendirilir; işaretçi ptrdokunulmadan bırakılır. Eşdeğerdir ++(*ptr).

Ayrıca bir tane daha var, ancak yazmak için parantezlere ihtiyacınız var:

  1. (*ptr)++bir artar arr[i]ve artırılmadan önce değerini değerlendirir; işaretçi ptryine dokunulmadan bırakılır.

Gerisini kendiniz çözebilirsiniz; @Jaguar tarafından da yanıtlandı.


13

*ptr++ : post increment a pointer ptr

*++ptr : Pre Increment a pointer ptr

++*ptr : preincrement the value at ptr location

Arttırma öncesi ve artım sonrası operatörleri hakkında burayı okuyun


Bu Helloçıktı olarak verecek

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

@ Nik-Lz Evet, çıktı şu olacakHello
Jainendra

7

Döngünüzdeki durum kötü:

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

Aynıdır

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

Ve bu yanlış, bu şöyle olmalı:

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

*ptr++şununla aynıdır *(ptr++):

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

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

*++ptrşununla aynıdır *(++ptr):

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

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

++*ptrşununla aynıdır ++(*ptr):

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

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

Cevabın ilk kısmına kesinlikle katılıyorum. İkinci bölümde, işaretçileri (tamsayılara!) Tamsayılarla başlatmak, işaretçi kullanımını anlamakta zorlanan biri için kafa karıştırıcıdır.
nickie

4

Öncelik konusunda haklısınız, unutmayın, *önek artışına göre önceliğe sahiptir, ancak sonek artışına göre önceliğe sahip değildir. İşte bu döküm şu şekilde:

*ptr++ - soldan sağa giderken, işaretçinin referansını kaldırın ve ardından işaretçi değerini artırın (sonekin referansa göre önceliği nedeniyle işaret ettiği değeri değil)

*++ptr - işaretçiyi artırın ve sonra referansını kaldırın, bunun nedeni önek ve referansın aynı önceliğe sahip olması ve bu nedenle sağdan sola sırayla değerlendirilmesidir.

++*ptr- Öncelik açısından yukarıdakine benzer şekilde, işaretçinin referansını kaldırmak ve ardından işaretçinin işaret ettiği şeyi artırmak için yine sağdan sola gitmek. Lütfen, salt okunur bir değişkeni ( char* p = "Hello";) değiştirmeye çalıştığınız için, sizin durumunuzda bunun tanımsız davranışa yol açacağını unutmayın .


3

Ben de kendi düşüncemi ekleyeceğim çünkü diğer cevaplar doğru olsa da, bir şeyleri eksik olduklarını düşünüyorum.

 v = *ptr++

anlamına geliyor

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

Buna karşılık

 v = *++ptr

anlamına geliyor

 ptr = ptr + 1
 v   = *ptr

Arttırmanın (ve azaltmanın) ne anlama geldiğini anlamak önemlidir.

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

Neden fark eder? C de bu o kadar önemli değil. C ++ 'da ptryineleyici gibi karmaşık bir tür olabilir. Örneğin

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

Bu durumda itkarmaşık bir tip it++olduğu için tempyaratılışından dolayı yan etkileri olabilir . Elbette şanslıysanız, derleyici gerekli olmayan kodu atmaya çalışacaktır, ancak yineleyicinin kurucusu veya yıkıcısı herhangi bir şey yaparsa it++, o zaman yarattığı zaman bu etkileri gösterecektir temp.

Söylemeye çalıştığım şeyin kısası, Ne Demek İstediğinizi Yazın . Eğer ortalama Eğer artım ptr sonra yazmak ++ptrdeğil ptr++. Demek istiyorsan temp = ptr, ptr += 1, tempyazptr++


0
*ptr++    // 1

Bu şununla aynıdır:

    tmp = *ptr;
    ptr++;

Böylece ile gösterilen nesnenin değeri ptralınır, ardından ptrartırılır.

*++ptr    // 2

Bu şununla aynıdır:

    ++ptr;
    tmp = *ptr;

Böylece işaretçi ptrartırılır, ardından işaret edilen nesne ptrokunur.

++*ptr    // 3

Bu şununla aynıdır:

    ++(*ptr);

Böylece ile gösterilen nesne ptrartırılır; ptrkendisi değişmedi.


0

sonek ve önek, referansa göre daha yüksek önceliğe sahiptir, bu nedenle

* ptr ++ burada artım ptr sonrası ve ardından yeni ptr değerine işaret etme

* ++ ptr burada Ön Arttırma yumruğu sonra yeni ptr değerini işaret edin

++ * ptr burada önce ptr'nin değerini alın ve bu değeri artırın


1
Bu yanlış. Sonek daha yüksek önceliğe sahiptir, ancak önek, referans ile aynı önceliğe sahiptir.
ayrıntılı

0

İşaretçi İfadeleri: * ptr ++, * ++ ptr ve ++ * ptr:

Not : işaretçiler başlatılmalı ve geçerli bir adrese sahip olmalıdır. Çünkü programımız (a.out) dışında RAM'de aynı anda çalışan çok daha fazla program var, yani sizin için ayrılmamış bir belleğe erişmeye çalışırsanız, OS Segmentasyon hatasıyla karşılaşacaktır.

Bunu açıklamadan önce basit bir örneği ele alalım.

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

Yukarıdaki kodun çıktısını analiz edin, umarım yukarıdaki kodun çıktısını almışsınızdır. Yukarıdaki koddan açık olan bir şey, işaretçi adının ( ptr ) adres hakkında konuştuğumuz anlamına geldiği ve * ptr'nin değer / veri hakkında konuştuğumuz anlamına gelmesidir .

DURUM 1 : * ptr ++, * ++ ptr, * (ptr ++) ve * (++ ptr):

Yukarıda belirtilen 4 sözdiziminin tümü benzerdir, address gets incrementedancak adresin nasıl arttığı farklıdır.

Not : Herhangi bir ifadeyi çözmek için ifadede kaç operatör olduğunu bulun, ardından operatörün önceliklerini bulun . Aynı önceliğe sahip birden fazla operatör daha sonra sağdan (R) sola (L) ve soldan sağa olabilen evrim veya ilişkilendirilebilirlik sırasını kontrol ediyorum .

* ptr ++ : Burada 2 operatör vardır: de-reference (*) ve ++ (artış). Her ikisi de aynı önceliğe sahip ve sonra R'den L'ye olan ilişkiyi kontrol et. Böylece, operatörler önce gelirse, Sağdan Sola çözmeye başlar.

* ptr ++ : ilk ++, R'den L'ye çözerken geldi, bu nedenle adres artırılır, ancak post artışı.

* ++ ptr : Buradaki ilkinin aynısı, adres de artırılır ancak ön artış olur.

* (ptr ++) : Burada 3 operatör vardır, bunların arasında en yüksek önceliğe sahip olan gruplama (), Yani önce ptr ++ çözüldü, yani adres artırılır ama post edilir.

* (++ ptr) : Yukarıdaki durumla aynı, burada da adres artırılır, ancak önceden artar.

DURUM 2 : ++ * ptr, ++ (* ptr), (* ptr) ++:

Yukarıda belirtilen 4 sözdiziminin tümü benzerdir, tüm değerde / verilerde artış olur, ancak değerin nasıl değiştiği farklıdır.

++ * ptr : ilk *, R'den L'ye çözerken geldi, bu nedenle değer değişir, ancak ön artışı.

++ (* ptr) : Yukarıdaki durumla aynı, değer değiştirilir.

(* ptr) ++ : Burada 3 operatör vardır, bunların arasında en yüksek önceliğe sahip gruplama () vardır, Inside () * ptr vardır, Yani önce * ptr çözülür, yani değer artırılır ama post edilir.

Not : ++ * ptr ve * ptr = * ptr + 1 her ikisi de aynıdır, her iki durumda da değer değişir. ++ * ptr: sadece 1 komut (INC) kullanılır, tek seferde doğrudan değer değişir. * ptr = * ptr + 1: burada ilk değer artırılır (INC) ve sonra atanır (MOV).

İşaretçideki artış sözdiziminin yukarıda belirtilen tüm sözdizimini anlamak için basit kodu ele alalım:

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

Yukarıdaki kodda, yorumları yorumlamayı / açıklamayı kaldırmayı ve çıktıları analiz etmeyi deneyin.

Sabit Olarak İşaretçiler : İşaretçileri sabit yapmanın hiçbir yolu yoktur, burada birkaçından bahsediyorum.

1) #define * p YA int const * p : İşte valuebir sabit , adres sabit değildir p işaret ediyor yani? Adres mi? Bu adreste değer nedir? Bazıları doğru mu? Bu değer sabittir, bu değeri değiştiremezsiniz ama işaretçi nereye işaret ediyor? Bir adres değil mi? Ayrıca başka bir adrese de işaret edebilir.

Bunu anlamak için aşağıdaki kodu ele alalım:

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

Yukarıdaki kodun çıktısını analiz etmeye çalışın

2) int const * p : buna **constant pointe**r"yani" denir address is constant but value is not constant. Burada adresi değiştirmenize izin verilmez ancak değeri değiştirebilirsiniz.

Not : sabit gösterici (yukarıdaki durum) kendini bildirirken başlatılmalıdır.

Bunu anlamak için basit kodu kontrol edelim.

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

Yukarıdaki kodda, ++ * p veya * p ++ olmadığını gözlemlerseniz, bunun basit bir durum olduğunu düşünebilirsiniz, çünkü adresi veya değeri değiştirmiyoruz, ancak hata üretecektir. Neden ? Yorumlarda bahsettiğim sebep.

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

Peki bu problemin çözümü nedir?

     int* const p = &x;

bu durum hakkında daha fazla bilgi için aşağıdaki örneği ele alalım.

#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 : Burada hem adres hem de değer sabittir .

Bunu anlamak için aşağıdaki kodu kontrol edelim

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

-1
const char *p = "Hello";   

*p means "Hello"
          ^
          | 
          p

*p++ means "Hello"
             ^
             | 
             p

*++p means "Hello"
            ^
            |     (WHILE THE STATEMENT IS EXECUTED)
            p

*++p means "Hello"
             ^
             |     (AFTER THE STATEMENT IS EXECUTED)
             p

++*paraçlar Eğer ASCII değeri arttırmak için çalıştıklarını*p

   is "Hello"
       ^
       | 
       p

değeri arttıramazsınız çünkü bu bir sabittir, böylece bir hata alırsınız

while döngünüzde olduğu gibi, döngü (NULL) karakterin *p++olduğu dizenin sonuna ulaşıncaya kadar çalışır '\0'.

Artık *p++ilk karakteri atladığından, çıktınızı yalnızca ikinci karakterden başlayarak alırsınız.

Aşağıdaki kod herhangi bir çıktı vermeyecektir çünkü while döngüsü '\0'

const char *p = "Hello";
    while('\0') 
         printf("%c",*p);

Aşağıdaki kod size bir sonraki kodla, yani ello ile aynı çıktıyı verecektir.

const char *p = "Hello";
    while(*++p)
         printf("%c",*p);

...................................

const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
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.