3

I'm currently trying to loop over a collection retrieved by an API in C.

The API offers a function getNext() that returns a reference to the next element in the collection, or NULL if the end has been reached.

Now i wanted to declare a variable in a while expression and loop until NULL:

// create collection from API
Collection collection = create();

if (collection == NULL) {
  return -1
}

while (const Element *e = getNext(collection) != NULL) {
  // print data from e
}

When compiling, 'error: unexpected expression' pops up. Why does that statement not work in C? How can I loop over the collection when all I have is a function getNext() that returns either an element or NULL?

I also tried the following, but the same error occured:

while ((const Element *e = getNext(collection)) != NULL) {
  // print data from e
}

5 Answers 5

6

It is not possible because while() expects an expression and it is not possible to place a declaration in the expression (though it is possible to introduce a new type with expression!).

The best you can get is:

const Element *e;
while ((e = getNext(collection)) != NULL) {
  // print data from e
}

It is however possible to achieve the desired functionlity with a for loop.

for (const Element *e; (e = getNext(collection)) != NULL; ) {
  // print data from e
}
Sign up to request clarification or add additional context in comments.

2 Comments

@TedLyngmo, good observation, there are even more bizarre tricks with for loop. It is even possible to emulate if (type x = expr; x)
You can add an hanging block to further limit the scope: int e = 42; { const Element *e; while (e = getNext(collection)) { /* e is a pointer here */ } /* e is a pointer here */ } /* e is int here */
2

First of all, in contrast to a for statement, you cannot declare a new variable in a while statement. Therefore, the following line is wrong:

while (const Element *e = getNext(collection) != NULL) {

You could fix this by writing the following:

const Element *e;

while ( e = getNext(collection) != NULL ) {

A more compact way of writing this is the following:

for ( const Element *e; e = getNext(collection) != NULL ; ) {

The second version has the advantage that the scope of the variable e is limited to the for loop.

However, the lines mentioned above are also wrong, for the following reason:

The != operator has higher precedence than =. So the line

while ( e = getNext(collection) != NULL) {

is equivalent to:

while ( e = ( getNext(collection) != NULL ) ) {

This is not want you want. You should write the following instead:

while ( ( e = getNext(collection) ) != NULL ) {

7 Comments

"You could fix this by writing the following" - { const Element *e; while(...) {} } would be more similar to what OP wants in terms of context (I think).
@TedLyngmo: I don't understand what you are suggesting. Are you suggesting that I put it everything into an extra code block by adding { and } around everything? That is the only difference I can find between your suggested code and my code.
Yes, that's exactly it. It gives the variable the same (limited) context as I think OP was aiming for.
@TedLyngmo: I don't have the impression that OP is concerned with the scope of the variable e. If they are indeed concerned with the scope, it would probably be best to use for, as shown in my answer, instead of using while and adding an additional code block.
The solution isn't to spam parenthesis all over but to get rid of the assignment inside the loop condition.
|
0

In C, you can't declare a variable in the condition expression of a while loop.

GCC will tell you:

Error: Expected expression before 'const'

Comments

0

I would write something like this, hope it can help :)

void main()
{
    bool running = true;
    while(running)
    {
        printf("Running while loop\n");
        running = getNext() != NULL; //Check if there is data in your collection - otherwise exit
    }
    printf("getNext() returned NULL\n");
    return;
}

Comments

0

Some rules of thumb in C programming are: "don't do really strange things" and "never do assignments inside control or loop statements". Turns out that we can follow these rules and solve all problems by using a for loop:

for(const Element* e = getNext(collection); e != NULL; e = getNext(collection))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.