76

I found the following code:

int func_prim (int zahl) {
    int count;
    if (zahl < 0)
        return -1;

    for (count = 2; zahl % count != 0 && zahl >= count; count++);
    if (count == zahl)
        return 1;
    return 0;
}

The point of function is to check whether a number is a prime number or not.

I don't understand why the for-loop has ; at the end:

                                                            v
for (count = 2; zahl % count != 0 && zahl >= count; count++);

Without that, the code doesn't work properly.

What is the explanation?

Braiam
  • 4,345
  • 11
  • 47
  • 69
Wien95
  • 806
  • 6
  • 6
  • 48
    The for loop has a semicolon at the end because the author is EVIL! It should go on its own line in situations like this. – sh1 Apr 24 '15 at 01:29
  • 21
    @sh1 Or, if the author wants the whole loop on one line, `{ }` could be used in place of `;` to document that it's intentional for the loop to have an empty body and not include any of the subsequent lines. – Eliah Kagan Apr 24 '15 at 02:36
  • 22
    @EliahKagan, sometimes when I'm feeling like I want to emphasise the emptiness of the loop body I'll write `for (...) continue;`. – sh1 Apr 24 '15 at 02:47
  • 5
    @sh1 @EliahKagan On the other hand, `;` is part of the syntax and by definition represents an empty body everytime a body is expected. Arguably, it might be preferable to use `{}` for new codebases, so that it is somehow more explicit. But the semi-colon is a well-known idiom that exists in a majority of existing C programs. As such, it seems unfair to blame the original author here. – coredump Apr 24 '15 at 08:31
  • 8
    @coredump But the two problems with the semi-colon used in this way are (1) that it looks like a mistake, that some well-meaning developer might remove one day; and (2) if you don't see it, you'll expect that the statement beneath it will be the one that is "looped". The latter is a particular danger, because programmers learn not to pay particular notice to the semi-colon at the end of a line; just as people reading tend not to notice if a sentence fails to end with a full stop – Dawood ibn Kareem Apr 24 '15 at 12:13
  • 1
    So many cowboys start writing code without knowing the basic, that's a problem. – Bolu Apr 24 '15 at 14:38
  • 3
    @DavidWallace I am aware of that, and I agree: use `{}`. That doesn't change the fact that existing code has `;` everywhere. Also (1) the well-meaning developper removes it, and that's it? where is the step where he challenges his assumptions? (2) and the following line is not indented, which is a code smell; the expectation vanishes as well. It is easy to make mistakes in `C`, so yes, coding style helps a lot. But you need to pay attention to details. If `;` is a problem, what about memory allocation or undefined behavior due to [missing parenthesis](https://bugs.php.net/bug.php?id=52550)? – coredump Apr 24 '15 at 16:55
  • 2
    @DavidWallace: If the following statement were intended to be "looped", it should be indented. The indentation makes the code perfectly clear. – Dolda2000 Apr 24 '15 at 18:13
  • 6
    @Marco13 Why automatically assume the original author is ignorant? You hate this kind of writing, very well. But you'll find plenty of people who prefer the `for` loop approach: after all, there is an initialization, a stopping condition and an iteration, which is naturally expressed by the `for` construct. You disagree, but I am sure the author knows what a `while` loop is. Btw, that's why you need coding conventions in a team. – coredump Apr 24 '15 at 19:43
  • If count would have been initialized at declaration, it could even be `for (; zahl % count != 0 && zahl >= count; count++) ;`. Party of the single semicolons! – Anne van Rossum Apr 24 '15 at 23:53
  • @Marco13 It was about ignorance when you said 'the author simply did not know a "while" loop'. What is wrong about this line in the comments and answers here is the amount of bikeshedding this kind of "problem" generates. My opinion is that the code is far from being obfuscated, but a standard C idiom; please use `{}` and comments if you want when writing new code, but be prepared to encounter `;` a lot in existing code. But above all, don't waste your time over this. – coredump Apr 25 '15 at 13:26
  • I like to emphasize empty bodies with *a commented out void*: `for (...) /* void */;` – pmg Apr 26 '15 at 10:00
  • related: http://stackoverflow.com/questions/12193170 – Federico Apr 26 '15 at 11:54
  • 1
    It is at the end because it cant be there at the begining.... – N-JOY May 19 '15 at 07:57
  • YOU SHOULD ACCEPT THE ANSWER.- – gsamaras Mar 26 '16 at 01:23
  • @pmg, why not `for (..;..;..;) continue;` ??? – Luis Colorado Nov 03 '18 at 11:31
  • @LuisColorado: it's the same. I find the version with `/* void */` easier to understand than the version with `continue`. Do what you prefer. – pmg Nov 03 '18 at 11:52
  • @pmg, the problem is that with a comment you have more trouble to be able to detect that at compile time. Compilers are forced to look into the comment to check what you mean. the `continue;` approach allow the compiler to preciselly detect and avoid a warning. – Luis Colorado Nov 05 '18 at 18:17

11 Answers11

89

It means exactly the same as:

for(count = 2; zahl % count != 0 && zahl >= count; count++)
{
}
gsamaras
  • 66,800
  • 33
  • 152
  • 256
M.M
  • 130,300
  • 18
  • 171
  • 314
  • 7
    And this is a much better way to write an empty loop body (though writing `{}` on a single line is maybe a visually easier clue to an empty body). If it weren't for legacy code, the language would be better off without the `;` empty statement rule. The `;` that is obligatory after `do ... while(...)` is stupid as well, but at least there I've seen some clever use of it. – Marc van Leeuwen Apr 24 '15 at 11:20
  • 5
    @MarcvanLeeuwen I find the `;` more readable. The empty block looks like an accident, like the programmer just forgot to fill in the body. The empty statement makes his intentions clear. – Paul Apr 24 '15 at 17:32
  • 19
    @Paulpro, I find both to be potential mistakes, and `for (...) { /* empty block */ }` to be clearer than both, as far as demonstrating that it's intentional. – atk Apr 24 '15 at 19:05
  • 2
    I'm not a `C` programmer, but why on earth would doing this ever be useful? – Ethan Bierlein Apr 25 '15 at 03:43
  • 6
    @EthanBierlein the 'work' is done by the statements inside the `( )` ; the point of this loop is to end up with `count` having a particular value based on `zahl` – M.M Apr 25 '15 at 06:42
  • 1
    @Paulpro so you're saying a single character is likely to be less of a typo than a body, and the intent is therefore clearer? Gonna have to disagree with you on this! – Joe Apr 25 '15 at 18:50
  • @Joe typing `{}` needs to type two characters, so is should be more difficult to do it by mistake. A more visible approach would be `for (...;...;...) continue;`, that's not commonly typed by mistake. But as you can observe, there are more tastes than people. You could also `#define DO_NOTHING() do{}while(0)`, and then `for(...) DO_NOTHING();`... etc. – Luis Colorado Nov 05 '18 at 18:25
53

A for loop has the for keyword, followed by parentheses containing three optional expressions separated by semicolons, followed by a body which executes in each iteration of the loop.

The goal of the for loop in your example is to set the value of count, which will be compared to zahl in the if statement that follows. This is achieved in the semicolon-delimited expressions, so the loop body doesn't need to do anything.

Since the loop doesn't need to do anything, it uses the empty statement as its body.

If the ; at the end were omitted and no other changes were made, then the if statement after the for loop would itself become the body of the for loop. (That is not intended and would break the program, as you have observed.)

However, making one's loop body consist of a single ; on the same line is not the only way to write an empty loop body, nor is it probably the most sensible way to do so. It works perfectly well, but the problem is that other readers - and perhaps the same programmer, returning to the project later - may wonder if it was actually an error. After all, one types semicolons at the ends of lines quite often when coding in a C-style language, so it's easy to type an extra one where it doesn't belong.

The other problem is that, in code where a one-line loop with ; as its body is the chosen style, it is difficult to recognize when someone actually has made the mistake of putting a ; when one doesn't belong.

Therefore, these alternatives may be preferable:

  • putting the ;, indented, on the next line -- as sh1 suggests
  • writing the loop body as an empty block, { }, rather than an empty statement
  • making the loop body a continue; statement, which simply causes the loop to move on to its next iteration (which is the same as what happens when the loop body is empty) -- also as sh1 suggests
Community
  • 1
  • 1
Eliah Kagan
  • 1,681
  • 3
  • 22
  • 36
  • 4
    While I can agree with the `;` and the `{}`, I would find the `continue;` extremely weird. It would look to me as if somebody expected to `continue` an outer loop or something. Definitely a WTF moment, and you want to avoid these in code. I'd say `{}` captures the intent in the most readable way. – Angew is no longer proud of SO Apr 24 '15 at 09:04
  • 5
    Another option (which can be combined with the others) is to insert a comment: `for (...) /* do nothing */ ;`, to make it clear that it's intentional. –  Apr 24 '15 at 10:59
  • 2
    I would add to the alternatives _incrementing the variable inside the loop_, like: `for(count=2; zahl % count != 0 && zahl >= count;) ++count;` – Massa Apr 24 '15 at 12:57
  • 3
    @Massa - the `for` loop is a counted one by definition; exporting the incrementor out of the loop gives you no reason to use `for` vs `while` whatsoever. –  Apr 24 '15 at 18:06
  • @vaxquis you still have the initialization; I would have gone with `int count = 2; while( zahl % count && zahl >= count ) ++count;` to begin with anyway :D – Massa Apr 25 '15 at 19:08
41

The semicolon at the end of the for-loop means it has no body. Without this semicolon, C thinks the if statement is the body of the for loop.

David says Reinstate Monica
  • 16,634
  • 19
  • 69
  • 108
Rohn Adams
  • 812
  • 7
  • 16
  • 4
    +int(PI/3) for being spot-on without going into "is it good/bad coding practice" debate. –  Apr 24 '15 at 18:07
  • Definately +1, a clean, short factual answer that doesn't try and declare the code to be bador poor style. – Vality Apr 24 '15 at 21:20
  • 1
    The for loop definitely has a body. It's just that the body consists solely of the null statement, `;`. A lone `;` is valid practically (if not actually) in every place where a statement is allowed, because a lone `;` is a null statement (which is a statement). – user Apr 24 '15 at 21:51
22

Syntax of for loop (iteration statement) is

for ( clause-1 ; expression-2 ; expression-3 ) statement 

statement can be a null statement (;). C11 6.8.3 says

A null statement (consisting of just a semicolon) performs no operations.

In para 5 it gives an example

In the program fragment

char *s;
/* ... */
while (*s++ != '\0')
    ;

a null statement is used to supply an empty loop body to the iteration statement.

Same thing is happening in

for (count = 2; zahl % count != 0 && zahl >= count; count++);

; is used to supply an empty loop body to the for statement. Without ; the statement next to the for loop will be considered as its body and will be executed.

haccks
  • 97,141
  • 23
  • 153
  • 244
  • 1
    +int(PI/3) for being spot-on without going into "is it good/bad coding practice" debate. –  Apr 24 '15 at 18:07
  • @vaxquis; Yes, because question is about *"why the for-loop has `;` at the end?"*. It is not about *"whether it is good a practice or not?"*. – haccks Apr 24 '15 at 18:14
17

In addition to what the other excellent answers already say, I would like to point out that

for(count=2; zahl % count != 0 && zahl >= count; count++);

(that is, a for loop with an empty statement used to increment a "counter") is equivalent to

count=2;
while(zahl % count != 0  && zahl >= count)
{
    count++;
}

that would make the objective of the code even clearer than some of the listed alternatives: if not comments are present, as in the presented case, a loop with an empty statement might confuse another programmer that has to mantain or use the code (as was the case with the OP here).

The context might help discerning the true scope of the statement, but between a for loop with an empty statement and a while loop with a statement, the latter requires less work to understand its scope.

Federico
  • 1,032
  • 3
  • 15
  • 33
  • 1
    Minor nitpick: this is not strictly equivalent since in the second version `count` is declared in a larger scope. – coredump Apr 24 '15 at 19:26
  • I mean, in general... here `count` is declared at the beginning of the function in both versions. – coredump Apr 24 '15 at 19:49
  • 2
    @coredump: Considering that the purpose of this loop--in this particular case--is to get `count` to the correct value so it can be used further on, `count` does have to exist in a larger scope in order for that to work at all and therefore it is exactly equivalent. (It's still an ugly abuse of a `for` loop, though, and Federico is right that this is The Right Way to express the semantics involved.) – Mason Wheeler Apr 24 '15 at 20:31
  • @MasonWheeler Yes, I was thinking about the general case. Both are indeed equivalent here. – coredump Apr 24 '15 at 20:45
  • 1
    Why is the for loop unclear? I understood a for loop was there explicitly to have an initialization, a condition and an iterating statement bundled together logically. It is never necessary to use a for loop but that case seemed sensible and cleanly written. – Vality Apr 24 '15 at 21:23
  • This would be a much better answer if it explained *why* the claim made holds, and *why* this answers the question as asked. Yes, you can rewrite one to the other with little ill effect, but I don't see how stating that helps the OP understand what the semicolon is doing at the end of the `for(...);` line. – user Apr 24 '15 at 21:53
12

The ; after the for loop simply means that the for loop won't do anything more than increase the counter count.

12

for Statement:

The for statement is a loop statement whose structure allows easy variable initialization, expression testing, and variable modification. It is very convenient for making counter-controlled loops. Here is the general form of the for statement:

 for (initialize; test; step)
   statement

[...]

Null Statement:

The null statement is merely a semicolon alone.

 ;

A null statement does not do anything. It does not store a value anywhere. It does not cause time to pass during the execution of your program.

Most often, a null statement is used as the body of a loop statement, or as one or more of the expressions in a for statement. Here is an example of a for statement that uses the null statement as the body of the loop (and also calculates the integer square root of n, just for fun):

 for (i = 1; i*i < n; i++)
   ;

Here is another example that uses the null statement as the body of a for loop and also produces output:

 for (x = 1; x <= 5; printf ("x is now %d\n", x), x++)
   ;

A null statement is also sometimes used to follow a label that would otherwise be the last thing in a block.


In your case, the ; is the Null Statement of the for Statement:

int func_prim (int zahl) {
  int count;
  if (zahl < 0)
    return -1;

  for (count = 2; zahl % count != 0 && zahl >= count; count++)
    ;
  if (count == zahl)
    return 1;
  return 0;
}

Without it, the if becomes the for statement:

int func_prim (int zahl) {
  int count;
  if (zahl < 0)
    return -1;

  for (count = 2; zahl % count != 0 && zahl >= count; count++)
    if (count == zahl)
      return 1;
  return 0;
}

Therefore, behaving differently.

falsarella
  • 11,640
  • 8
  • 65
  • 104
10

The for loop is there just to increase the value of count.

bmpasini
  • 1,433
  • 1
  • 19
  • 42
9

a for loop will (normally) have a body,

where the body is enclosed in braces { }

However, for a single statement body, the braces are optional.

; is an empty statement.

Combining the above it becomes obvious that the for loop executes until the condition becomes false.

John Alexiou
  • 23,931
  • 6
  • 67
  • 123
user3629249
  • 15,593
  • 1
  • 16
  • 17
6

The for loop is basically looping through all the numbers that are less than or equal to zahl but greater than 2 and storing it in the variable count. As it loops through all these numbers it is checking to see if zahl is divisible by count. If zahl is divisible by count, the loop is stopped. Otherwise, the loop is stopped when count equals zahl.

The if statement after the for loop checks to see if count is equal to zahl. If it is, then that must mean that the loop went through all the numbers less than zahl and greater than 2. This means that zahl is divisible by all the numbers less than itself and greater 2, which makes zahl prime.

Zachary Vance
  • 583
  • 2
  • 15
Ace
  • 157
  • 2
  • 13
0

It indicates the statement the for loop is used for. It can't be empty. At least it should include a single statement. ; is the empty statement which the iteration is done for.

hamidi
  • 1,343
  • 1
  • 12
  • 22