Zeigerausdrücke: * ptr ++, * ++ ptr und ++ * ptr

128

Vor kurzem bin ich auf dieses Problem gestoßen, das ich selbst nicht verstehen kann.

Was bedeuten diese drei Ausdrücke WIRKLICH ?

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

Ich habe Ritchie ausprobiert. Aber leider konnte er nicht folgen, was er über diese 3 Operationen erzählte.

Ich weiß, dass sie alle ausgeführt werden, um den Zeiger / den Wert, auf den gezeigt wird, zu erhöhen. Ich kann auch vermuten, dass es eine Menge Dinge über Vorrang und Reihenfolge der Bewertung gibt. Wie man den Zeiger zuerst inkrementiert, dann den Inhalt dieses Zeigers abruft, man einfach den Inhalt abruft und dann den Zeiger usw. inkrementiert usw. Wie Sie sehen können, habe ich kein klares Verständnis über ihre tatsächlichen Operationen, die ich gerne hätte so schnell wie möglich klar. Aber ich bin wirklich verloren, wenn ich die Möglichkeit bekomme, sie in Programmen anzuwenden. Beispielsweise:

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

gibt mir diese Ausgabe:

ello

Aber ich hatte erwartet, dass es gedruckt wird Hello. Eine letzte Anfrage - Bitte geben Sie mir Beispiele dafür, wie jeder Ausdruck in einem bestimmten Codeausschnitt funktioniert. Da die meiste Zeit nur ein Absatz der Theorie über meinen Kopf geflogen wird.

zugewiesen
quelle
6
Sie haben den vierten verpasst: (*ptr)++(Klammern müssen *ptr++
eindeutig sein
15
Weil Sie den Zeiger erhöht haben, bevor Sie ihn gedruckt haben. Sie wollten while (* p) und printf ("% c", * p ++);
Dcaswell
Tolle Fragen zum Interview. Begrenzte praktische Verwendung. Ich wünschte, C hätte diese Hinweise nicht :)
Himanshu
5
@Himanshu Wenn das die Nudel Ihres Befragten backt, versuchen Sie Folgendes: Haben Sie einen globalen Zeiger char* p, der auf eine gültige terminierte Zeichenfolge eindeutiger Zeichen zeigt. Haben Sie dann eine Funktion fn(char ch), die sowohl den chParameter als auch das aktuelle Zeichen druckt, auf das von gezeigt wird p. Rufen Sie nun fn(*p++);F auf: Druckt fndasselbe Zeichen zweimal ? Sie werden erstaunt sein, wie viele Professoren diese Frage falsch verstehen.
WhozCraig
1
da p auf ein String-Literal zeigt, sollten Sie schreibenconst char* p = "Hello";
hetepeperfan

Antworten:

275

Hier ist eine detaillierte Erklärung, von der ich hoffe, dass sie hilfreich ist. Beginnen wir mit Ihrem Programm, da es am einfachsten zu erklären ist.

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

Die erste Aussage:

const char* p = "Hello";

deklariert pals Zeiger auf char. charWas bedeutet das, wenn wir "Zeiger auf a " sagen ? Dies bedeutet, dass der Wert von pdie Adresse von a ist char; psagt uns, wo im Speicher etwas Platz für a ist char.

Die Anweisung wird auch initialisiert p, um auf das erste Zeichen im Zeichenfolgenliteral zu verweisen "Hello". Für diese Übung ist es wichtig zu verstehen p, dass nicht auf die gesamte Zeichenfolge, sondern nur auf das erste Zeichen verwiesen wird 'H'. Immerhin pist ein Zeiger auf eins char, nicht auf die gesamte Zeichenfolge. Der Wert pist die Adresse des 'H'in "Hello".

Dann richten Sie eine Schleife ein:

while (*p++)

Was bedeutet die Schleifenbedingung *p++? Drei Dinge wirken hier rätselhaft (zumindest bis Vertrautheit einsetzt):

  1. Der Vorrang der beiden Operatoren Postfix ++und Indirektion*
  2. Der Wert eines Postfix-Inkrementausdrucks
  3. Der Nebeneffekt eines Postfix-Inkrementausdrucks

1. Vorrang . Ein kurzer Blick auf die Prioritätstabelle für Operatoren zeigt, dass das Postfix-Inkrement eine höhere Priorität hat (16) als die Dereferenzierung / Indirektion (15). Dies bedeutet, dass der komplexe Ausdruck wie *p++folgt gruppiert wird : *(p++). Das heißt, das *Teil wird auf den Wert des p++Teils angewendet . Nehmen wir also p++zuerst den Teil.

2. Postfix-Ausdruckswert . Der Wert von p++ist der Wert p vor dem Inkrement . Wenn Sie haben:

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

Die Ausgabe lautet:

7
8

weil i++bis ivor dem Inkrement ausgewertet . Ebenso p++wird auf den aktuellen Wert von ausgewertet p. Wie wir wissen, ist der aktuelle Wert von pdie Adresse von 'H'.

Nun wurde der p++Teil von *p++bewertet; Es ist der aktuelle Wert von p. Dann *passiert der Teil. *(current value of p)bedeutet: Zugriff auf den Wert unter der Adresse von p. Wir wissen, dass der Wert an dieser Adresse ist 'H'. Der Ausdruck *p++ergibt also 'H'.

Moment mal, sagst du. Wenn dies *p++ausgewertet wird 'H', warum wird das nicht 'H'im obigen Code gedruckt? Hier kommen Nebenwirkungen ins Spiel.

3. Nebenwirkungen des Postfix-Ausdrucks . Das Postfix ++hat den Wert des aktuellen Operanden, hat jedoch den Nebeneffekt, dass dieser Operand inkrementiert wird. Huh? Schauen Sie sich diesen intCode noch einmal an:

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

Wie bereits erwähnt, lautet die Ausgabe wie folgt:

7
8

Wenn i++es im ersten printf()bewertet wird, wird es mit 7 bewertet. Der C-Standard garantiert jedoch, dass irgendwann vor printf()Beginn der Ausführung des zweiten die Nebenwirkung des ++Bedieners aufgetreten ist. Das heißt, bevor das zweite printf()passiert, wurde ies aufgrund des ++Operators im ersten erhöht printf(). Dies ist übrigens eine der wenigen Garantien, die der Standard für das Timing von Nebenwirkungen gibt.

Wenn der Ausdruck in Ihrem Code *p++ausgewertet wird, wird er ausgewertet 'H'. Aber wenn Sie dazu kommen:

printf ("%c", *p)

diese lästige Nebenwirkung ist aufgetreten. pwurde erhöht. Whoa! Es zeigt nicht mehr auf 'H', sondern auf eine vergangene Figur 'H': mit 'e'anderen Worten auf die. Das erklärt Ihre übermütige Leistung:

ello

Daher der Chor hilfreicher (und genauer) Vorschläge in den anderen Antworten: Um die empfangene Aussprache "Hello"und nicht ihr Cockney-Gegenstück zu drucken , benötigen Sie so etwas wie

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

So viel dazu. Was ist mit dem Rest? Sie fragen nach den Bedeutungen dieser:

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

Wir haben gerade über das erste gesprochen, also schauen wir uns das zweite an : *++ptr.

Wir haben in unserer früheren Erklärung gesehen, dass das Postfix-Inkrement p++eine bestimmte Priorität , einen Wert und einen Nebeneffekt hat . Das Präfixinkrement ++phat den gleichen Nebeneffekt wie sein Postfix-Gegenstück: Es erhöht seinen Operanden um 1. Es hat jedoch eine andere Priorität und einen anderen Wert .

Das Präfixinkrement hat eine niedrigere Priorität als das Postfix. es hat Vorrang 15. Mit anderen Worten, es hat den gleichen Vorrang wie der Dereferenzierungs- / Indirektionsoperator *. In einem Ausdruck wie

*++ptr

Was zählt, ist nicht Vorrang: Die beiden Operatoren haben Vorrang. Die Assoziativität setzt also ein. Das Präfixinkrement und der Indirektionsoperator haben eine Assoziativität von rechts nach links. Aufgrund dieser Assoziativität wird der Operand ptrmit dem Operator ganz rechts ++vor dem Operator weiter links gruppiert *. Mit anderen Worten, der Ausdruck wird gruppiert *(++ptr). Wie bei, *ptr++aber aus einem anderen Grund, wird das *Teil auch hier auf den Wert des ++ptrTeils angewendet .

Was ist dieser Wert? Der Wert des Präfix-Inkrement-Ausdrucks ist der Wert des Operanden nach dem Inkrement . Dies macht es zu einem ganz anderen Tier als der Postfix-Inkrement-Operator. Angenommen, Sie haben:

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

