C: ++ i ve i ++ arasındaki fark nedir?


888

C, kullanma arasındaki fark ne ++ive i++ve hangi bir artırılmaz blok kullanılmalıdır fordöngü?


10
Orijinal posterin ilgilendiğinden emin değilim, ancak C ++ 'da performans farkı önemli olabilir, çünkü geçici nesnenin oluşturulması kullanıcı tanımlı bir tür için pahalı olabilir.
Freund'da

Yanıtlar:


1100
  • ++ideğerini artırır ive sonra da artan değeri döndürür.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
  • i++değerini artırır i, ancak iartırılmadan önce tutulan orijinal değeri döndürür .

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

Bir fordöngü için her ikisi de çalışır. ++ibelki de K & R'de kullanılan şey budur .

Her durumda, "tercih kılavuz takip ++iüzerinde i++" ve yanlış gitmeyecek.

Verimliliğini ilgili yorumların bir çift var ++ive i++. Öğrenci olmayan proje derleyicilerinde performans farkı olmayacaktır. Aynı olacak oluşturulan koda bakarak bunu doğrulayabilirsiniz.

Verimlilik sorusu ilginç ... İşte benim yanıtımdaki girişim: C'de i ++ ve ++ i arasında bir performans farkı var mı?

Şöyle @OnFreund yana notları, bu C ++ nesne için farklı operator++()bir fonksiyonudur ve derleyici ara değer tutmak için geçici bir nesne oluşturma uzak optimize bilemez.


6
Bu etki hava durumu, son duruma ulaşıldığında bir kez daha çalışır mı? Örneğin, for(int i=0; i<10; i++){ print i; } bu for(int i=0; i<10; ++i){ print i; } benim anlayışımdan farklı olmayacak mı, bazı diller kullandığınız şekle bağlı olarak size farklı sonuçlar verecektir.
aVeRTRAC

27
jonnyflash, her ikisi de aynı şekilde çalışacaktır, çünkü i ve baskının artışı farklı ifadelerdedir. Bu, C stili ++ 'ı destekleyen herhangi bir dil için geçerli olmalıdır. ++ i ve i ++ arasındaki tek fark, işlemin değerini aynı ifadede kullanırken olacaktır.
Mark Harrison

16
Çoğu durumda özdeş kod ürettiklerinden i++dolayı, "işlenen-işleç" biçiminde, "işlenen-işleç-değer" ataması şeklinde tercih ederim . Başka bir deyişle, hedef işlenen, tıpkı bir atama ifadesinde olduğu gibi ifadenin sol tarafındadır.
David R Tribble

2
@MarkHarrison, bu aynı şekilde çalışıp çalışmadığını çünkü edecek i++ve print ifarklı tablolara, ancak çünkü i++;ve i<10vardır. @ jonnyflash'ın sözleri bu tabandan değil. Varsayalım for(int i=0; i++<10){ print i; }ve for(int i=0; ++i<10){ print i; }. Bunlar, @johnnyflash'ın ilk yorumda açıklanan şekilde farklı şekilde çalışacaktır.
Adam

3
@sam, çünkü tipik bir döngü için ++ i bölümünde hiçbir yan etki (örneğin atama) yoktur.
Mark Harrison

175

i ++ , Artış Sonrası olarak bilinirken, ++ i'ye Ön Artış denir .

i++

i++iişlem bittikten sonra değerini 1 artırır, çünkü işlem bittikten sonra değerini 1 artırır .

Aşağıdaki örneğe bakalım:

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

Burada j = 1ama değeri i = 2. Burada değeri iönce atanacak jsonra iartırılacaktır.

++i

++iioperasyondan önce değerini 1 arttırdığı için ön artıştır . j = i;Sonra yürütülecek demektir i++.

Aşağıdaki örneğe bakalım:

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

Burada j = 2ama değeri i = 2. Burada değeri, değerinin artırılmasından sonra iatanacaktır . Benzer şekilde daha önce icra edilecektir .jii++ij=i;

Sorunuz için bir for döngüsünün artış bloğunda hangisi kullanılmalıdır? cevap, herhangi birini kullanabilirsiniz .. önemli değil. Aynı döngü için for yürütecek. kez.

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

Ve

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

Her iki döngü de aynı çıktıyı üretecektir. yani 0 1 2 3 4.

