Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Everybody is aware of the most common use of for: (0 - 9)
for (int i = 0; i < 10; i++)
however, I've also seen some less common versions, like (1 - 10)
for (int i = 0; i++ < 10;)
or (1 - 10)
int i = 0;
for (;i++ < 10;)
Which would suggest that loops might be more customizable than I thought. If I'm guessing this correctly, it would seem that
There always needs to be 2 semicolons to separate 3 optional statements
The second statement needs to be convertible to boolean 1 for the loop to continue
The first statement is the only one where I can declare variables and is called once
The third and second statement are called after every iteration and can contain whatever (aside from declarations)
As far as those conditions are met, I can do whatever
for instance (0, 3, 7)
for (int i = 0, j = 2; i < 10; i+=++j)
Are those kinds of for loops considered standard use of the language? or just things that happen to work due to the implementation design in msvc++? Any official instructions on what the rules of for loop really are?
You are correct. However...
Just because it is possible doesn't mean you should do it. The entire purpose of a "for" loop is it is supposed to be organized at a level any competent programmer can understand quickly. A key fundamental is the programmer should know how long a "for" loop will run. If you add more complexity to that which is taught, the point of the "for" loop is lost. I cannot easily look at your 3rd example and tell how long the loop will iterate.
If you need to use a "for" loop like your 3rd example, you'd be better off writing a while/do-while loop.
From the ISO C99 draft:
for ( clause-1 ; expression-2 ; expression-3 ) statement behaves as
follows:
The expression expression-2 is the controlling expression
that is evaluated before each execution of the loop body.
The expression expression-3 is evaluated as a void expression after each
execution of the loop body.
If clause-1 is a declaration, the scope of
any identifiers it declares is the remainder of the declaration and
the entire loop, including the other two expressions; it is reached in
the order of execution before the first evaluation of the controlling
expression.
If clause-1 is an expression, it is evaluated as a void
expression before the first evaluation of the controlling
expression.
Both clause-1 and expression-3 can be omitted. An
omitted expression-2 is replaced by a nonzero constant.
To answer your questions:
There always needs to be 2 semicolons to separate 3 optional statements
Yes.
The second statement needs to be convertible to boolean 1 for the loop to continue.
Yes. The second statement will evaluate as a boolean true/false (although not necessarily "1").
The first statement is the only one where I can declare variables and is called once
For C++, yes. In C (before C99), you had to declare the variable outside of the for loop.
The third and second statement are called after every iteration and can contain whatever (aside from declarations)
Yes. And they may contain nothing. For example, for ( ;; ) means "loop forever".
As far as those conditions are met, I can do whatever
Here is a good tutorial:
http://www.cplusplus.com/doc/tutorial/control/
One of my personal favourites is to iterate over a linked list:
for(Node *p = head; p; p = p->next) ...
And of course, if you do "no condition", you get an inifinite loop:
for(;;) ...
But yes, as long as you have for( following by valid statements, two semicolons and ), it's "good code".
for(printf("h"); !printf("world\n"); printf("ello, "));
is valid, if rather bizarre C-code (and C++, but cout is preferred there).
Of course, "it compiles and does what you expect" does not make it RIGHT or a good use of the language. It's often preferred if other people can read the code and understand what it's meant to do, and not want to go work somewhere else or to perform violence against the person that originally wrote the code.
It depends on how you want to do it. C++ is flexible and allows you to build statements as you wish. Of course, clearer ways as preferable.
The "for" statement has 3 parts separated by ";" character:
1) initialize code (int i = 0): where you init the counter variable(s) you're gonna use in your loop;
2) condition for loop (i < 20): condition that will be tested for the loop to continue;
3) step (increment): you can optionally specify an increment to the counter variable;
The "for" statement has preferable and indicated use when you know how much times you're going to iterate (to loop). Otherwise, it's recommended to use "while".
Example of flexibility of C++:
for(int i = 0; i < 20; i++) { }
is equivalent to
int i = 0;
for(;i < 20;) { i++; }
Related
This question already has answers here:
What does it mean when the first "for" parameter is blank?
(8 answers)
Closed 4 years ago.
I'm studying for my exam and I bumped into this example that has a line that says:
for(;i<=m;i++)
The thing I don't understand is why is there a ; with nothing in front of it?
what does it do? What does it mean?
A for statement has the following syntax:
for (declaration; condition; post-condition)
The declaration happens once and once only. The condition is checked at the start of each loop and determines whether the loop will proceed, and the post-condition happens at the end of the loop.
Any and all of these statements can be omitted.
Yours is simply a for loop that does not require a declaration, perhaps because something is already declared, like so:
int i = 0;
for (;i<=m;++i)
If you wanted a loop to run indefinitely, you could omit the second statement:
for (int i = 0; ;++i)
In this regard, infinite loops are typically written as
for (;;)
You may wish to omit the post-condition, perhaps because you're using iterators and change it during the loop
for (auto it = std::begin(v); it != std::end(v);)
what does it do, what does it mean ?
It means that the initializing part of the for-loop is empty, i.e. no loop-variable is initialized in the scope of the loop.
This construct is most common in situations where you want to access the loop variable after the loop is left, e.g. in
int i = 7;
for(; i < 100; ++i) {
if(isPrime(i)) break;
}
assert(i == 11); // can access i now
This means a part of this statement is declared somewhere before.
i=0
for(;i<=m;i++)
This loop says,for every time that i is smaller than m, I'm going to do whatever is in the code block. Whenever i reaches m value, I'll stop. After each iteration of the loop, it increments i by 1 (i++), so that the loop will eventually stop when it meets the i <=m.
The thing that i don't understand is why is there a ";" with nothing in front of it. what does it do, what does it mean.
It is a valid statement that does nothing.
You can have empty statements any where you like. It's quite common to see them in looping constructs.
The i variable must have been initialized somewhere else.. so it picks the value from there and the loop iterates from that value of i.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Why there is a need of 3 different loops : "while", "do-while", and "for" to exist in c/c++, especially when each of them gives you power to do almost anything that the other 2 can do? Other languages lack one or the other.
Is it just for ease of use or to make the code look better in cases, or are there any special purposes that are served by any one of them specifically that can't be accomplished so easily with the other two? If yes, then please mention.
P.S. - In general, do a language support many iteration syntax just to enhance readability?
It's not just readability, it's also the closely-related but distinct maintainability, and concision, and scoping (esp. for files, locks, smart pointers etc.), and performance....
If we consider the for loop, it:
allows some variables to be defined - in the for loop's own scope - and initialised,
tests a control expression before entering the loop each time (including the first), and
has a statement that gets executed after each iteration and before re-testing the control expression, assuming no break/return/throw/exit/failed assert etc., and regardless of whether the last statement in the body executed or whether a continue statement executed; this statement is traditionally reserved for logically "advancing" some state "through" the processing, such that the next test of the control expression is meaningful.
That's very flexible and given the utility of more localised scopes to ensure earlier destructor invocation, can help ensure locks, files, memory etc. are released as early as possible - implicitly when leaving the loop.
If we consider a while loop...
while (expression to test)
...
...it's functionally exactly equivalent to...
for ( ; expression to test; )
...
...but, it also implies to the programmer that there are no control variables that should be local to the loop, and that either the control "expression to test" inherently "progresses" through a finite number of iterations, loops forever if the test expression is hardcoded true, or more complicated management of "progress" had to bed itself controlled and coordinated by the statements the while controls.
In other words, a programmer seeing while is automatically aware that they need to study the control expression more carefully, then possibly look more widely at both the surrounding scope/function and the contained statements, to understand the loop behaviour.
So, do-while? Well, writing code like this is painful and less efficient:
bool first_time = true;
while (first_time || ...)
{
first_time = false;
...
}
// oops... first_time still hanging around...
...compared to...
do
...
while (...);
Examples
While loop:
int i = 23;
while (i < 99)
{
if (f(i)) { ++i; continue; }
if (g(i)) break;
++i;
}
// oops... i is hanging around
For loop:
for (int i = 23; i < 99; ++i)
{
if (f(i)) continue;
if (g(i)) break;
}
Well, C++ has goto and you can use it to implement all three loops, but it doesn't mean that they should be removed. Actually it just increases readability. Of course you could implement any of them yourself.
Some loops are easiest to write using for, some are easiest to write using while, and some are easiest to write using do-while. So the language provides all three.
We have things things like the += operator for the same reason; += doesn't do anything that you can't do with plain +, but using it (where appropriate) can make your code a bit more readable.
In general, when presented with different language constructs that accomplish similar purposes, you should choose the one that more clearly communicates the intended purpose of the code you are writing. It is a benefit that C provides four distinct structured iteration devices to use, as it provides a high chance you can clearly communicate the intended purpose.
for ( initialization ; condition ; iteration-step ) body
This form communicates how the loop will start, how it will adjust things for the next iteration, and what is the condition to stay within the loop. This construct lends itself naturally for doing something N times.
for (int i = 0; i < N; ++i) {
/* ... */
}
while ( condition ) body
This form communicates simply that you wish to continue to perform the loop while the condition remains true. For loops where the iteration-step is implicit to the way the loop works, it can be a more natural way to communicate the intention of the code:
while (std::cin >> word) {
/* ... */
}
do body while ( condition )
This form communicates that the loop body will execute at least once, and then continues while the condition remains true. This is useful for situations where you have already determined that you need to execute the body, so you avoid a redundant looking test.
if (count > 0) {
do {
/* ... */
} while (--count > 0);
} else {
puts("nothing to do");
}
The fourth iteration device is ... recursion!
Recursion is another form of iteration that expresses that the same function can be used to work on a smaller part of the original problem. It is a natural way to express a divide and conquer strategy to a problem (like binary searching, or sorting), or to work on data structures that self-referential (such as lists or trees).
struct node {
struct node *next;
char name[32];
char info[256];
};
struct node * find (struct node *list, char *name)
{
if (list == NULL || strcmp(name, list->name) == 0) {
return list;
}
return find(list->next, name);
}
In a loop like so,
for (int i = 0; i < 5; i++)
{
int i_foo;
i_foo = foo();
if (i < 5)
return; //<-------- Right here
footwo();
}
How would I return that one particular turn of the loop?
I know that I could make footwo() execute under the condition that i >= 5, but I'm wondering if there is a way to make the loop exit (just the once).
For more explanation, I would like the for loop to start back at the beginning and add 1 to i, as if it had just finished that particular "loop" of the loop.
(I could not find an answer to this based on the strange wording, but if there is one just direct me and I will happily take this down.)
Use continue:
if (i < 5)
continue;
This jumps straight to the next iteration of the loop.
I'm not entirely sure what you mean but if you're checking the condition of if (i < 5) then just use the keyword continue. If the expression is true the loop will continue.
I'm not exactly what you're saying, but to clear up a bit of terminology, I think you mean to say "iteration" when you're saying a "turn of the loop" or a "loop of the loop." Common terms allow for better clarity.
As to your issue:
If you use the continue keyword, it allows you to skip to the next iteration. If you use the break keyword, it will skip past the entire iteration structure (out of the for loop entirely). This also works with while statements.
You can use continue to terminate the current iteration of a loop without terminating the loop itself. But depending on how your code is structured, an if statement might be cleaner.
Given your example, you might want:
for (int i = 0; i < 5; i++)
{
int i_foo;
i_foo = foo();
if (i_foo >= 5) {
footwo();
}
}
I'm assuming that you meant to assign the result of foo() to i_foo, not to i.
A continue can be simpler if you need to bail out from the middle of some nested structure, or if you need to bail out very early in the body of the loop and there's a lot of code that would be shoved into the if.
But in the case of nested control structures, you need to remember that continue applies only to the innermost enclosing loop; there's no construct (other than goto) for bailing out of multiple nested loops. And break applies to the innermost enclosing loop or switch statement.
I was trying to compile the following code:
#pragma omp parallel shared (j)
{
#pragma omp for schedule(dynamic)
for(i = 0; i != j; i++)
{
// do something
}
}
but I got the following error: error: invalid controlling predicate.
The OpenMP standard states that for parallel for constructor it "only" allows one of the following operators: <, <=, > >=.
I do not understand the rationale for not allowing i != j. I could understand, in the case of the static schedule, since the compiler needs to pre-compute the number of iterations assigned to each thread. But I can't understand why this limitation in such case for example. Any clues?
EDIT: even if I make for(i = 0; i != 100; i++), although I could just have put "<" or "<=" .
.
I sent an email to OpenMP developers about this subject, the answer I got:
For signed int, the wrap around behavior is undefined. If we allow !=, programmers may get unexpected tripcount. The problem is whether the compiler can generate code to compute a trip count for the loop.
For a simple loop, like:
for( i = 0; i < n; ++i )
the compiler can determine that there are 'n' iterations, if n>=0, and zero iterations if n < 0.
For a loop like:
for( i = 0; i != n; ++i )
again, a compiler should be able to determine that there are 'n' iterations, if n >= 0; if n < 0, we don't know how many iterations it has.
For a loop like:
for( i = 0; i < n; i += 2 )
the compiler can generate code to compute the trip count (loop iteration count) as floor((n+1)/2) if n >= 0, and 0 if n < 0.
For a loop like:
for( i = 0; i != n; i += 2 )
the compiler can't determine whether 'i' will ever hit 'n'. What if 'n' is an odd number?
For a loop like:
for( i = 0; i < n; i += k )
the compiler can generate code to compute the trip count as floor((n+k-1)/k) if n >= 0, and 0 if n < 0, because the compiler knows that the loop must count up; in this case, if k < 0, it's not a legal OpenMP program.
For a loop like:
for( i = 0; i != n; i += k )
the compiler doesn't even know if i is counting up or down. It doesn't know if 'i' will ever hit 'n'. It may be an infinite loop.
Credits: OpenMP ARB
Contrary to what it may look like, schedule(dynamic) does not work with dynamic number of elements. Rather the assignment of iteration blocks to threads is what is dynamic. With static scheduling this assignment is precomputed at the beginning of the worksharing construct. With dynamic scheduling iteration blocks are given out to threads on the first come, first served basis.
The OpenMP standard is pretty clear that the amount of iteratons is precomputed once the workshare construct is encountered, hence the loop counter may not be modified inside the body of the loop (OpenMP 3.1 specification, ยง2.5.1 - Loop Construct):
The iteration count for each associated loop is computed before entry to the outermost
loop. If execution of any associated loop changes any of the values used to compute any
of the iteration counts, then the behavior is unspecified.
The integer type (or kind, for Fortran) used to compute the iteration count for the
collapsed loop is implementation defined.
A worksharing loop has logical iterations numbered 0,1,...,N-1 where N is the number of
loop iterations, and the logical numbering denotes the sequence in which the iterations
would be executed if the associated loop(s) were executed by a single thread. The
schedule clause specifies how iterations of the associated loops are divided into
contiguous non-empty subsets, called chunks, and how these chunks are distributed
among threads of the team. Each thread executes its assigned chunk(s) in the context of
its implicit task. The chunk_size expression is evaluated using the original list items of any variables that are made private in the loop construct. It is unspecified whether, in what order, or how many times, any side-effects of the evaluation of this expression occur. The use of a variable in a schedule clause expression of a loop construct causes an implicit reference to the variable in all enclosing constructs.
The rationale behind these relational operator restriction is quite simple - it provides clear indication on what is the direction of the loop, it alows easy computation of the number of iterations, and it provides similar semantics of the OpenMP worksharing directive in C/C++ and Fortran. Also other relational operations would require close inspection of the loop body in order to understand how the loop goes which would be unaceptable in many cases and would make the implementation cumbersome.
OpenMP 3.0 introduced the explicit task construct which allows for parallelisation of loops with unknown number of iterations. There is a catch though: tasks introduce some severe overhead and the one task per loop iteration only makes sense if these iterations take quite some time to be executed. Otherwise the overhead would dominate the execution time.
The answer is simple.
OpenMP does not allow premature termination of a team of threads.
With == or !=, OpenMP has no way of determining when the loop stops.
1. One or more threads could hit the termination condition, which might not be unique.
2. OpenMP has no way to shut down the other threads that might never detect the condition.
If I were to see the statement
for(i = 0; i != j; i++)
used instead of the statement
for(i = 0; i < j; i++)
I would be left wondering why the programmer had made that choice, never mind that it can mean the same thing. It may be that OpenMP is making a hard syntactic choice in order to force a certain clarity of code.
Here's code which raises challenges for the use of != and may help explain why it isn't allowed.
#include <cstdio>
int main(){
int j=10;
#pragma omp parallel for
for(int i = 0; i < j; i++){
printf("%d\n",i++);
}
}
notice that i is incremented in both the for statement as well as within the loop itself leading to the possibility (but not the guarantee) of an infinite loop.
If the predicate is < then the loop's behavior can still be well-defined in a parallel context without the compiler having to check within the loop for changes to i and determining how those changes will affect the loop's bounds.
If the predicate is != then the loop's behavior is no longer well-defined and it may be infinite in extent, preventing easy parallel subdivision.
I think there is perhaps no good reason other than having extended existing functionality to get this far.
IIRC originally these had to be static so that it could determine at compile time how to generate the loop code... it could just be a hangover from that.
I would like to increment two variables in a for-loop condition instead of one.
So something like:
for (int i = 0; i != 5; ++i and ++j)
do_something(i, j);
What is the syntax for this?
A common idiom is to use the comma operator which evaluates both operands, and returns the second operand. Thus:
for(int i = 0; i != 5; ++i,++j)
do_something(i,j);
But is it really a comma operator?
Now having wrote that, a commenter suggested it was actually some special syntactic sugar in the for statement, and not a comma operator at all. I checked that in GCC as follows:
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);
}
I was expecting x to pick up the original value of a, so it should have displayed 5,6,7.. for x. What I got was this
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
However, if I bracketed the expression to force the parser into really seeing a comma operator, I get this
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
Initially I thought that this showed it wasn't behaving as a comma operator at all, but as it turns out, this is simply a precedence issue - the comma operator has the lowest possible precedence, so the expression x=i++,a++ is effectively parsed as (x=i++),a++
Thanks for all the comments, it was an interesting learning experience, and I've been using C for many years!
Try this
for(int i = 0; i != 5; ++i, ++j)
do_something(i,j);
Try not to do it!
From http://www.research.att.com/~bs/JSF-AV-rules.pdf:
AV Rule 199
The increment expression in a for loop will perform no action other than to change a single
loop parameter to the next value for the loop.
Rationale: Readability.
for (int i = 0; i != 5; ++i, ++j)
do_something(i, j);
I came here to remind myself how to code a second index into the increment clause of a FOR loop, which I knew could be done mainly from observing it in a sample that I incorporated into another project, that written in C++.
Today, I am working in C#, but I felt sure that it would obey the same rules in this regard, since the FOR statement is one of the oldest control structures in all of programming. Thankfully, I had recently spent several days precisely documenting the behavior of a FOR loop in one of my older C programs, and I quickly realized that those studies held lessons that applied to today's C# problem, in particular to the behavior of the second index variable.
For the unwary, following is a summary of my observations. Everything I saw happening today, by carefully observing variables in the Locals window, confirmed my expectation that a C# FOR statement behaves exactly like a C or C++ FOR statement.
The first time a FOR loop executes, the increment clause (the 3rd of its three) is skipped. In Visual C and C++, the increment is generated as three machine instructions in the middle of the block that implements the loop, so that the initial pass runs the initialization code once only, then jumps over the increment block to execute the termination test. This implements the feature that a FOR loop executes zero or more times, depending on the state of its index and limit variables.
If the body of the loop executes, its last statement is a jump to the first of the three increment instructions that were skipped by the first iteration. After these execute, control falls naturally into the limit test code that implements the middle clause. The outcome of that test determines whether the body of the FOR loop executes, or whether control transfers to the next instruction past the jump at the bottom of its scope.
Since control transfers from the bottom of the FOR loop block to the increment block, the index variable is incremented before the test is executed. Not only does this behavior explain why you must code your limit clauses the way you learned, but it affects any secondary increment that you add, via the comma operator, because it becomes part of the third clause. Hence, it is not changed on the first iteration, but it is on the last iteration, which never executes the body.
If either of your index variables remains in scope when the loop ends, their value will be one higher than the threshold that stops the loop, in the case of the true index variable. Likewise, if, for example, the second variable is initialized to zero before the loop is entered, its value at the end will be the iteration count, assuming that it is an increment (++), not a decrement, and that nothing in the body of the loop changes its value.
I agree with squelart. Incrementing two variables is bug prone, especially if you only test for one of them.
This is the readable way to do this:
int j = 0;
for(int i = 0; i < 5; ++i) {
do_something(i, j);
++j;
}
For loops are meant for cases where your loop runs on one increasing/decreasing variable. For any other variable, change it in the loop.
If you need j to be tied to i, why not leave the original variable as is and add i?
for(int i = 0; i < 5; ++i) {
do_something(i,a+i);
}
If your logic is more complex (for example, you need to actually monitor more than one variable), I'd use a while loop.
int main(){
int i=0;
int a=0;
for(i;i<5;i++,a++){
printf("%d %d\n",a,i);
}
}
Use Maths. If the two operations mathematically depend on the loop iteration, why not do the math?
int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
do_something (counter+i, counter+j);
Or, more specifically referring to the OP's example:
for(int i = 0; i != 5; ++i)
do_something(i, j+i);
Especially if you're passing into a function by value, then you should get something that does exactly what you want.