Order of execution question

C

Chad

Let's say I'm freeing a linked list like the following..


while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

When
current = current->next;

executes and updates 'current'. Will the value of 'current' in the
while loop get updated at the same time or is the order undefined?

Chad
 
K

Keith Thompson

Chad said:
Let's say I'm freeing a linked list like the following..


while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

When
current = current->next;

executes and updates 'current'. Will the value of 'current' in the
while loop get updated at the same time or is the order undefined?

The order is well defined.

The fact that you ask whether "the value of 'current' in the while
loop get(s) updated at the same time" makes me suspect you have a
misconception about how while loops work.

The condition in the while loop, ``current != NULL'', is relevant only
at the top of the loop. The body of the loop is executed
sequentially; the condition is re-checked only after the current
iteration of the body of the loop has finished.
 
C

Chad

There's nothing wrong with your posted code.

'current' appears four times in the loop,
and I don't know exactly what you mean.

i = i + 1; is well defined.

Are you asking something like that?

When the following executes

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

and when it gets to
current = current->next;

The value of 'current' in current = current->next will get updated.
For whatever reasons, I was thinking that when this happens that the
value of 'current' in

while( current != NULL )

got updated at the same time. Keith pointed out that it doesn't.



Chad
 
C

CBFalconer

Chad said:
Let's say I'm freeing a linked list like the following..

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

When
current = current->next;

executes and updates 'current'. Will the value of 'current' in the
while loop get updated at the same time or is the order undefined?

I would get very nervous, because you are declaring temp within the
loop, and the update is done by the initialization code. I would
suggest the safe:

name *temp; /* in the appropriate declaration section */
...
while (current) {
temp = current;
current = current->next;
free(temp);
}
 
C

CBFalconer

pete said:
I don't perceive any problems with any of that.

What's wrong with declaring temp in a loop
and doing the update with the initialization code?

Strictly speaking, probably nothing. I haven't examined the
standard to resolve it. However, it would be just the sort of
thing that could be missed when constructing the compiler, so my
following suggested code is 'safe'. In addition, it doesn't give
up anything except restricting the scope of temp.
 
L

lovecreatesbea...

When the following executes

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

and when it gets to
current = current->next;

When the control flow comes here, it doesn't remain there - ``while
(current != NULL)''. You can't step in a rive twice at one time,
right?
The value of 'current' in current = current->next will get updated.
For whatever reasons, I was thinking that when this happens that the
value of 'current' in

while( current != NULL )

got updated at the same time.

They are the same pointer, same variable. When it comes to ``while
(current != NULL)'' and evaluates the expression next time, the
updated value (by current = current->next) takes effect.
Keith pointed out that it doesn't.

: )

I think Keith didn't mean what you say.
 
D

Dand

Let's say I'm freeing a linked list like the following..


while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

When
current = current->next;

executes and updates 'current'. Will the value of 'current' in the
while loop get updated at the same time or is the order undefined?

The while does not continously check current, it only checks it when it has
finished all the commands in-between the { } brackets, and when it first
starts.

Current is updated immedaitly, but the test for the while loop does not
happen until after free(temp); has completed.
Only 1 thing is ever done at once, in this chase the order of command is
predetermined as:
-Test if current is not equal to null
-assign temp
-assign current
-free temp
-Test if current is not equal to null
....
so on and so on (so long as current is not equal to null).
 
D

Dand

Strictly speaking, probably nothing. I haven't examined the
standard to resolve it. However, it would be just the sort of
thing that could be missed when constructing the compiler, so my
following suggested code is 'safe'. In addition, it doesn't give
up anything except restricting the scope of temp.

Interesting, where I work we are also told to make the scope as small as
possible and often do it like that. Haven't seen a compiler yet that doesn't
know to use the same memory. I doupt the standard says memory/registers must
be freed immediatly when something goes out of scope, so its interesting. I
guess a compiler would have to be extremely stupid.
 
K

Keith Thompson

CBFalconer said:
I would get very nervous, because you are declaring temp within the
loop, and the update is done by the initialization code. I would
suggest the safe:

name *temp; /* in the appropriate declaration section */
...
while (current) {
temp = current;
current = current->next;
free(temp);
}

There's no problem. temp is simply declared in a compound statement
(surrounded by '{' ... '}'); the fact that the compound statement
happens to be the body of a loop doesn't create any additional issues.
The code is fine as it is, and declaring temp within the compound
statement is perfectly sensible.
 
K

Keith Thompson

When the control flow comes here, it doesn't remain there - ``while
(current != NULL)''. You can't step in a rive twice at one time,
right?


They are the same pointer, same variable. When it comes to ``while
(current != NULL)'' and evaluates the expression next time, the
updated value (by current = current->next) takes effect.


: )

I think Keith didn't mean what you say.

I think I did.

The point is that the condition is evaluated once for each iteration
of the loop, not continuously as the body of the loop is executed.
Any changes to variables that happen to be referred to in the
condition have no effect on the execution of the loop until the
condition is re-evaluated. (I remember having a similar
misunderstanding many years ago.)
 
V

viza

Interesting, where I work we are also told to make the scope as small as
possible and often do it like that. Haven't seen a compiler yet that
doesn't know to use the same memory. I doupt the standard says
memory/registers must be freed immediatly when something goes out of
scope, so its interesting. I guess a compiler would have to be extremely
stupid.

I also try to do this as much as possible. If it was a very stupid
compiler the worst I can imagine it doing is lots of repeated push sizeof
(temp), pop sizeof(temp).

[OT] Dand, please don't strip the attribution lines from the top of
quoted text.

viza
 
C

CBFalconer

Dand said:
Interesting, where I work we are also told to make the scope as
small as possible and often do it like that. Haven't seen a
compiler yet that doesn't know to use the same memory. I doupt
the standard says memory/registers must be freed immediatly when
something goes out of scope, so its interesting. I guess a
compiler would have to be extremely stupid.

It has nothing to do with 'using the same memory'. The point is
that you are initializing the variable on entry to the while loop.
You want that initialization code to be executed on every pass
through the loop, not on the entry to the loop. So I recommend
saying what you mean.

In addition using that construct requires a C99 compiler. My
method only requires a C90 compiler.
 
N

nicolas.sitbon

It has nothing to do with 'using the same memory'.  The point is
that you are initializing the variable on entry to the while loop.
You want that initialization code to be executed on every pass
through the loop, not on the entry to the loop.  So I recommend
saying what you mean.

In addition using that construct requires a C99 compiler.  My
method only requires a C90 compiler.

Encapsulation (in that case, restriction of scope) is a good practice,
that construct, in fact, doesn't require a C99 compiler.
 
K

Keith Thompson

CBFalconer said:
It has nothing to do with 'using the same memory'. The point is
that you are initializing the variable on entry to the while loop.
You want that initialization code to be executed on every pass
through the loop, not on the entry to the loop. So I recommend
saying what you mean.

In addition using that construct requires a C99 compiler. My
method only requires a C90 compiler.

Huh??

Here's the code in question:

| while( current != NULL )
| {
| name* temp = current;
| current = current->next;
| free( temp );
| }

temp is initialized on each execution of the compound statement, i.e.,
on each iteration of the loop, which is exactly what you want.

Declarations at the beginning of a compound statement have always been
supported; they are not a C99-specific feature.

Here's a complete (but non-functional) program that incorporates the
above fragment. Compile it with whatever strict C90 options you like
to convince yourself that it doesn't depend on C99. And consult the
standard to convince yourself that temp is initialized on each
iteration of the loop, exactly as it needs to be, and there's no
benefit to moving its declaration outside the loop.

#include <stdlib.h>

int main(void)
{
typedef struct name {
struct name *next;
} name;

struct name *current = NULL;

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}
return 0;
}
 
C

CBFalconer

Keith said:
.... snip ...


Huh??

Here's the code in question:

| while( current != NULL )
| {
| name* temp = current;
| current = current->next;
| free( temp );
| }

temp is initialized on each execution of the compound statement, i.e.,
on each iteration of the loop, which is exactly what you want.

Declarations at the beginning of a compound statement have always been
supported; they are not a C99-specific feature.

Here's a complete (but non-functional) program that incorporates the
above fragment. Compile it with whatever strict C90 options you like
to convince yourself that it doesn't depend on C99. And consult the
standard to convince yourself that temp is initialized on each
iteration of the loop, exactly as it needs to be, and there's no
benefit to moving its declaration outside the loop.

#include <stdlib.h>

int main(void)
{
typedef struct name {
struct name *next;
} name;

struct name *current = NULL;

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}
return 0;
}

I may be mistaken about the C90 problem. However, you must admit
that making the initialization repeat at every loop through the
while, while not assigning further data space at the same time, is
a complication. My simple code avoids that problem.
 
B

Ben Bacarisse

CBFalconer said:
I may be mistaken about the C90 problem. However, you must admit
that making the initialization repeat at every loop through the
while, while not assigning further data space at the same time, is
a complication.

I don't admit that and I would be very surprised if anyone else
did[1]. The assignment needs to be repeated every time, and I can't
see any reason why a declaration is worse. It has the advantage of
reducing the scope of the variable and, as a major UK retailer says,
every little helps.
My simple code avoids that problem.

I see no problem to avoid.

[1] But c.l.c never fails to surprise me, so lets see...
 
H

Harald van Dijk

The local declaration and initialization of temp.

C90 does not allow declarations and initialisation of variables at the
start of a block? Are you sure about that? In an earlier message, you
stated that you hadn't examined the standard. Have you now?
 
K

Keith Thompson

CBFalconer said:
I may be mistaken about the C90 problem. However, you must admit
that making the initialization repeat at every loop through the
while, while not assigning further data space at the same time, is
a complication. My simple code avoids that problem.

I've retained the entire context to avoid any possible
misunderstanding.

Yes, you are mistaken about the C90 problem. Declarations within
compound statements have always been supported. Look it up in K&R
(either edition) or in your n869_txt.bz2.

And no, I do not admit that repeating the initialization is a
complication. In fact, I firmly deny it; it is a simplification.

The original code was:

while( current != NULL )
{
name* temp = current;
current = current->next;
free( temp );
}

Your suggested replacement was:

name *temp; /* in the appropriate declaration section */
...
while (current) {
temp = current;
current = current->next;
free(temp);
}

You replaced an initialization (executed on each iteration of the
loop) with an equivalent assignment (executed on each iteration of the
loop). You widened the visibility of temp, making it more difficult
to confirm that it's not used before or after the loop.

The original code was quite simply better than your replacement
(though I prefer your layout). Just what improvement did you imagine
you were offering?
 
C

CBFalconer

Harald said:
C90 does not allow declarations and initialisation of variables
at the start of a block? Are you sure about that? In an earlier
message, you stated that you hadn't examined the standard. Have
you now?

No, I am very lazy. Also I believe I have put up sufficient (i.e.
any) reason for the safer code. It can't hurt.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top