Sadece nerede kullandığınız önemlidir.

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

Bu durumda çıktı olacaktır 1 2 3 4 5.


1
Önek ve düzeltme sonrası değişkenlerin başlatılması anlamaya yardımcı olur. Teşekkürler.
Abdul Alim Shakir

42

Lütfen daha hızlı olan "verimlilik" (hız, gerçekten) konusunda endişelenmeyin. Bugünlerde bu şeylerle ilgilenen derleyicilerimiz var. Niyetinizi daha açık bir şekilde gösteren, hangisinin kullanılması mantıklı olursa kullanın.


1
ki, umarım, çok az insanın yaptığı (inc | dec) öncesinde eski değere ihtiyacınız yoksa ve yine de sözde öğretim materyallerinin şaşırtıcı bir oranının kullanıldığı sürece ' kullanım öneki (inc | dec) rement anlamına gelir , ne olduğunu bile bilmeyen postfix kullanıcılarının kargo kültünün yaratılması '..!
underscore_d

"Bugünlerde derleyiciler ... bu şeylerle ilgilen" in evrensel olarak doğru olduğundan emin değilim. Bir özel operator++(int)(postfix sürümü) içinde kodun hemen hemen döndürülecek bir geçici oluşturması gerekir. Derleyicilerin bunu her zaman optimize edebileceğinden emin misiniz?
Peter - Monica'yı

36

++i değeri artırır, sonra döndürür.

i++ değeri döndürür ve sonra artırır.

İnce bir fark.

For döngüsü için, ++ibiraz daha hızlı olduğu için kullanın . i++sadece atılan ekstra bir kopya oluşturur.


23
En azından tamsayılar için bir fark yaratan herhangi bir derleyicinin farkında değilim.
blabla999

4
Daha hızlı değil . Değerler yok sayılır (yalnızca yan etki etkilidir) ve derleyici tam olarak aynı kodu üretebilir / üretebilir.
wildplasser

31

i++: Bu senaryoda önce değer atanır ve sonra artış olur.

++i: Bu senaryoda önce artış yapılır ve sonra değer atanır

Aşağıda görüntü görselleştirme ve burada da aynı şeyi gösteren güzel bir pratik video var.

resim açıklamasını buraya girin


Atanmamış bir şekilde nasıl arttırabilirsiniz?
kouty

@kouty Bir değişkene atanmamış bir kaydı artırabilirsiniz.
Polluks

20

Nedeni ++i olabilir biraz daha hızlı olması i++DİR i++o artırılır hale geçmeden iken, i değerinin yerel bir kopyasını gerektirebilir ++iyapmaz. Bazı durumlarda, bazı derleyiciler mümkünse onu optimize eder ... ancak her zaman mümkün değildir ve tüm derleyiciler bunu yapmaz.

Derleyici optimizasyonlarına çok fazla güvenmemeye çalışıyorum, bu yüzden Ryan Fox'un tavsiyelerine uyuyorum: her ikisini de kullanabildiğimde kullanıyorum ++i.


11
C sorusuna C ++ yanıtı için -1. iBir ifade yazdığınızda değerin "yerel kopyası" diye bir değer kalmaz 1;.
R .. GitHub BUZA YARDIMCI DURDUR

14

Bir döngüde kullanılmasının etkili sonucu aynıdır. Başka bir deyişle, döngü her iki durumda da aynı şeyi yapar.

Verimlilik açısından, ++ i üzerinden i ++ seçimi ile ilgili bir ceza olabilir. Dil spesifikasyonu açısından, artım sonrası operatörünün kullanılması, operatörün hareket ettiği değerin fazladan bir kopyasını oluşturmalıdır. Bu, fazladan bir işlem kaynağı olabilir.