Die Ausgabe wird sein:

8
8

... anders als beim Postfix-Operator. Ebenso, wenn Sie haben:

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++

Die Ausgabe lautet:

H e e l                // good dog

Verstehst du warum?

Nun kommen wir zu dem dritten Ausdruck, nach dem Sie gefragt haben ++*ptr. Das ist eigentlich das Schwierigste. Beide Operatoren haben die gleiche Priorität und Rechts-Links-Assoziativität. Dies bedeutet, dass der Ausdruck gruppiert wird ++(*ptr). Das ++Teil wird auf den Wert des *ptrTeils angewendet .

Also wenn wir haben:

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

Die überraschend egoistische Ausgabe wird sein:

I

Was?! Okay, das *pTeil wird also ausgewertet 'H'. Dann ++kommt das ins Spiel, an welchem ​​Punkt es 'H'auf den Zeiger angewendet wird , überhaupt nicht auf den Zeiger! Was passiert, wenn Sie 1 hinzufügen 'H'? Sie erhalten 1 plus den ASCII-Wert von 'H'72; Sie erhalten 73. Stellen Sie das als dar char, und Sie erhalten das charmit dem ASCII-Wert von 73 : 'I'.

Das kümmert sich um die drei Ausdrücke, nach denen Sie in Ihrer Frage gefragt haben. Hier ist eine andere, die im ersten Kommentar zu Ihrer Frage erwähnt wurde:

(*ptr)++ 

Das ist auch interessant. Wenn Sie haben:

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

es wird Ihnen diese begeisterte Ausgabe geben:

HI

Was ist los? Auch hier geht es um Vorrang , Ausdruckswert und Nebenwirkungen . Aufgrund der Klammern wird der *pTeil als primärer Ausdruck behandelt. Primäre Ausdrücke übertreffen alles andere; Sie werden zuerst ausgewertet. Und *p, wie Sie wissen, bewertet zu 'H'. Der Rest des Ausdrucks, der ++Teil, wird auf diesen Wert angewendet. Also, in diesem Fall (*p)++wird 'H'++.

Was ist der Wert von 'H'++? Wenn Sie gesagt haben 'I', haben Sie (bereits!) Unsere Diskussion über Wert vs. Nebenwirkung mit Postfix-Inkrement vergessen. Denken Sie daran, ergibt'H'++ den aktuellen Wert von 'H' . Das wird also zuerst printf()gedruckt 'H'. Dann wurde als Nebeneffekt , dass 'H'geht werden erhöht 'I'. Der zweite printf()druckt das 'I'. Und du hast deinen fröhlichen Gruß.

In Ordnung, aber in den letzten beiden Fällen, warum brauche ich

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

Warum kann ich nicht einfach so etwas haben?

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

Weil "Hello"ist ein String-Literal. Wenn Sie es versuchen ++*p, versuchen Sie, 'H'die Zeichenfolge in zu ändern 'I'und die gesamte Zeichenfolge zu erstellen "Iello". In C sind String-Literale schreibgeschützt. Der Versuch, sie zu ändern, ruft undefiniertes Verhalten hervor. "Iello"ist auch auf Englisch undefiniert, aber das ist nur Zufall.

Umgekehrt kann man nicht haben

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

Warum nicht? Denn in diesem Fall phandelt es sich um ein Array. Ein Array ist kein modifizierbarer l-Wert. Sie können nicht ändern, wo pPunkte vor oder nach dem Inkrementieren oder Dekrementieren liegen, da der Name des Arrays so funktioniert, als wäre es ein konstanter Zeiger. (Das ist nicht das, was es eigentlich ist. Das ist nur eine bequeme Art, es zu betrachten.)

Zusammenfassend sind hier die drei Dinge, nach denen Sie gefragt haben:

*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

Und hier ist ein vierter, der genauso viel Spaß macht wie die anderen drei:

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

Der erste und der zweite stürzen ab, wenn ptr es sich tatsächlich um eine Array-ID handelt. Der dritte und vierte stürzen ab, wenn ptrauf ein Zeichenfolgenliteral verwiesen wird.

Hier hast du es. Ich hoffe es ist jetzt alles Kristall. Sie waren ein großartiges Publikum und ich werde die ganze Woche hier sein.

