C: Qual è la differenza tra ++ i e i ++?


888

In C, qual è la differenza tra l'utilizzo di ++ie i++, e quale dovrebbe essere usato nel blocco di incremento di un forciclo?


10
Non sono sicuro che il poster originale sia interessato, ma in C ++ la differenza nelle prestazioni può essere sostanziale, poiché la creazione dell'oggetto temporaneo potrebbe essere costosa per un tipo definito dall'utente.
Freund,

Risposte:


1101
  • ++iincrementerà il valore di ie quindi restituirà il valore incrementato.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
    
  • i++incrementerà il valore di i, ma restituirà il valore originale iconservato prima di essere incrementato.

     i = 1;
     j = i++;
     (i is 2, j is 1)
    

Per un forciclo, entrambi funzionano. ++isembra più comune, forse perché è quello che viene utilizzato in K&R .

In ogni caso, seguire le linee guida "preferiscono ++iover i++" e non andrà male.

Ci sono un paio di commenti sull'efficienza di ++ie i++. In qualsiasi compilatore per progetto non studente, non ci saranno differenze di prestazioni. Puoi verificarlo guardando il codice generato, che sarà identico.

La domanda di efficienza è interessante ... ecco il mio tentativo di risposta: c'è una differenza di prestazioni tra i ++ e ++ i in C?

Come osserva @OnFreund , è diverso per un oggetto C ++, poiché operator++()è una funzione e il compilatore non può sapere di ottimizzare la creazione di un oggetto temporaneo per contenere il valore intermedio.


6
Questo effetto non si ripercuoterà ancora una volta sul loop al raggiungimento della condizione finale? Ad esempio, for(int i=0; i<10; i++){ print i; } questo non sarà diverso dalla for(int i=0; i<10; ++i){ print i; } mia comprensione è che alcune lingue ti daranno risultati diversi a seconda di quale usi.
aVeRTRAC il

27
jonnyflash, entrambi funzioneranno in modo identico, poiché l'incremento di i e la stampa sono in dichiarazioni diverse. Questo dovrebbe essere il caso di qualsiasi linguaggio che supporti C-style ++. L'unica differenza tra ++ i e i ++ sarà quando si utilizza il valore dell'operazione nella stessa istruzione.
Mark Harrison,

16
Dato che nella maggior parte dei casi producono un codice identico, preferisco i++perché è nella forma "operando-operatore", come un "operando-operatore-valore". In altre parole, l'operando target si trova sul lato sinistro dell'espressione, proprio come in un'istruzione di assegnazione.
David R Tribble,

2
@MarkHarrison, funzionerà in modo identico non perché i++e print isiano in dichiarazioni diverse, ma perché i++;e lo i<10sono. L'osservazione di @ jonnyflash non è così off base. Supponiamo di avere for(int i=0; i++<10){ print i; }e for(int i=0; ++i<10){ print i; }. Funzioneranno diversamente nel modo descritto da @johnnyflash nel primo commento.
Adam,

3
@sam, perché in un tipico ciclo for non ci sono effetti collaterali (ad esempio, assegnazione) nella parte ++ i.
Mark Harrison,

175

i ++ è noto come Post Increment mentre ++ i è chiamato Pre Increment.

i++

i++è post incremento perché incrementa iil valore di 1 al termine dell'operazione.

Vediamo il seguente esempio:

int i = 1, j;
j = i++;

Qui valore di j = 1ma i = 2. Qui il valore di iverrà assegnato per jprimo, quindi iverrà incrementato.

++i

++iè pre-incremento perché incrementa iil valore di 1 prima dell'operazione. Significa che j = i;verrà eseguito dopo i++.

Vediamo il seguente esempio:

int i = 1, j;
j = ++i;

Qui valore di j = 2ma i = 2. Qui iverrà assegnato il valore di jdopo l' i incremento di i. Allo stesso modo ++iverrà eseguito prima j=i;.

Per la tua domanda quale dovrebbe essere usato nel blocco di incremento di un ciclo for? la risposta è che puoi usare chiunque .. non importa. Eseguirà il tuo ciclo for lo stesso no. di volte.

for(i=0; i<5; i++)
   printf("%d ",i);

E

for(i=0; i<5; ++i)
   printf("%d ",i);

Entrambi i loop produrranno lo stesso output. vale a dire 0 1 2 3 4.

Importa solo dove lo stai usando.

for(i = 0; i<5;)
    printf("%d ",++i);

In questo caso l'output sarà 1 2 3 4 5.


1
L'inizializzazione delle variabili dopo il prefisso e post-correzione aiuta a capire. Grazie.
Abdul Alim Shakir

42