Ancak, önceki mantıkla ilgili iki ana sorunu göz önünde bulundurmalısınız.

  1. Modern derleyiciler harika. Tüm iyi derleyiciler, for-loop'ta bir tamsayı artışı gördüğünü anlayacak kadar akıllıdır ve her iki yöntemi de aynı verimli koda optimize edecektir. Artım öncesi artış sonrası kullanmak aslında programınızın daha yavaş çalışma süresine neden oluyorsa, korkunç bir derleyici kullanıyorsunuz demektir .

  2. Operasyonel zaman karmaşıklığı açısından, iki yöntem (bir kopya gerçekte yapılsa bile) eşdeğerdir. Döngü içinde gerçekleştirilen talimat sayısı, arttırma işlemindeki işlem sayısına önemli ölçüde hakim olmalıdır. Bu nedenle, önemli boyuttaki herhangi bir döngüde, artış yönteminin cezası, döngü gövdesinin yürütülmesi ile büyük ölçüde gölgede bırakılacaktır. Başka bir deyişle, kodu artımdan ziyade döngüdeki optimize etme konusunda endişelenmeniz çok daha iyidir.

Benim düşünceme göre, tüm sorun sadece bir stil tercihine bağlı. Ön artışın daha okunabilir olduğunu düşünüyorsanız, onu kullanın. Şahsen, artımı sonrası tercih ederim, ancak bunun nedeni muhtemelen optimizasyon hakkında bir şey bilmeden önce bana öğretilen şeydi.

Bu, erken optimizasyonun özet bir örneğidir ve bunun gibi sorunlar, bizi tasarımdaki ciddi sorunlardan uzaklaştırma potansiyeline sahiptir. Bununla birlikte, hala sorulması iyi bir soru, çünkü "en iyi uygulamada" kullanımda tekdüze veya fikir birliği yoktur.


13

Her ikisi de sayıyı arttırır. ++ieşittir i = i + 1.

i++ve ++içok benzer ancak tam olarak aynı değil. Her ikisi de sayıyı artırır, ancak ++igeçerli ifade değerlendirilmeden önce sayıyı i++artırır, ifade ifade edildikten sonraki sayıyı artırır.

Misal:

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

8

++i(Önek çalışma): o artımlarla ve değer atar
(örneğin) int i = 5, int b = ++i bu durumda, 6, 7 ve böylece ilk ve sonra artışlarla b atanır.

i++(Postfix'i çalışma): o atar ve değerini artırır
(örneğin) int i = 5, int b = i++ bu durumda, 5, 6 ve bu şekilde birinci ve daha sonra artışlarla b atanır.

For loop i++örneği : çoğunlukla kullanılır, çünkü normalde for döngüsünü artırmadan iönce başlangıç ​​değerini kullanırız . Ancak program mantığınıza bağlı olarak değişebilir.


7

++i: artış öncesi diğeri artış sonrası.

i++: öğeyi alır ve sonra artırır.
++i: i değerini artırır ve öğeyi döndürür.

Misal:

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

Çıktı:

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

5

Semantikteki farkı şimdi anladığınızı varsayıyorum (dürüst olmak gerekirse, insanların neden okumak, bilirsiniz, bir kitap veya web öğreticisi veya başka bir şey yerine yığın taşması hakkında neden 'operatör X'in ne anlama geldiğini' 'sorduğunu merak ediyorum.

Ama yine de, hangisini kullanacağı kadarıyla, C ++ 'da bile olası olmayan performans sorularını göz ardı edin. Hangisini kullanacağınıza karar verirken kullanmanız gereken prensip budur:

Kodda ne demek istediğinizi söyleyin.

İfadenizde artımdan önceki değere ihtiyacınız yoksa, operatörün bu formunu kullanmayın. Bu küçük bir sorundur, ancak bir sürümü diğeri lehine yasaklayan bir stil kılavuzu ile çalışmadığınız sürece (kemik başlı stil kılavuzu olarak da bilinir), yapmaya çalıştığınız şeyi tam olarak ifade eden formu kullanmalısınız.

QED, artış öncesi sürümünü kullanın:

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

5

Fark aşağıdaki basit C ++ kodu ile anlaşılabilir:

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

Temel Fark:

  • i ++ Post ( Artıştan Sonra ) ve
  • ++ i Pre ( Arttırmadan Önce )

    • i =1 döngü aşağıdaki gibi artarsa1,2,3,4,n
    • öncesi i =1 döngü aşağıdaki gibi artarsa2,3,4,5,n

5

i ++ ve ++ i

Bu küçük kod, farkı önceden gönderilen cevaplardan farklı bir açıdan görselleştirmeye yardımcı olabilir:

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

Sonuç:

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

Önceki ve sonraki durumlara dikkat edin.

döngü için

Bunlardan hangisinin bir for döngüsünün artım bloğunda kullanılması gerektiğine göre, bir karar vermek için yapabileceğimiz en iyi şeyin iyi bir örnek kullanmak olduğunu düşünüyorum:

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

Sonuç:

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

Seni bilmiyorum, ama en azından bir for döngüsünde kullanımında herhangi bir fark görmüyorum.


5

Aşağıdaki C kodu parçası, öncesi ve sonrası artış ve azalma operatörleri arasındaki farkı gösterir:

int  i;
int  j;

Artış operatörleri:

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

4

Ön-krem aynı çizgide artış anlamına gelir. Artış sonrası, satır yürütüldükten sonra artış anlamına gelir.

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

OR VE VE operatörleri ile birlikte geldiğinde daha ilginç hale gelir.

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
}

Dizide

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
}