ausführlich
quelle
22
Bevor ich zu diesem Forum komme, habe ich 3 "C" -Bücher durchsucht, die ich besitze. Ich habe auch einige bemerkenswerte Online-Tutorials ausprobiert. Aber keiner von ihnen kommt Ihrer Erklärung nahe (insbesondere der Art und Weise, wie Sie alles zusammengestellt haben). Sie haben nicht nur die Frage beantwortet, die ich gestellt habe, sondern Sie haben auch viel mehr Dinge von der Basis aus besprochen. Eigentlich hast du mir heute viele grundlegende Dinge beigebracht, die mir vorher gefehlt haben. Ich konnte nicht anders, als meine akzeptierte Antwort umzuschalten. :) Danke noch einmal.
zugewiesen
26
+1 Ich denke, dies ist die beste lange Antwort, die ich auf SO gelesen habe. Ich denke, jeder kann aus dieser Antwort viel lernen.
Shafik Yaghmour
9
Sie, Sir, sollten ein Buch über C.
Dillon Burton
1
Was für eine schöne Antwort auf eine gute Frage! Gut gemacht @verbose!
Benka
7
@verbose Sie Sir, gelebt haben bis zu Ihrem Namen .. :)
sleeping_dragon
44

Angenommen, ptrPunkte zeigen auf das i-te Element des Arrays arr.

  1. *ptr++wertet aus arr[i]und setzt ptrauf das (i + 1) -te Element von arr. Es ist äquivalent zu *(ptr++).

  2. *++ptrsetzt ptrauf das (i + 1) -te Element von arrund wertet auf aus arr[i+1]. Es ist äquivalent zu *(++ptr).

  3. ++*ptrerhöht sich arr[i]um eins und bewertet seinen erhöhten Wert; Der Zeiger ptrbleibt unberührt. Es ist äquivalent zu ++(*ptr).

Es gibt noch eine weitere, aber Sie benötigen Klammern, um sie zu schreiben:

  1. (*ptr)++erhöht sich arr[i]um eins und bewertet seinen Wert, bevor er erhöht wird; Der Zeiger ptrbleibt wieder unberührt.

Den Rest können Sie selbst herausfinden; es wurde auch von @Jaguar beantwortet.

Nickie
quelle
13

*ptr++ : post increment a pointer ptr

*++ptr : Pre Increment a pointer ptr

++*ptr : preincrement the value at ptr location

Lesen Sie hier mehr über Operatoren vor und nach dem Inkrementieren


Dies wird Helloals Ausgabe geben

int main()
{
    const char *p = "Hello";
    while(*p)
         printf("%c",*p++);//Increment the pointer here 
    return 0;
}
Jainendra
quelle
@ Nik-Lz Ja, die Ausgabe wäreHello
Jainendra
7

Der Zustand in Ihrer Schleife ist schlecht:

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

Ist das gleiche wie

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

Und das ist falsch, das sollte sein:

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

*ptr++ist das gleiche wie *(ptr++), was ist:

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

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

*++ptrist das gleiche wie *(++ptr), was ist:

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

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

++*ptrist das gleiche wie ++(*ptr), was ist:

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

value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)
Nomen
quelle
Ich werde dem ersten Teil der Antwort absolut zustimmen. Im zweiten Teil ist das Initialisieren von Zeigern (auf Ganzzahlen!) Mit Ganzzahlen für jemanden verwirrend, der Schwierigkeiten hat, die Verwendung von Zeigern zu verstehen.
Nickie
4

Wenn Sie Recht haben, beachten Sie, dass das *Vorrang vor dem Präfixinkrement hat, jedoch nicht vor dem Postfixinkrement. Hier ist, wie diese Aufschlüsselung:

*ptr++ - von links nach rechts gehen, den Zeiger dereferenzieren und dann den Zeigerwert erhöhen (nicht das, worauf er zeigt, da Postfix Vorrang vor der Dereferenzierung hat)

*++ptr - Inkrementieren Sie den Zeiger und dereferenzieren Sie ihn. Dies liegt daran, dass Präfix und Dereferenzierung dieselbe Priorität haben und daher in der Reihenfolge von rechts nach links ausgewertet werden

++*ptr- Ähnlich wie oben in Bezug auf die Priorität, wieder von rechts nach links, um den Zeiger zu dereferenzieren und dann zu erhöhen, auf was der Zeiger zeigt. Bitte beachten Sie, dass dies in Ihrem Fall zu undefiniertem Verhalten führt, da Sie versuchen, eine schreibgeschützte Variable ( char* p = "Hello";) zu ändern .

Nobilis
quelle
3

