Chciałbym inkrementować dwie zmienne w stanie for
-loop zamiast jednej.
Więc coś takiego:
for (int i = 0; i != 5; ++i and ++j)
do_something(i, j);
Jaka jest składnia tego?
Chciałbym inkrementować dwie zmienne w stanie for
-loop zamiast jednej.
Więc coś takiego:
for (int i = 0; i != 5; ++i and ++j)
do_something(i, j);
Jaka jest składnia tego?
Odpowiedzi:
Popularnym idiomem jest użycie operatora przecinka, który ocenia oba operandy i zwraca drugi operand. A zatem:
for(int i = 0; i != 5; ++i,++j)
do_something(i,j);
Po napisaniu tego komentator zasugerował, że jest to w rzeczywistości jakiś specjalny cukier składniowy w instrukcji for, a nie w ogóle operator przecinka. Sprawdziłem to w GCC w następujący sposób:
int i=0;
int a=5;
int x=0;
for(i; i<5; x=i++,a++){
printf("i=%d a=%d x=%d\n",i,a,x);
}
Spodziewałem się, że x podniesie oryginalną wartość a, więc powinno było wyświetlić 5,6,7 .. dla x. Dostałem to
i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3
Jeśli jednak ująłem wyrażenie w nawiasach, aby zmusić parser do rzeczywistego zobaczenia operatora przecinka, otrzymuję to
int main(){
int i=0;
int a=5;
int x=0;
for(i=0; i<5; x=(i++,a++)){
printf("i=%d a=%d x=%d\n",i,a,x);
}
}
i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8
Początkowo myślałem, że to pokazało, że nie zachowuje się on wcale jak operator przecinka, ale jak się okazuje, jest to po prostu kwestia pierwszeństwa - operator przecinka ma najniższy możliwy priorytet , więc wyrażenie x = i ++, a ++ jest efektywne przeanalizowane jako (x = i ++), a ++
Dzięki za wszystkie komentarze, to była ciekawa nauka, a C od wielu lat używam!
Spróbuj tego
for(int i = 0; i != 5; ++i, ++j)
do_something(i,j);
for( ; ; ((++i), (++j)) )
for(int i = 0; i != 5; (++i)) {
dodatkowy nawias oszukuje kompilator do myślenia, że nie jest to już operacja „inkrementacji”.
Staraj się tego nie robić!
Z http://www.research.att.com/~bs/JSF-AV-rules.pdf :
Reguła AV 199
Wyrażenie inkrementujące w pętli for nie wykona żadnej akcji poza zmianą pojedynczego parametru pętli na następną wartość pętli.Uzasadnienie: czytelność.
Przyszedłem tutaj, aby przypomnieć sobie, jak zakodować drugi indeks w klauzuli inkrementacji pętli FOR, co wiedziałem, że można to zrobić głównie obserwując go w próbce, którą włączyłem do innego projektu, napisanego w C ++.
Dziś pracuję w języku C #, ale miałem pewność, że pod tym względem będzie przestrzegać tych samych reguł, ponieważ instrukcja FOR jest jedną z najstarszych struktur kontrolnych w całym programowaniu. Na szczęście spędziłem ostatnio kilka dni na dokładnym dokumentowaniu zachowania pętli FOR w jednym z moich starszych programów w języku C i szybko zdałem sobie sprawę, że te badania obejmowały lekcje dotyczące dzisiejszego problemu C #, w szczególności zachowania drugiej zmiennej indeksu .
Dla nieostrożnych poniżej znajduje się podsumowanie moich obserwacji. Wszystko, co widziałem dzisiaj, dzięki uważnej obserwacji zmiennych w oknie Locals, potwierdziło moje oczekiwanie, że instrukcja C # FOR zachowuje się dokładnie tak, jak instrukcja C lub C ++ FOR.
Jeśli którakolwiek ze zmiennych indeksujących pozostanie w zasięgu po zakończeniu pętli, ich wartość będzie o jeden wyższa niż próg zatrzymujący pętlę, w przypadku zmiennej indeksującej true. Podobnie, jeśli, na przykład, druga zmienna jest inicjalizowana do zera przed wprowadzeniem pętli, jej wartością na końcu będzie liczba iteracji, przy założeniu, że jest to przyrost (++), a nie dekrementacja i że nic w ciało pętli zmienia swoją wartość.
Zgadzam się z squelartem. Zwiększanie dwóch zmiennych jest podatne na błędy, zwłaszcza jeśli testujesz tylko jedną z nich.
Oto czytelny sposób, aby to zrobić:
int j = 0;
for(int i = 0; i < 5; ++i) {
do_something(i, j);
++j;
}
For
pętle są przeznaczone dla przypadków, w których pętla działa na jednej rosnącej / malejącej zmiennej. Dla każdej innej zmiennej zmień ją w pętli.
Jeśli musisz j
być przywiązany i
, dlaczego nie pozostawić oryginalnej zmiennej bez zmian i dodać i
?
for(int i = 0; i < 5; ++i) {
do_something(i,a+i);
}
Jeśli twoja logika jest bardziej złożona (na przykład, musisz faktycznie monitorować więcej niż jedną zmienną), użyłbym while
pętli.
int main(){
int i=0;
int a=0;
for(i;i<5;i++,a++){
printf("%d %d\n",a,i);
}
}
i
i a
lokalnego w pętli?
Użyj matematyki. Jeśli te dwie operacje matematycznie zależą od iteracji pętli, dlaczego nie wykonać matematyki?
int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
do_something (counter+i, counter+j);
Lub, bardziej szczegółowo odwołując się do przykładu PO:
for(int i = 0; i != 5; ++i)
do_something(i, j+i);
Zwłaszcza jeśli przechodzisz do funkcji według wartości, powinieneś otrzymać coś, co robi dokładnie to, czego chcesz.