C ++ post / pointer değişkeninin ön artışı

#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

kısaca:

++ive i++bir işlevde yazmıyorsanız aynı şekilde çalışır. Gibi bir şey kullanırsanız function(i++)veya function(++i)farkı görebilirsiniz.

function(++i)ilk i i 1 'i arttırır, bundan sonra bunu iyeni değer ile fonksiyona sokar.

function(i++)1 ile ibu artıştan sonra ilk önce fonksiyona girdiğini söylüyor i.

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
Aradaki fark gerçekten fonksiyon çağrılarına bağlı değildir (ve fonksiyon çağrıları yapmadan farkı görebilirsiniz). Herhangi bir işlev çağrısı olmadığında int j = ++i;ve int k = i++;hatta aralarında bir fark vardır.
Jonathan Leffler

3

Tek fark, değişkenin artışı ile operatörün döndürdüğü değer arasındaki işlemlerin sırasıdır.

Bu kod ve çıktısı farkı açıklar:

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

Çıktı:

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

Temelde ++ideğeri artırıldıktan sonra döndürür, değeri artırılmadan ++iönce döndürür. Sonunda, her iki durumda da iiradenin değeri artırılır.

Başka bir örnek:

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

Çıktı:

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

Çoğu zaman fark yok

Döndürülen değeri bir değişken ya da arttırma işlemleri öncelik uygulandığı başka işlemler ile birleştirme gerçekleştirilir (zaman atandığında farklar açık i++*2farklıdır ++i*2, ancak (i++)*2ve (++i)*2bir çok durumda, aynı değere döner) kendi aralarında değiştirilebilir. Klasik bir örnek for döngüsü sözdizimidir:

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

aynı etkiye sahiptir

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

Hatırlama kuralı

İki operatör arasında kafa karışıklığı yaratmamak için bu kuralı kabul ettim:

Operatörün ++değişkene göre pozisyonunu , göreve göre operasyonun isırasına ++göre ilişkilendirin

Başka bir deyişle:

  • ++ önce i , atamadan önce artım yapılmalıdır ;
  • ++ sonra i araçların artırılması atamadan sonra yapılmalıdır :

3

Bunun içsel dönüşümünü birden çok ifade olarak düşünebilirsiniz ;

  • dava 1
i++;

olarak düşünebilirsiniz,

i;
i = i+1;
  • vaka 2
++i;

olarak düşünebilirsiniz,

i = i+i;
i;

-3

a = i ++, mevcut i değerini içeren anlamına gelir a = ++ i, artırılmış i değerini içeren anlamına gelir


10
Bu cevap doğru değil. a = i++;burada depolanan adeğerin i, artıştan önceki değer olacağı , ancak 'arttırmadan', iartırılmamış, yani tamamen yanlış olanın artırıldığı anlamına gelir i, ancak ifadenin değeri, artıştan önceki değerdir.
Jonathan Leffler

-6

İşte farkı anlamak için örnek

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

çıktı: 10 12/11 11( printfderleyiciler ve mimariler arasında değişen işleve yönelik argümanların değerlendirme sırasına bağlı olarak )

Açıklama: i++-> iyazdırılır ve sonra artar. (10 yazdırır, ancak i11 olur) ++i-> ideğer artar ve değeri yazdırır. (Baskı 12 ve ayrıca değeri i12)


11
i++Ve++i
MM

@Lundin doğru olsa da, LHS, RHS virgüllerinin aralarında sıralama noktası vardır, ancak 2 ifade hala birbirinden bağımsızdır
Antti Haapala
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.