Bir fark var mı ++i
ve i++
bir de for
döngü? Bu sadece bir sözdizimi midir?
Bir fark var mı ++i
ve i++
bir de for
döngü? Bu sadece bir sözdizimi midir?
Yanıtlar:
a ++ postfix olarak bilinir.
a 1 eklenirse eski değeri döndürür.
++ a öneki olarak bilinir.
a 1 eklenirse, yeni değer döndürülür.
C #:
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");
i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}
Çıktı:
1
2
3
4
0
1
2
3
foreach
ve while
döngüler kullandığınız artış türüne bağlıdır. Aşağıdaki gibi döngüler için, i'nin dönüş değerini kullanmıyorsanız fark etmez:
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }
0 1 2 3 4
0 1 2 3 4
Değerlendirildiği şekliyle değer kullanılırsa, artışın türü anlamlı hale gelir:
int n = 0;
for (int i = 0; n < 5; n = i++) { }
Ön artış ++ i , i değerini artırır ve yeni artan değere göre değerlendirir.
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
Artış sonrası i ++ , i değerini artırır ve orijinal artmamış değere göre değerlendirir.
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
C ++ 'da, her ikisini de kullanabileceğiniz yerlerde genellikle ön artış tercih edilir.
Çünkü artım sonrası kullanırsanız, derleyicinin fazladan bir geçici değişken oluşturan kod üretmesi gerekebilir. Bunun nedeni, artırılan değişkenin hem önceki hem de yeni değerlerinin bir yerde tutulması gerektiğidir, çünkü değerlendirilmekte olan ifadede başka bir yere ihtiyaç duyulabilir.
Yani, en azından C ++ 'da, hangisini kullanacağınıza karar veren bir performans farkı olabilir.
Bu, yalnızca artırılan değişken, geçersiz kılınmış bir ++ işlecine sahip kullanıcı tanımlı bir tür olduğunda yalnızca bir sorundur. İlkel tipler (int, vb.) İçin performans farkı yoktur. Ancak, artım sonrası operatör kesinlikle gerekli olmadığı sürece, ön artış operatörüne bir kılavuz olarak bağlı kalmaya değer.
Burada daha fazla tartışma var:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
C ++ 'da STL kullanıyorsanız yineleyiciler ile döngüler için kullanıyor olabilirsiniz. Bunlar esas olarak geçersiz kılınmış ++ operatörlerine sahiptir, bu nedenle ön artışa bağlı kalmak iyi bir fikirdir. Derleyiciler her zaman daha akıllı hale gelir ve daha yenileri performans farkı olmadığı anlamına gelen optimizasyonlar gerçekleştirebilir - özellikle artırılan tür başlık dosyasında satır içi olarak tanımlanırsa (STL uygulamaları sıklıkla olduğu gibi) yöntem uygulanır ve daha sonra hangi optimizasyonların güvenli bir şekilde gerçekleştirilebileceğini bilir. Yine de, büyük olasılıkla hala artmaya devam etmeye değer çünkü döngüler birçok kez idam edilir ve bu da küçük bir performans cezasının yakında yükseltilebileceği anlamına gelir.
++ operatörünün aşırı yüklenemediği C # gibi diğer dillerde performans farkı yoktur. Döngü değişkenini ilerletmek için bir döngüde kullanıldığında, öncesi ve sonrası artış işleçleri eşdeğerdir.
Düzeltme: C # 'da aşırı yüklenmeye ++ izin verilir. Görünüşe göre, C ++ ile karşılaştırıldığında, c # 'da ön ve son sürümleri bağımsız olarak aşırı yükleyemezsiniz. Bu nedenle, C # 'da ++ çağrılmasının sonucu bir değişkene atanmamışsa veya karmaşık bir ifadenin parçası olarak kullanılmamışsa, derleyicinin ++ öncesi ve sonrası sürümlerini eşdeğer performans gösteren koda indirgeyeceğini varsayarım.
C # 'da bir for döngüsünde kullanıldığında fark yoktur .
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
ile aynı şeyi çıktılar
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
Diğerlerinin belirttiği gibi, genel olarak i ++ ve ++ kullanıldığında ince ama önemli bir fark var:
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++, i'nin değerini okur ve sonra artırır.
++ i i değerini artırır sonra okur.
++i
ve i++
aynı sırada aynı işlemleri gerçekleştirin: Geçici kopya ait oluşturmak i
; yeni bir değer üretmek için sıcaklık değerini arttırın (sıcaklığı geçersiz kılmamak için); yeni değeri i
; şimdi ++i
sonuç döndürülürse yeni değer; o ise i++
iade sonuç geçici kopyasıdır. Burada daha ayrıntılı cevap: stackoverflow.com/a/3346729/3330348
Soru:
Bir for döngüsünde ++ i ve i ++ 'da bir fark var mı?
Cevap: Hayır .
Neden her soru cevaplanmasa bile, ön ve son artışlarla ilgili ayrıntılı açıklamalara gitmek zorunda kalıyor?
Bu döngü için:
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
Döngüler kullanmadan bu koda çevirirsiniz:
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
Şimdi buraya koymanız i++
veya ++i
artırmanız önemli mi? Hayır , arttırma işleminin dönüş değeri önemsiz olduğu için değildir. i
kodun for döngüsü gövdesi içindeki yürütme SONRASI artırılacaktır.
Bir döngüdeki farkı sorduğunuz için, sanırım demek istediniz
for(int i=0; i<10; i++)
...;
Bu durumda, çoğu dilde fark vardır: döngü olursa olsun yazdığınız bakılmaksızın aynı şekilde davranır i++
ve ++i
. C ++ ile, ++ işleçlerinin kendi sürümlerini yazabilir ve i
kullanıcı tanımlı türdeyse (örneğin kendi sınıfınız) onlar için ayrı anlamlar tanımlayabilirsiniz .
Yukarıda önemli olmasının nedeni, değerini kullanmamanızdır i++
. Başka bir şey,
for(int i=0, a = 0; i<10; a = i++)
...;
Şimdi, bir diğerleri, işaret ettiği gibi, çünkü bir fark, i++
aracı artırmak, ancak önceki değerine değerlendirmek , ama ++i
aracı artış, ancak değerlendirmeki
(böylece yeni değere değerlendirmek olacaktır). Yukarıdaki durumda, a
i artırılırken i'nin önceki değeri atanır.
Bu kodun gösterdiği gibi (yorumlarda kaldırılmış MSIL'e bakın), C # 3 derleyicisi bir for döngüsünde i ++ ve ++ i arasında bir ayrım yapmaz. İ ++ veya ++ i değeri alınıyor olsaydı, kesinlikle bir fark olurdu (bu Visutal Studio 2008 / Release Build'da derlendi):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PreOrPostIncrement
{
class Program
{
static int SomethingToIncrement;
static void Main(string[] args)
{
PreIncrement(1000);
PostIncrement(1000);
Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
}
static void PreIncrement(int count)
{
/*
.method private hidebysig static void PreIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PreIncrement
*/
for (int i = 0; i < count; ++i)
{
++SomethingToIncrement;
}
}
static void PostIncrement(int count)
{
/*
.method private hidebysig static void PostIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PostIncrement
*/
for (int i = 0; i < count; i++)
{
SomethingToIncrement++;
}
}
}
}
Bir (++ i) ön bölge, bir (i ++) ön bölge. Fark, ifadeden hemen döndürülen değerdir.
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1
Düzenleme: Woops, şeylerin döngü tarafını tamamen görmezden geldi. 'Adım' kısmı ((...; ...;)) olduğunda döngüler için gerçek bir fark yoktur, ancak diğer durumlarda devreye girebilir.
Döngüdeki artıştan sonra değeri kullanmıyorsanız fark yoktur.
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
Her iki döngü de 0123 yazdıracaktır.
Ancak fark, döngünüzdeki artış / azalmadan sonraki değeri aşağıdaki gibi kullandığınızda ortaya çıkar:
Artış Öncesi Döngü:
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
Çıktı: 0 0 1 1 2 2 3 3
Artış Sonrası Döngü:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
Çıktı: 0 0 1 0 2 1 3 2
Umarım çıktıyı karşılaştırarak fark açıktır. Burada dikkat edilmesi gereken nokta, artışın / azalmanın her zaman for döngüsünün sonunda gerçekleştirilmesidir ve bu nedenle sonuçlar açıklanabilir.
İşte bir Java Örneği ve Byte Kodu, post ve preIncrement Bytecode'da fark göstermiyor:
public class PreOrPostIncrement {
static int somethingToIncrement = 0;
public static void main(String[] args) {
final int rounds = 1000;
postIncrement(rounds);
preIncrement(rounds);
}
private static void postIncrement(final int rounds) {
for (int i = 0; i < rounds; i++) {
somethingToIncrement++;
}
}
private static void preIncrement(final int rounds) {
for (int i = 0; i < rounds; ++i) {
++somethingToIncrement;
}
}
}
Ve şimdi bayt kodu için (javap -private -c PreOrPostIncrement):
public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;
static {};
Code:
0: iconst_0
1: putstatic #10; //Field somethingToIncrement:I
4: return
public PreOrPostIncrement();
Code:
0: aload_0
1: invokespecial #15; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: sipush 1000
3: istore_1
4: sipush 1000
7: invokestatic #21; //Method postIncrement:(I)V
10: sipush 1000
13: invokestatic #25; //Method preIncrement:(I)V
16: return
private static void postIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
private static void preIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
}
Evet var. Fark, dönüş değerindedir. "++ i" nin dönüş değeri, i'nin artırılmasından sonraki değer olacaktır . Dönüşü "i ++" değeri olacaktır önce artan. Bu, aşağıdaki gibi görünen kod anlamına gelir:
int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.
Bu nedenle, a 2, b ve c'nin her biri 1 olacaktır.
Ben böyle kodu yeniden yazabilirsiniz:
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
Her iki durumda da gerçek bir fark yoktur ' i
' 1 ile artırılacaktır.
Ancak bir ifadede kullandığınızda bir fark vardır, örneğin:
int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3
Döngülerden ve performans farklılıklarından daha fazla ++ i ve i ++ vardır. ++ i bir l değeri döndürür ve i ++ bir r değeri döndürür. Buna dayanarak, (++ i) için yapabileceğiniz, ancak (i ++) için yapabileceğiniz pek çok şey vardır.
1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:
T& operator ++ ( )
{
// logical increment
return *this;
}
const T operator ++ ( int )
{
T temp( *this );
++*this;
return temp;
}
Neden aklımı boğdur ki insanlar for-loop'ta artış ifadesini i ++ olarak yazabilir?
For-loop'ta, 3. bileşen basit bir artış ifadesi olduğunda,
for (i=0; i<x; i++)
veya
for (i=0; i<x; ++i)
sonuçta gerçekleşen infazlarda bir fark yoktur.
As @Jon B diyor, döngü için hiçbir fark yoktur.
Ancak bir while
veya do...while
döngüsünde, ++i
veya ile karşılaştırma yapıyorsanız bazı farklılıklar bulabilirsiniz.i++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
Aşağıdaki i ++ nedeniyle javascript kullanmak daha iyi olabilir:
var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.
Diziler (sanırım hepsi) ve diğer bazı işlevler ve çağrılar başlangıç noktası olarak 0'ı kullanırken, döngüyü ++ i kullanırken dizi ile çalışmasını sağlamak için i'yi -1 olarak ayarlamanız gerekir .
İ ++ kullanırken aşağıdaki değer, artırılmış değeri kullanır. İ ++ diyebilirsin , insanlar sayılır, çünkü 0 ile başlayabilirsin .
FOR döngüsünün ne yaptığını anlamak için
Bu gösterileri Yukarıdaki görüntü İÇİN dönüştürülebilir WHILE'den en sonunda tamamen (en azından gcc'deki) aynı montaj kodu var gibi. Biz aşağı kırabilir Yani İÇİN parçalar bir çift içine, ne yaptığını undertand.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
WHILE sürümüne eşittir
i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}
Size kullanabileceğiniz anlamına gelir FOR basit bir versiyonu olarak WHILE'den :
FOR (int i) 'nin ilk argümanı dışarıda döngüden önce yürütülür.
FOR (i ++ veya ++ i) öğesinin üçüncü argümanı , içeride, döngünün son satırında yürütülür .
TP: DR: olursa olsun ister
i++
ya++i
, biz onlar bağımsız olduklarında kendileri üzerinde hiçbir fark ama +1 yapmak biliyoruz.Okulda, genellikle i ++ yolunu öğretmek, ama bir sürü insan dolayı orada da ++ i yolu tercih ettiklerini göstermektedir çeşitli nedenlerden .
NOT: Geçmişte, i ++ 'ın performans üzerinde çok az etkisi vardır, çünkü yalnızca tek başına artı değil, aynı zamanda orijinal değeri kayıt defterinde tutar. Ancak şimdilik, derleyici artı bir parçayı aynı kıldığından hiçbir fark yaratmıyor.
Döngüler için bir fark olabilir. Bu, post / artımın pratik uygulamasıdır.
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
İlki 11'e ve 11 kez döngüye girerken, ikincisi sayılmaz.
Çoğunlukla bu basit bir süre kullanılır (x--> 0); - - Örneğin, bir dizinin tüm öğelerini yinelemek için döngü yapın (burada foreach-build'ler hariç).
Her ikisi de sayıyı arttırır. ++i
eşittir i = i + 1
.
i++
ve ++i
çok benzer ancak tam olarak aynı değil. Her ikisi de sayıyı artırır, ancak ++i
geçerli ifade değerlendirilmeden önce sayıyı i++
artırır, ifade ifade edildikten sonraki sayıyı artırır.
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =
Bu bağlantıyı kontrol edin .
Evet, olağandışı kullanım durumlarında olsa da, bir döngü içinde ++i
ve i++
bir for
döngü arasında bir fark vardır ; for bloğunda veya döngü testi ifadesinde artış / azalma operatörüne sahip bir döngü değişkeni veya döngü değişkenlerinden biri ile kullanıldığında . Hayır, sadece bir sözdizimi işi değildir.
i
Bir kodda olduğu gibi ifadeyi değerlendirmek anlamına gelir i
ve operatör bir değerlendirme değil, sadece bir işlem anlamına gelir;
++i
değeri i
1 artar ve daha sonra değerlendirir i
,i++
" 1" i
değerini değerlendirmek ve daha sonra değerini artırmak anlamına gelir i
.Dolayısıyla, her iki ifadeden elde edilenler farklılık gösterir, çünkü değerlendirilenler her birinde farklılık gösterir. Aynı Hepsi --i
vei--
Örneğin;
let i = 0
i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2
Olağandışı kullanım durumlarında, ancak bir sonraki örnek yararlı görünüyor veya önemli değil, bir fark gösteriyor
for(i=0, j=i; i<10; j=++i){
console.log(j, i)
}
for(i=0, j=i; i<10; j=i++){
console.log(j, i)
}
İçin i
'kullanıcı tanımlı türleri s, bu operatörler (could ama olmamalı ) bir döngü indeksi bağlamında anlamlı farklar sematics sahiptir ve bu (ancak olmamalıdır) döngü davranışı tarif etkileyebilir.
Ayrıca, daha kolay bir şekilde optimize edilebildiğinden, c++
artım öncesi formu ( ++i
) kullanmak genellikle en güvenlidir. (Scott Langham beni bu çöplükte dövdü . Lanet olsun, Scott)
Ben diğer diller için bilmiyorum ama Java ++ i bir olduğunu önek artım hangi araçlar: artırmak i 1 ile ve daha sonra hangi ifadesinde i yeni bir değer kullanmak i bulunduğu ve ben ++ bir olan sonek artışı şu demektir : ifadede i'nin geçerli değerini kullanın ve ardından 1 ile artırın. Örnek:
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} ve çıktı: