For petlja
Izvor: Wikipedija
U računarstvu, for petlja je naredba programskog jezika koja dopušta opetovano izvršavanje koda. For petlja se klasificira kao iterativna naredba.
Za razliku od drugih petlji, poput while petlje, for petlja se razlikuje postojanjem eksplicitnog brojača petlje ili varijable petlje. Ovo dopušta tijelu petlje (kodu koji se opetovano izvršuje) svjesnost o sekvenciranju svake iteracije. For petlje se tipično koriste kad je broj iteracija poznat prije ulaska u petlju.
Ime "for petlja" dolazi od engl. riječi for koja se koristi kao ključna riječ u većini programskih jezika. U FORTRAN-u i PL/I se, međutim, koristi ključna riječ DO i zvana je "do petljom", dok je u svim drugim pogledima istovjetna ovdje opisanoj for petlji.
Sadržaj |
[uredi] Vrste for petlji
Naredba for petlje je dostupna u većini imperativnih programskih jezika. Čak i ignorirajući manje razlike u sintaksi, postoje mnoge razlike u načinu na koje ove naredbe rade i razini ekspresivnosti koju pružaju. Općenito for petlje potpadaju u jednu od sljedećih kategorija:
[uredi] Numerički opsezi
Ova je vrsta for petlje karakterizirana brojanjem - enumeriranjem svake od vrijednosti unutar cjelobrojnog numeričkog opsega ili aritmetičkim napredovanjem. Opseg je često specificiran početnim i završnim brojem, i ponekad uključuje vrijednost koraka (dopuštajući primjerice brojanje po dva, ili npr. unazad). Reprezentativan primjer u BASIC-u jest:
FOR I = 1 TO 10 tijelo petlje NEXT I
Varijabla petlje I će poprimiti vrijednosti 1, 2, ..., 9, 10 u svakoj od deset iteracija tijela petlje, koje će se izvršiti u tom redoslijedu. Svaki računalni jezik, pa čak i različiti dijalekti istog jezika (npr. BASIC), ima razlčite ključne riječi za for petlju i različite načine određivanja početnih, završnih i vrijednosti koraka.
Rijetko dostupno poopćenje dopušta vrijednostima početka, kraja i koraka da budu specificirane kao stavke u listi, a ne samo kao aritmetički niz; primjerice:
for i:=2,3,5,7,11 do itd.
Pri čemu svaki stavak liste može i sam biti aritmetički niz. Obična je for petlja stoga primjer liste sa samo jednim elementom.
[uredi] For petlje zasnovane na iteratorima
Ova vrsta petlje je poopćenje one vrste for petlje koja barata numeričkim opsezima, s obzirom da dopušta enumeriranje skupova stavaka (elemenata) koji ne moraju biti nizovi brojeva. Obično je karakterizirana uporabom implicitnog ili eksplicitnog iteratora, u kojem varijabla petlje poprima svaku od vrijednosti niza ili neke druge uredive podatkovne kolekcije. Kanonski primjer u Pythonu jest:
for item in lista: tijelo petlje
Pri čemu je lista ili podatkovna kolekcija koja implicitno podržava iteriranje, ili sama može biti eksplicitni iterator. Neki jezici imaju ovo kao dodatak drugoj sintaksi for petlje; prije svega PHP posjeduje ovu vrstu petlje pod imenom foreach
kao i kao troizraznu for petlju (vidjeti dolje) pod imenom for
.
[uredi] Složene for petlje
Uvedene u Algol-68 nakon čega su ostvarane i u PL/I, dopuštaju da iteriranje petlje bude složeno sa ispitivanjem, kao u:
for i:=1:N while A(i) > 0 do itd.
To jest, vrijednost je dodijeljena varijabli petlje i i tijelo će petlje biti izvršeno samo ako je while izraz istinit. Ako je rezultat lažan, izvršavanje se for petlje zaustavlja. Pod pretpostavkom da je vrijednost varijable petlje definirana nakon terminacije petlje, gornja će naredba naći prvi nepozitivan element niza A (ako takav ne postoji, njegova će vrijednost biti N+1) ili, s prikladnim varijacijama, prvi znak nebjeline u stringu, itd.
[uredi] For petlje s tri izraza
This type of for loop is found in nearly all languages which share a common heritage with the C programming language. It is characterized by a three-parameter loop control expression; consisting of an initializer, a loop-test, and a counting expression. A representative example in C is:
for (counter = 0; counter < 10; counter++) tijelo petlje'
The three control expressions, separated by semicolons here, are from left to right the initializer expression, the loop test expression, and the counting expression. The initializer is evaluated exactly once right at the beginning. The loop test expression is evaluated at the beginning of each iteration through the loop, and determines when the loop should exit. Finally, the counting expression is evaluated at the end of each loop iteration, and is usually responsible for altering the loop variable.
In most languages which provide this type of for loop, each of the three control loop expressions is optional. When omitted the loop test expression is taken to always be true, while the initializer and counting expressions are treated as no-ops when omitted. The semicolons in the syntax are sufficient to indicate the omission of one of the expressions. Some examples include:
int i = 0; for ( ; i<10; ) { i++; }
or this,
int i = 0; for ( ; ; i++ ) { if ( i >= 10 ) break; }
Notice that in normal usage, the name of the iteration variable is repeated in each of the three parts. Using a different name in any part is valid syntax, though the resulting behaviour might not be desired.
[uredi] Dodatna semantika i konstrukti
[uredi] Upotreba kao beskonačne petlje
This C-style for loop is commonly the source of an infinite loop since the fundamental steps of iteration are completely in the control of the programmer. In fact when infinite loops are intended, this type of for loop is often used (with empty expressions), such as:
for (;;) tijelo petlje'
[uredi] Rani izlazak i nastavljanje
Some languages may also provide other supporting statements, which when present can alter how the for loop iteration proceeds. Common among these are the break and continue statements found in C and its derivatives. The break statement causes the inner-most loop to be terminated immediately when executed. The continue statement will move at once to the next iteration without further progress through the loop body for the current iteration. Other languages may have similar statements or otherwise provide means to alter the for loop progress; for example in Fortran 95:
DO I = 1,N I = 7 !Overt adjustment of the loop variable. Compiler complaint likely. Z = ADJUST(I) !Function ADJUST might alter I, to uncertain effect. normal statements IF (no good) CYCLE !Skip this value of I, continue with the next. statements IF (finish now!) EXIT !Abandon the loop. statements END DO
Unfortunately, the clear lead given by BASIC has not been followed and so the END DO does not identify the loop variable it is thought to belong with, and worse, nor do the CYCLE and EXIT statements. This becomes much more important when many and nested loops are involved. The EXIT could even be taken to mean exit the procedure instead of exit the loop: phrases such as NEXT I and possibly, DONEXT I and DOQUIT I or similar explicit indications would help make blunders more apparent. A partial solution is offered through a syntax extension (in Fortran and PL/I for example) whereby a label is associated with the DO statement and the same label text is appended to the end marker, such as x:DO I = 1,N and END DO x in the example, whereupon CYCLE x and EXIT x could be used. However, working directly against the objective, the text of the label x is not allowed to be the name of the loop variable, so "I" would not be allowed (though "II" would be), and, if there is a second such loop later in the routine, different label texts would have to be chosen.
[uredi] Doseg i semantika varijable petlje
Different languages specify different rules for what value the loop variable will hold on termination of its loop, and indeed some hold that it "becomes undefined". This permits a compiler to generate code that leaves any value in the loop variable, or perhaps even leaves it unchanged because the loop value was held in a register and never stored to memory.
In some languages (not C or C++) the loop variable is immutable within the scope of the loop body, with any attempt to modify its value being regarded as a semantic error. Such modifications are sometimes a consequence of a programmer error, which can be very difficult to identify once made. However only overt changes are likely to be detected by the compiler. Situations where the address of the loop variable is passed as an argument to a subroutine make it very difficult to check, because the routine's behavior is in general unknowable to the compiler
Still another possibility is that the code generated may employ an auxiliary variable as the loop variable, possibly held in a machine register, whose value may or may not be copied to I on each iteration. In this case, modifications of I would not affect the control of the loop, but now a disjunction is possible: within the loop, references to the value of I might be to the (possibly altered) current value of I or to the auxiliary variable (held safe from improper modification) and confusing results are guaranteed. For instance, within the loop a reference to element I of an array would likely employ the auxiliary variable (especially if held in a machine register), but if I is a parameter to some routine (for instance, a print-statement to reveal its value), it would likely be to the proper variable I instead. It is best to avoid such possibilities.
[uredi] Razlikovanje for petlji zasnovanih na iteratorima i onih numeričkih
A language may offer both an iterator-based for loop and a numeric-based for loop in of course their own syntax. It may appear that a numeric-based loop may always be replaced by an appropriate iterator-based loop, but differences can arise. Suppose an array A has elements 1 to N and the language does not offer a simple assignment statement A:=3*A; so that some sort of for-loop must be devised. Then in pseudocode, the two versions might be
for i:=1:N do A(i):=3*A(i); next i; forall i:=1:N do A(i):=3*A(i);
Which are clearly equivalent, indeed the differences seem mere syntax trivia, but, the semantics are different. The forall version is to be regarded as a mass assignment where notionally, all the right-hand side results are evaluated and left-hand side recipients are located, then the assignments are done. The code the compiler devises to effect this is unstated, but the idea is that no item on the left-hand side is changed before all items on the right-hand side are evaluated; every element is assigned to once only.
Now suppose that the requirement is that each element of A is to be the average of itself and its two neighbours, and for simplicity, suppose that the first and last elements are to be unchanged. Then, the loops become
for i:=2:N-1 do A(i):=[A(i-1) + A(i) + A(i+1)]/3; next i; forall i:=2:N-1 do A(i):=[A(i-1) + A(i) + A(i+1)]/3;
In this case, the results will be different: because the for loop is executed as successive iterations, element A(i-1) will hold the value that had just been calculated by the previous iteration, not the original value, while in the forall version, it would not yet have been changed. Provided of course that the compiler's implementation of the forall construct does in fact uphold that interpretation. This difference may or may not be important. If not, whichever runs fastest could be chosen. But the difference can be vital, as in certain stages of the LU decomposition algorithm for just one example.
More complex for loops (especially with conditional branching) will introduce further difficulties unlikely to be accommodated by the syntax of the forall statement. Rather than trying to convert a for statement into a forall statement, the task should be recast in terms of the assignment of one data structure (such as an array) to another of the same type, avoiding complex conditions. For instance, given integer division where 3/4 = 0, a square array A can be initialised to the identity matrix as follows:
forall i:=1:N,j:=1:N do A(i,j):=(i/j)*(j/i); %=1 if i=j, otherwise zero.
Here, the right-hand side is not an actual square array like A, but an expression generating a value for each element nonetheless, which could be regarded as forming a notional array. The forall statement is thus a generalisation of the simpler array-assignment statements, where both sides of the expression have to be actual arrays.
It might be that during the preparation of the right-hand side's values the compiler might deduce that the rather odd integer arithmetic expression generates either zero or one in a simple pattern and so would produce code that does not perform the evaluations, but this is unlikely. Better results would likely be gained by
A:=0; %Mass assignment to an array. forall i:=1:N do A(i,i):=1; %Too complex for simple array assignment.
Though a language designed to support array manipulation and especially matrix arithmetic might well allow some syntax that identifies the diagonal of a square array, so that the second statement might become
Diag(A):=1;
[uredi] Istovjetnost s while petljama
A for loop can always be converted into an equivalent while loop by incrementing a counter variable directly. The following pseudocode illustrates this technique:
faktorijela := 1 for brojac from 1 to 5: faktorijela := faktorijela * brojac
is easily translated into the following while loop:
faktorijela := 1 brojac := 1 while brojac <= 5: faktorijela := faktorijela * brojac brojac := brojac + 1
[uredi] Sintaksa
Given an action that must be repeated, for instance, five times, different languages' for loops will be written differently. The syntax for a three-expression for loop is nearly identical in all languages that have it, after accounting for different styles of block termination and so on (example is C):
for (brojac = 1; brojac <= 5; brojac++) naredbe;
The numeric-range for loop varies somewhat more. Pascal would write it:
for Brojac := 1 to 5 do naredbe;
Whereas Perl would use:
for($brojac = 1; $brojac <= 5; ++$brojac) { naredbe; }
(Note that for(1..5) { }
is really a foreach in Perl.)
Iterator for loops most commonly take a form such as this (example is Python):
for brojac in range (1, 6): # range() gives values to one less than the second argument naredbe
But the PHP equivalent (virtually never used for simple repetition but noted here for completeness):
foreach (range(1,5) as $i) naredbe;
Contrary to other languages, in Smalltalk a for loop is not a language construct but defined in the class Number as a method with two parameters, the end value and a closure, using self as start value.
1 to: 5 do: [ "naredbe" ]
[uredi] Vremeplov for petlji u raznim programskim jezicima
[uredi] 1966: FORTRAN 66
FORTRAN 66's equivalent of the for
loop is the DO
loop. The syntax of Fortran's DO
loop is:
DO label counter=start, stop, step label naredbe
Example:
PROGRAM MAIN SUM SQ=0 DO 101 I=1,9999999 IF (SUM SQ.GT.1000) GO TO 109 SUM SQ=SUM SQ+I**2 101 CONTINUE 109 CONTINUE END
The fortran DO loop caused an orbit computation error in a Mercury flight, and was long suspected to have caused the crash of the Mariner 1 space rocket on 22 July 1962 - C.A.R. Hoare, in particular a missing comma in the wrong place can drastically alter the meaning of the loop. Example:
DO 101 I=1.9999999 101 CONTINUE
Because of the peculiar feature of fortran that spaces are not significant, this is interpreted as a single assignment to the (probably undeclared) variable DO101I
. In the subsequent FORTRAN 77 specification an additional comma was required in the DO
loop syntax.
[uredi] 1968: Algol68
Algol68 has what was considered the universal loop, the full syntax is:
for i from 1 by 1 to 3 while i≠4 do ~ od
There are several unusual aspects of the construct
- only the do ~ od portion was compulsory, in which case the loop will iterate indefinitely.
- thus the clause to 100 do ~ od, will iterate only 100 times.
- the while "syntactic element" allowed a programmer to break from a for loop early, as in:
int sum sq:=0; for i while print (("So far:",i, newline)); sum sq≤1000 do sum sq+:=i↑2 od
Subsequent "extensions" to the standard Algol68 allowed the to syntactic element to be replaced with upto and downto to achieve a small optimization. The same compilers also incorporated:
- until - for late loop termination.
- foreach - for working on arrays in parallel.
[uredi] 1977: FORTRAN 77
FORTRAN 77's equivalent of the for
loop is the DO
loop. The syntax of Fortran's DO
loop is:
DO label, counter=start, stop, step label naredbe
Example:
PROGRAM MAIN SUM SQ=0 DO 101, I=1,9999999 IF (SUM SQ.GT.1000) GO TO 109 SUM SQ=SUM SQ+I**2 101 CONTINUE 109 CONTINUE END
[uredi] Vidjeti također
- While petlja
- Do while petlja
- Brojač petlje
- Foreach