Per favore, non preoccuparti dell '"efficienza" (velocità, davvero) di cui uno è più veloce. Oggi abbiamo compilatori che si occupano di queste cose. Usa quello che ha senso usare, in base al quale mostra più chiaramente le tue intenzioni.


1
che, spero, significa " usa il prefisso (inc | dec) rement a meno che tu non abbia effettivamente bisogno del vecchio valore prima di (inc | dec), che pochissime persone fanno, e che tuttavia una proporzione sconcertante di presunto materiale didattico usa, creando un culto del carico di utenti postfix che non sanno nemmeno cosa sia '..!
underscore_d

Non sono sicuro che "i compilatori in questi giorni ... prenditi cura di queste cose" è universalmente vero. All'interno di una versione personalizzata operator++(int)(la versione postfix) il codice deve praticamente creare un temporaneo che verrà restituito. Sei sicuro che i compilatori possano sempre ottimizzarlo?
Peter - Ripristina Monica

36

++i incrementa il valore, quindi lo restituisce.

i++ restituisce il valore e quindi lo incrementa.

È una differenza sottile.

Per un ciclo for, usa ++i, poiché è leggermente più veloce. i++creerà una copia extra che viene semplicemente gettata via.


23
Non sono a conoscenza di alcun compilatore in cui faccia almeno una differenza per gli interi.
blabla999,

4
Si tratta di non più veloce . I valori vengono ignorati (solo l'effetto collaterale è efficace) e il compilatore può / genererà esattamente lo stesso codice.
wildplasser,

31

i++: In questo scenario viene prima assegnato il valore e poi si verifica l'incremento.

++i: In questo scenario prima viene eseguito l'incremento e quindi viene assegnato il valore

Di seguito è riportata la visualizzazione delle immagini e anche qui è un bel video pratico che dimostra lo stesso.

inserisci qui la descrizione dell'immagine


Come si può incrementare un po 'non assegnato?
Kouty,

@kouty È possibile incrementare un registro non assegnato a una variabile.
Polluks,

20

Il motivo ++i può essere leggermente più veloce di quello i++che i++può richiedere una copia locale del valore di i prima che venga incrementato, mentre ++inon lo fa mai. In alcuni casi, alcuni compilatori lo ottimizzeranno se possibile ... ma non è sempre possibile, e non tutti i compilatori lo fanno.

Cerco di non fare troppo affidamento sulle ottimizzazioni dei compilatori, quindi seguirò i consigli di Ryan Fox: quando posso usare entrambi, li uso ++i.


11
-1 per la risposta C ++ alla domanda C. Non esiste più "copia locale" del valore di iquanto non lo sia del valore 1 quando si scrive un'istruzione 1;.
R .. GitHub smette di aiutare ICE il

14

Il risultato effettivo dell'uso di entrambi in un ciclo è identico. In altre parole, il loop farà la stessa cosa esatta in entrambi i casi.

In termini di efficienza, potrebbe esserci una penalità per la scelta di i ++ su ++ i. In termini di specifiche della lingua, l'uso dell'operatore post-incremento dovrebbe creare una copia aggiuntiva del valore su cui l'operatore agisce. Questo potrebbe essere una fonte di operazioni extra.

Tuttavia, è necessario considerare due problemi principali con la logica precedente.

  1. I compilatori moderni sono fantastici. Tutti i buoni compilatori sono abbastanza intelligenti da rendersi conto che sta vedendo un incremento intero in un ciclo for e ottimizzerà entrambi i metodi con lo stesso codice efficiente. Se l'uso di post-incremento su pre-incremento provoca effettivamente un tempo di esecuzione più lento del programma, allora stai usando un compilatore terribile .

  2. In termini di complessità temporale operativa, i due metodi (anche se una copia viene effettivamente eseguita) sono equivalenti. Il numero di istruzioni eseguite all'interno del loop dovrebbe dominare in modo significativo il numero di operazioni nell'operazione di incremento. Pertanto, in qualsiasi loop di dimensioni significative, la penalità del metodo di incremento verrà enormemente messa in ombra dall'esecuzione del corpo del loop. In altre parole, è molto meglio preoccuparsi di ottimizzare il codice nel ciclo piuttosto che l'incremento.

Secondo me, l'intera questione si riduce semplicemente a una preferenza di stile. Se ritieni che il pre-incremento sia più leggibile, allora usalo. Personalmente preferisco il post-incremento, ma probabilmente è perché era quello che mi era stato insegnato prima di sapere qualcosa sull'ottimizzazione.

Questo è un esempio per eccellenza di ottimizzazione prematura e problemi come questo hanno il potenziale per distrarci da gravi problemi di progettazione. È comunque una buona domanda da porre, poiché non vi è uniformità nell'uso o consenso nelle "migliori pratiche".


13

Entrambi incrementano il numero. ++iè equivalente a i = i + 1.

i++e ++isono molto simili ma non esattamente uguali. Entrambi incrementano il numero, ma ++iincrementa il numero prima che venga valutata l'espressione corrente, mentre i++incrementa il numero dopo la valutazione dell'espressione.

Esempio:

int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3

8

++i(Funzionamento prefisso): Si aggiunge quindi assegna il valore
(es): int i = 5, int b = ++i in questo caso, 6 viene assegnato B primo e poi lentamente per 7 e così via.

i++(Funzionamento Postfix): attribuisce e quindi incrementa il valore
(es): int i = 5, int b = i++ in questo caso, 5 appartiene alla B primo e poi lentamente per 6 e così via.

Incase di for loop: i++è usato principalmente perché, normalmente usiamo il valore iniziale di iprima di incrementare in for loop. Ma a seconda della logica del programma può variare.


7

++i: è pre-incremento l'altro è post-incremento.

i++: ottiene l'elemento e quindi lo incrementa.
++i: incrementa i e quindi restituisce l'elemento.

Esempio:

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

Produzione:

i: 0
i++: 0
++i: 2

5

Presumo che tu capisca la differenza nella semantica ora (anche se onestamente mi chiedo perché la gente faccia domande "cosa significa l'operatore X" sullo stack overflow piuttosto che leggere, sai, un libro o un tutorial web o qualcosa del genere.

Ma comunque, per quanto riguarda quello da usare, ignora le domande di prestazione, che sono improbabili importanti anche in C ++. Questo è il principio che dovresti usare quando decidi quale usare:

Dì cosa intendi nel codice.

Se non hai bisogno del valore prima dell'incremento nella tua dichiarazione, non utilizzare quella forma di operatore. È un problema minore, ma a meno che tu non stia lavorando con una guida di stile che vieta una versione a favore dell'altra (alias una guida di stile dalla testa d'osso), dovresti usare il modulo che esprime più esattamente ciò che stai cercando di fare.

QED, utilizzare la versione pre-incremento:

for (int i = 0; i != X; ++i) ...

5

La differenza può essere compresa da questo semplice codice C ++ di seguito:

int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;

5

La differenza principale è

  • i ++ Post ( dopo l'incremento ) e
  • ++ i Pre ( prima dell'incremento )

    • pubblica se i =1 il ciclo aumenta come1,2,3,4,n
    • pre se i =1 il ciclo aumenta come2,3,4,5,n

5

i ++ e ++ i

Questo piccolo codice può aiutare a visualizzare la differenza da un'angolazione diversa rispetto alle risposte già pubblicate:

int i = 10, j = 10;

printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);

printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);

Il risultato è:

//Remember that the values are i = 10, and j = 10

i is 10 
i++ is 10     //Assigns (print out), then increments
i is 11 

j is 10 
++j is 11    //Increments, then assigns (print out)
j is 11 

Prestare attenzione alle situazioni prima e dopo.

per loop

Per quanto riguarda quale di questi dovrebbe essere usato in un blocco di incremento di un ciclo for, penso che il meglio che possiamo fare per prendere una decisione sia usare un buon esempio:

int i, j;

for (i = 0; i <= 3; i++)
    printf (" > iteration #%i", i);

printf ("\n");

for (j = 0; j <= 3; ++j)
    printf (" > iteration #%i", j);

Il risultato è:

> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3 

Non ti conosco, ma non vedo alcuna differenza nel suo utilizzo, almeno in un ciclo for.


5

Il seguente frammento di codice C illustra la differenza tra gli operatori di incremento e decremento pre e post:

int  i;
int  j;

Incrementare gli operatori:

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2

4

Pre-crement significa incremento sulla stessa riga. Post-incremento significa incremento dopo l'esecuzione della riga.

int j=0;
System.out.println(j); //0
System.out.println(j++); //0. post-increment. It means after this line executes j increments.

int k=0;
System.out.println(k); //0
System.out.println(++k); //1. pre increment. It means it increments first and then the line executes

Quando si tratta di operatori OR, AND, diventa più interessante.

int m=0;
if((m == 0 || m++ == 0) && (m++ == 1)) { //false
/* in OR condition if first line is already true then compiler doesn't check the rest. It is technique of compiler optimization */
System.out.println("post-increment "+m);
}

int n=0;
if((n == 0 || n++ == 0) && (++n == 1)) { //true
System.out.println("pre-increment "+n); //1
}

In matrice

System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 } ;
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); //12

jj = a[1]++; //12
System.out.println(a[1]); //a[1] = 13

mm = a[1];//13
System.out.printf ( "\n%d %d %d\n", ii, jj, mm ) ; //12, 12, 13

for (int val: a) {
     System.out.print(" " +val); //55, 13, 15, 20, 25
}

In C ++ post / pre-incremento della variabile puntatore

#include <iostream>
using namespace std;

int main() {

    int x=10;
    int* p = &x;

    std::cout<<"address = "<<p<<"\n"; //prints address of x
    std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
    std::cout<<"address = "<<&x<<"\n"; //prints address of x

    std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}

4

In breve:

++ie i++funziona allo stesso modo se non li stai scrivendo in una funzione. Se usi qualcosa come function(i++)ofunction(++i) puoi vedere la differenza.

function(++i)dice il primo incremento i di 1, dopodiché mettilo inella funzione con un nuovo valore.

function(i++)dice messo prima inella funzione dopo quell'incremento idi 1.

int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now

2
La differenza non è realmente legata alle chiamate di funzione (e puoi individuare la differenza senza effettuare chiamate di funzione). C'è una differenza tra int j = ++i;e int k = i++;anche quando non è coinvolta alcuna chiamata di funzione.
Jonathan Leffler

3

L'unica differenza è l'ordine delle operazioni tra l'incremento della variabile e il valore restituito dall'operatore.

Questo codice e il suo output spiegano la differenza:

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  a = i++;
  printf("i before: %d; value returned by i++: %d, i after: %d\n", i, a, i);
  i=0;
  a = ++i;
  printf("i before: %d; value returned by ++i: %d, i after: %d\n", i, a, i);
}

