Unterschied zwischen * ptr + = 1 und * ptr ++ in C.

122

Ich habe gerade angefangen, C zu studieren, und als ich ein Beispiel für die Übergabe eines Zeigers an einen Zeiger als Funktionsparameter machte, fand ich ein Problem.

Dies ist mein Beispielcode:

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

Das Problem tritt in Zeile 16, wenn ich ändern *ptr+=1zu *ptr++. Das erwartete Ergebnis sollte das gesamte Array und die Nummer 1 sein, aber wenn ich *ptr++das Ergebnis verwende, ist es 0.

Gibt es einen Unterschied zwischen +=1und ++? Ich dachte, dass beide gleich sind.

huy nguyen
quelle
2
Beachten Sie, dass der angegebene Code nicht kompiliert wird, da Sie ihn nicht deklariert haben string.
Spikatrix
6
Andere Hinweise: 1) allocateIntArrayist ein schlechter Name, da es scheint, dass Sie mallocdas Array von der Funktion, aber Sie nicht. Ich schlage fillIntArraystattdessen vor. 2) Sie verwenden nicht den Rückgabewert von allocateIntArray. Ich schlage vor, Sie ändern den Rückgabetyp in void. 3) Sollte nicht if (ptr != NULL)in Funktion increasePointersein if (*ptr != NULL)? 4) Das mallocEingießen ist nicht erforderlich. Siehe Souravs Kommentar oben. 5) Dies: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }und printf("%d\n", *p1); p1--;muss beigefügt werden if(p1 != NULL). 6) string.hwird nicht verwendet.
Spikatrix
9
p+=1ist wie ++p, nicht wiep++
Kos
5
Diese Frage wurde vor 4 Jahren gestellt: Ist ++ das gleiche wie + = 1 für Zeiger
ren
3
@ren Fast, aber nicht ganz. Die verknüpfte Frage betrifft nicht den Dereferenzierungsoperator, der hier den Kern des OP-Problems darstellt.
Jason C

Antworten:

289

Der Unterschied ist auf die Priorität des Bedieners zurückzuführen.

Der Post-Inkrement-Operator ++hat eine höhere Priorität als der Dereferenzierungsoperator *. Ist *ptr++also gleichbedeutend mit *(ptr++). Mit anderen Worten, das Post-Inkrement ändert den Zeiger und nicht das, worauf er zeigt.

Der Zuweisungsoperator +=hat eine niedrigere Priorität als der Dereferenzierungsoperator *und *ptr+=1entspricht daher (*ptr)+=1. Mit anderen Worten, der Zuweisungsoperator ändert den Wert, auf den der Zeiger zeigt, und ändert den Zeiger selbst nicht.

user3386109
quelle
3
Für Anfänger ist eine Mnemonik die Ähnlichkeit zwischen *p++und *++p. Der Operator hat Vorrang vor letzterem, der erstere folgt.
Walter Tross
21

Die Rangfolge für die 3 an Ihrer Frage beteiligten Operatoren lautet wie folgt:

Post-Inkrement ++> Dereferenzierung *> Zuweisung+=

Sie können diese Seite für weitere Details zu diesem Thema überprüfen .

Beim Parsen eines Ausdrucks wird ein Operator, der in einer Zeile aufgeführt ist, enger (wie in Klammern) an seine Argumente gebunden als jeder Operator, der in einer Zeile weiter unten aufgeführt ist. Beispielsweise wird der Ausdruck *p++als *(p++)und nicht als analysiert (*p)++.

Um es kurz auszudrücken: Um diese Zuweisung *ptr+=1mit dem Post-Inkrement-Operator auszudrücken , müssen Sie dem Dereferenzierungsoperator Klammern hinzufügen, damit diese Operation Vorrang hat++ dieser hat(*ptr)++

Younes Regaieg
quelle
3
Interessanterweise ist dies derzeit die einzige Antwort, die Lösung enthält ... (* ptr) ++
hyde
7

Wenden wir Klammern an, um die Reihenfolge der Operationen anzuzeigen

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

Lass es uns nochmal machen mit

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

Und wieder mit

*ptr++
*(ptr++)
  • In *ptr += 1erhöhen wir den Wert der Variablen, auf die unser Zeiger zeigt .
  • In *ptr++erhöhen wir den Zeiger, nachdem unsere gesamte Anweisung (Codezeile) ausgeführt wurde, und geben einen Verweis auf die Variable zurück, auf die unser Zeiger zeigt .

Letzteres ermöglicht es Ihnen, Dinge zu tun wie:

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

Dies ist eine gängige Methode zum Kopieren eines srcArrays in ein anderes destArray.

Mateen Ulhaq
quelle
"und geben Sie einen Verweis auf die Variable zurück, auf die unser Zeiger zeigt." C hat keine Referenzen.
Miles Rout
@MilesRout Vielleicht ist es genauer, es als l-Wert zu bezeichnen? Aber ich bin mir nicht sicher, wie ich es ausdrücken soll, ohne Jargon hinzuzufügen.
Mateen Ulhaq
3

Sehr gute Frage.

In der Programmiersprache "C" von K & R "5.1 Zeiger und Adressen" können wir eine Antwort darauf erhalten.

"Die unären Operatoren * und & binden enger als arithmetische Operatoren"

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

"Unäre Operatoren wie * und ++ assoziieren von rechts nach links ."

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

// Es funktioniert wie * (ptr ++).

Der richtige Weg ist:

(*ptr)++      //This will work.
Nick.Sang
quelle
Dies ist das erste Mal, dass ich Stack Overflow kommentiere. Ich habe das Format des Codes aktualisiert. ^^ Vielen Dank für Ihren Vorschlag.
Nick.Sang
2

* ptr + = 1: Inkrementiere Daten, auf die ptr zeigt. * ptr ++: Inkrementiert den Zeiger, der auf den nächsten Speicherort zeigt, anstelle der Daten, auf die der Zeiger zeigt.

user5787482
quelle