Ich werde meine Einstellung hinzufügen, denn während die anderen Antworten richtig sind, denke ich, dass ihnen etwas fehlt.

 v = *ptr++

meint

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

Wohingegen

 v = *++ptr

meint

 ptr = ptr + 1
 v   = *ptr

Es ist wichtig zu verstehen, dass Post-Inkrement (und Post-Dekrement) bedeuten

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

Warum spielt es eine Rolle? Nun, in C ist das nicht so wichtig. In C ++ kann ptres sich jedoch um einen komplexen Typ wie einen Iterator handeln. Beispielsweise

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

In diesem Fall kann itein komplexer Typ it++aufgrund der tempErstellung möglicherweise Nebenwirkungen haben . Wenn Sie Glück haben, wird der Compiler natürlich versuchen, nicht benötigten Code wegzuwerfen, aber wenn der Konstruktor oder Destruktor des Iterators irgendetwas tut it++, werden diese Effekte beim Erstellen angezeigt temp.

Das kurze von dem, was ich zu sagen versuche, ist Schreiben, was du meinst . Wenn Sie ptr inkrementieren, schreiben Sie ++ptrnicht ptr++. Wenn du meinst, temp = ptr, ptr += 1, tempdann schreibeptr++

gman
quelle
0
*ptr++    // 1

Dies ist das gleiche wie:

    tmp = *ptr;
    ptr++;

Der Wert des Objekts, auf das von zeigt, ptrwird abgerufen und dann ptrerhöht.

*++ptr    // 2

Dies ist das gleiche wie:

    ++ptr;
    tmp = *ptr;

Der Zeiger ptrwird also inkrementiert, und das Objekt, auf das von zeigt, ptrwird gelesen.

++*ptr    // 3

Dies ist das gleiche wie:

    ++(*ptr);

Das Objekt, auf das von zeigt, ptrwird also inkrementiert. ptrselbst ist unverändert.

David R Tribble
quelle
0

Postfix und Präfix haben also eine höhere Priorität als Dereferenzierung

* ptr ++ hier inkrementiere ptr und zeige dann auf den neuen Wert von ptr

* ++ ptr hier Inkrementiere die Faust und zeige dann auf den neuen Wert von ptr

++ * ptr Hier erhalten Sie zuerst den Wert von ptr, der auf diesen Wert zeigt, und erhöhen ihn

Kiran Padwal
quelle
1
Das ist falsch. Postfix hat eine höhere Priorität, aber Präfix hat dieselbe Priorität wie Dereferenzierung.
ausführliche
0

Zeigerausdrücke: * ptr ++, * ++ ptr und ++ * ptr:

Hinweis : Zeiger müssen initialisiert sein und eine gültige Adresse haben. Weil im RAM außer unserem Programm (a.out) viel mehr Programme gleichzeitig ausgeführt werden, dh wenn Sie versuchen, auf einen Speicher zuzugreifen, der nicht für Ihr Betriebssystem reserviert war, wird dies durch einen Segmentierungsfehler verursacht.

Bevor wir dies erklären, betrachten wir ein einfaches Beispiel.

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

Analysieren Sie die Ausgabe des obigen Codes. Ich hoffe, Sie haben die Ausgabe des obigen Codes erhalten. Aus dem obigen Code geht hervor, dass der Zeigername ( ptr ) bedeutet, dass wir über die Adresse sprechen , und * ptr bedeutet, dass wir über Wert / Daten sprechen .

FALL 1 : * ptr ++, * ++ ptr, * (ptr ++) und * (++ ptr):

oben erwähnt sind alle 4 Syntaxen ähnlich, address gets incrementedaber wie die Adresse erhöht wird, ist unterschiedlich.

Hinweis : Um einen Ausdruck zu lösen, ermitteln Sie, wie viele Operatoren im Ausdruck vorhanden sind, und ermitteln Sie dann die Prioritäten des Operators. Wenn mehrere Operatoren dieselbe Priorität haben, überprüfen Sie die Reihenfolge der Evolution oder Assoziativität , die von rechts (R) nach links (L) oder von links nach rechts erfolgen kann.

* ptr ++ : Hier gibt es 2 Operatoren, nämlich De-Reference (*) und ++ (Inkrement). Beide haben die gleiche Priorität und überprüfen dann die Assoziativität von R zu L. Beginnen Sie also mit der Lösung von rechts nach links, unabhängig davon, welche Operatoren zuerst kommen.