L'output è:

i before: 1; value returned by i++: 0, i after: 1
i before: 1; value returned by ++i: 1, i after: 1

Quindi sostanzialmente ++irestituisce il valore dopo che è stato incrementato, mentre ++irestituisce il valore prima che sia incrementato. Alla fine, in entrambi i casi il ivalore sarà incrementato.

Un altro esempio:

#include<stdio.h>

int main ()
  int i=0;
  int a = i++*2;
  printf("i=0, i++*2=%d\n", a);
  i=0;
  a = ++i * 2;
  printf("i=0, ++i*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  return 0;
}

Produzione:

i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2

Molte volte non c'è differenza

Le differenze sono chiare quando il valore restituito viene assegnato a un'altra variabile o quando l'incremento viene eseguito in concatenazione con altre operazioni in cui viene applicata la precedenza delle operazioni ( i++*2è diversa da ++i*2, (i++)*2e (++i)*2restituisce lo stesso valore) in molti casi sono intercambiabili. Un esempio classico è la sintassi del ciclo for:

for(int i=0; i<10; i++)

ha lo stesso effetto di

for(int i=0; i<10; ++i)

Regola da ricordare

Per non creare confusione tra i due operatori ho adottato questa regola:

Associare la posizione dell'operatore ++rispetto alla variabile iall'ordine ++dell'operazione rispetto all'assegnazione

Detto in altre parole:

  • ++ prima i significa che l'incremento deve essere effettuato prima dell'incarico;
  • ++ dopo i significa che l'incremento deve essere effettuato dopo l' assegnazione:

3

Puoi pensare alla conversione interna di ciò come a più dichiarazioni ;

  • caso 1
i++;

puoi pensarlo come

i;
i = i+1;
  • caso 2
++i;

puoi pensarlo come

i = i+i;
i;

-3

a = i ++ indica che contiene un valore i corrente a = ++ i indica che contiene un valore i incrementato


10
Questa risposta non è precisa. a = i++;significa che il valore memorizzato asarà il valore iprima dell'incremento, ma "senza incremento" implica che inon viene incrementato, il che è completamente sbagliato - iviene incrementato, ma il valore dell'espressione è il valore prima dell'incremento.
Jonathan Leffler

-6

Ecco l'esempio per capire la differenza

int i=10;
printf("%d %d",i++,++i);

output: 10 12/11 11(a seconda dell'ordine di valutazione degli argomenti per la printffunzione, che varia tra compilatori e architetture)

Spiegazione: i++-> iviene stampato, quindi viene incrementato. (Stampa 10, ma idiventerà 11) ++i-> iincrementi di valore e stampa il valore. (Stampa 12 e valore ianche di 12)


11
Ciò causa un comportamento indefinito in quanto non vi è alcun punto di sequenza tra i++e++i
MM

@Lundin è corretto, tuttavia, l'LHS, l'RHS della virgola hanno un punto di sequenza tra loro, ma le 2 espressioni non sono ancora seguite l'una dall'altra
Antti Haapala,
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.