Differenza tra * ptr + = 1 e * ptr ++ in C


123

Ho appena iniziato a studiare C e, facendo un esempio sul passaggio del puntatore al puntatore come parametro di una funzione, ho riscontrato un problema.

Questo è il mio codice di esempio:

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

Il problema si verifica nella riga 16, quando modifico *ptr+=1in *ptr++. Il risultato atteso dovrebbe essere l'intero array e il numero 1 ma quando uso *ptr++il risultato è 0.

C'è qualche differenza tra +=1e ++? Ho pensato che entrambi fossero la stessa cosa.


2
Nota che il codice fornito non verrà compilato come non hai dichiarato string.
Spikatrix

6
Altre note: 1) allocateIntArrayè un brutto nome in quanto sembra che tu sia mallocl'array dalla funzione, ma non lo fai. Suggerisco fillIntArrayinvece. 2) Non utilizzi il valore restituito di allocateIntArray. Ti suggerisco di cambiare il tipo di reso in void. 3) Non dovrebbe if (ptr != NULL)in funzione di increasePointeressere if (*ptr != NULL)? 4) Il cast non mallocè necessario. Vedi il commento di Sourav sopra. 5) Questo: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }e printf("%d\n", *p1); p1--;deve essere racchiuso in if(p1 != NULL). 6) string.hè inutilizzato.
Spikatrix

9
p+=1è come ++p, non comep++
Kos

5
questa domanda è stata posta 4 anni fa: ++ è uguale a + = 1 per i puntatori
ren

3
@ren Quasi, ma non del tutto. La domanda collegata non coinvolge l'operatore di dereferenziazione, che è il punto cruciale del problema dell'OP qui.
Jason C,

Risposte:


290

La differenza è dovuta alla precedenza degli operatori.

L'operatore di post-incremento ++ha una precedenza maggiore rispetto all'operatore di dereferenziazione *. Quindi *ptr++è equivalente a *(ptr++). In altre parole, l'incremento del post modifica il puntatore, non ciò a cui punta.

L'operatore di assegnazione +=ha una precedenza inferiore rispetto all'operatore di dereferenziazione *, quindi *ptr+=1è equivalente a (*ptr)+=1. In altre parole, l'operatore di assegnazione modifica il valore a cui punta il puntatore e non cambia il puntatore stesso.


3
Per i principianti, un mnemonico è la somiglianza tra *p++e *++p. La precedenza degli operatori del secondo è chiara, quella del primo segue.
Walter Tross

21

L'ordine di precedenza per i 3 operatori coinvolti nella tua domanda è il seguente:

post-incremento ++> dereferenziazione *> assegnazione+=

Puoi controllare questa pagina per ulteriori dettagli sull'argomento.

Quando si analizza un'espressione, un operatore elencato su una riga sarà legato più strettamente (come tra parentesi) ai suoi argomenti rispetto a qualsiasi operatore elencato su una riga più in basso. Ad esempio, l'espressione *p++viene analizzata come *(p++)e non come (*p)++.

Per farla breve, per esprimere questo compito *ptr+=1usando l'operatore di post-incremento è necessario aggiungere parentesi all'operatore di dereferenziazione per dare precedenza a tale operazione ++come in questo(*ptr)++


3
È interessante notare che questa è attualmente l'unica risposta che contiene la soluzione ... (* ptr) ++
hyde

7

Applichiamo le parentesi per mostrare l' ordine delle operazioni

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

Facciamolo di nuovo con

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

E ancora con

*ptr++
*(ptr++)
  • In *ptr += 1, incrementiamo il valore della variabile a cui punta il nostro puntatore .
  • In *ptr++, incrementiamo il puntatore dopo che l'intera istruzione (riga di codice) è terminata e restituiamo un riferimento alla variabile a cui punta il puntatore .

Quest'ultimo ti consente di fare cose come:

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

Questo è un metodo comune utilizzato per copiare un srcarray in un altro destarray.


"e restituisce un riferimento alla variabile a cui punta il puntatore." C non ha riferimenti.
Miglia in rotta

@MilesRout Forse chiamarlo lvalue potrebbe essere più accurato? Ma non sono sicuro di come metterlo senza aggiungere gergo.
Mateen Ulhaq

3

Domanda molto buona.

In K&R "linguaggio di programmazione C" "5.1 Puntatori e indirizzi", possiamo ottenere una risposta per questo.

"Gli operatori unari * e & si legano più strettamente degli operatori aritmetici"

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

"Gli operatori unari come * e ++ si associano da destra a sinistra ."

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

// Funziona come * (ptr ++).

Il modo corretto è:

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

Questa è la prima volta che commento su Stack Overflow. Ho aggiornato il formato del codice. ^^ Grazie per il tuo suggerimento.
Nick

2

* ptr + = 1: incrementa i dati a cui punta ptr. * ptr ++: puntatore di incremento che punta alla posizione di memoria successiva invece dei dati a cui punta il puntatore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.