* ptr ++ : Das erste ++ kam beim Lösen von R nach L, daher wird die Adresse erhöht, aber das Post-Inkrement.

* ++ ptr : Wie die erste hier wird auch die Adresse inkrementiert, aber ihre Vorinkrementierung.

* (ptr ++) : Hier gibt es 3 Operatoren, darunter grouping () mit der höchsten Priorität. Also wird zuerst ptr ++ gelöst, dh die Adresse wird erhöht, aber veröffentlicht.

* (++ ptr) : Wie im obigen Fall wird auch hier die Adresse inkrementiert, jedoch vor dem Inkrementieren.

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

oben erwähnt sind alle 4 Syntax ähnlich, in allen Wert / Daten werden erhöht, aber wie sich der Wert ändert, ist unterschiedlich.

++ * ptr : first * kam beim Lösen von R nach L, daher wird der Wert geändert, aber sein Vorinkrement.

++ (* ptr) : Wie im obigen Fall wird der Wert geändert.

(* ptr) ++ : Hier gibt es 3 Operatoren, darunter grouping () mit der höchsten Priorität. Inside () * ptr ist da. Also wird zuerst * ptr gelöst, dh der Wert wird erhöht, aber post.

Hinweis : ++ * ptr und * ptr = * ptr + 1 sind beide gleich, in beiden Fällen wird der Wert geändert. ++ * ptr: Es wird nur 1 Befehl (INC) verwendet, der direkte Wert wird in einem einzigen Schuss geändert. * ptr = * ptr + 1: Hier wird der erste Wert erhöht (INC) und dann zugewiesen (MOV).

Um alle oben genannten unterschiedlichen Syntaxen des Inkrements auf dem Zeiger zu verstehen, betrachten wir einfachen Code:

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

Versuchen Sie im obigen Code, Kommentare zu kommentieren / zu entfernen und die Ergebnisse zu analysieren.

Zeiger als Konstante : Es gibt keine Möglichkeit, Zeiger als Konstante zu setzen, nur wenige erwähne ich hier.

1) const int * p ODER int const * p : Hier valueist konstant , Adresse ist nicht konstant, dh wohin zeigt p? Eine Adresse? Was ist an dieser Adresse der Wert? Ein Wert, oder? Dieser Wert ist konstant. Sie können diesen Wert nicht ändern, aber wohin zeigt der Zeiger? Eine Adresse richtig? Es kann auch auf eine andere Adresse verweisen.

Um dies zu verstehen, betrachten wir den folgenden Code:

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

Versuchen Sie, die Ausgabe des obigen Codes zu analysieren

2) int const * p : es heißt ' **constant pointe**r' dh address is constant but value is not constant. Hier dürfen Sie die Adresse nicht ändern, aber Sie können den Wert ändern.

Hinweis : Der konstante Zeiger (siehe oben) muss initialisiert werden, während er sich selbst deklariert.

Um dies zu verstehen, überprüfen wir einfachen Code.

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

Wenn Sie im obigen Code feststellen, dass es kein ++ * p oder * p ++ gibt, haben Sie vielleicht gedacht, dass dies ein einfacher Fall ist, da wir die Adresse oder den Wert nicht ändern, dies jedoch zu Fehlern führen wird. Warum ? Grund erwähne ich in Kommentaren.

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

Was ist die Lösung dieses Problems?

     int* const p = &x;

Weitere Informationen zu diesem Fall finden Sie im folgenden Beispiel.

#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 : Hier sind sowohl Adresse als auch Wert konstant .

Um dies zu verstehen, überprüfen Sie den folgenden Code

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

++*pbedeutet , dass Sie versuchen , den ASCII - Wert zu erhöhen , *pwelche

   is "Hello"
       ^
       | 
       p

Sie können den Wert nicht erhöhen, da es sich um eine Konstante handelt, sodass ein Fehler angezeigt wird

Bei Ihrer while-Schleife wird die Schleife bis *p++zum Ende der Zeichenfolge ausgeführt, an der sich ein '\0'(NULL-) Zeichen befindet.

Da *p++Sie nun das erste Zeichen überspringen, erhalten Sie Ihre Ausgabe erst ab dem zweiten Zeichen.

Der folgende Code gibt nichts aus, da while-Schleife hat '\0'

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

Der folgende Code gibt Ihnen die gleiche Ausgabe wie der nächste Code, dh ello.

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

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

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