Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > scoping within for loops

Reply
Thread Tools

scoping within for loops

 
 
Stephen J. Fromm
Guest
Posts: n/a
 
      06-26-2003
What are the scoping rules for a for loop?

Example:

int i;
for(i = 0; i < 10; i++) {
int j;

/* more code here */

}

In this example, is the scope (a) "renewed" upon each iteration of
loop, or (b)common across all iterations? (My impression from
compiling code is "(a)").

This is in reference to scoping within blocks: one can write, absent
any control structure,
{
int j = 7;
/* more code */
}
and the lifetime of j is confined to the { }s, if I recall correctly.
With this in mind, (a) is like
int i = 0;
{
int j;
/* more code */
}
/* test i */
{
int j; /* New "instance" of j */
/* more code (again) */
}
....

whereas (b) is like
int i = 0;
{
int j; /* only 1 instance of j */
/* more code */

/* test i */

/* more code */
}

TIA,

sjfromm
 
Reply With Quote
 
 
 
 
Derk Gwen
Guest
Posts: n/a
 
      06-26-2003
http://www.velocityreviews.com/forums/(E-Mail Removed) (Stephen J. Fromm) wrote:
# What are the scoping rules for a for loop?
#
# Example:
#
# int i;
# for(i = 0; i < 10; i++) {
# int j;
#
# /* more code here */
#
# }
#
# In this example, is the scope (a) "renewed" upon each iteration of
# loop, or (b)common across all iterations? (My impression from
# compiling code is "(a)").

j is local to the surrounding {...}. It's value is undefined from the
beginning of the block until initialised or assigned a value. That's
all you should really concern yourself with.

for (...)
if (...) {
int j;
}else {
float k;
}

It is possible j and k will be assigned the same place in the stack frame.
With each iteration that slot in the stack frame might hold the previous
value of j, of k, or of anything else.

# and the lifetime of j is confined to the { }s, if I recall correctly.
# With this in mind, (a) is like
# int i = 0;
# {
# int j;
# /* more code */
# }
# /* test i */
# {
# int j; /* New "instance" of j */
# /* more code (again) */
# }

In non-iterative code, the variables in disjoint blocks may be overlapped or
disjoint at the compiler's discretion. There no universally correct answer.
Within a loop a compiler will assign a variable to the same stack frame offset,
but that's for a practical reason: otherwise the stack frame could grow
with each iteration and overflow the stack when there is no need to do so.
It's not something you should depend on though, since other code might use
the same slot without warning you.

--
Derk Gwen http://derkgwen.250free.com/html/index.html
Raining down sulphur is like an endurance trial, man. Genocide is the
most exhausting activity one can engage in. Next to soccer.
 
Reply With Quote
 
 
 
 
E. Robert Tisdale
Guest
Posts: n/a
 
      06-27-2003
Stephen J. Fromm wrote:

> What are the scoping rules for a for loop?
>
> Example:


> cat main.c

#include<stdio.h>

int main(int argc, char* argv[]) {
const int n = 10;
for (int i = 0; i < n; ++i) {
fprintf(stdout, "%d = i\n", i);
int i = 0;
fprintf(stdout, "%d = i\n", i);
}
return 0;
}

> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main

0 = i
0 = i
1 = i
0 = i
2 = i
0 = i
3 = i
0 = i
4 = i
0 = i
5 = i
0 = i
6 = i
0 = i
7 = i
0 = i
8 = i
0 = i
9 = i
0 = i

 
Reply With Quote
 
Stephen J. Fromm
Guest
Posts: n/a
 
      06-27-2003
"E. Robert Tisdale" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> Stephen J. Fromm wrote:
>
> > What are the scoping rules for a for loop?
> >
> > Example:

>
> > cat main.c

> #include<stdio.h>
>
> int main(int argc, char* argv[]) {
> const int n = 10;
> for (int i = 0; i < n; ++i) {
> fprintf(stdout, "%d = i\n", i);
> int i = 0;
> fprintf(stdout, "%d = i\n", i);
> }
> return 0;
> }


Thanks for your reply.

Very interesting example. While the "first i" and "second i" occur
within the same block, your example makes it appear there are is no
scoping conflict. Is this because
(a) scoping is largely dependent on declarations, and declarations
only extend downwards (here, the declarations *don't* occur in the
same block, and the "second i" is declared after the first one is used
but not declared), or
(b) gcc doesn't conform to some standard,
(c) c99 is different on this point than ANSI C (I guess that's c89 but
am not really sure.

Cheers,

S

>
> > gcc -Wall -std=c99 -pedantic -o main main.c
> > ./main

> 0 = i
> 0 = i
> 1 = i
> 0 = i
> 2 = i
> 0 = i
> 3 = i
> 0 = i
> 4 = i
> 0 = i
> 5 = i
> 0 = i
> 6 = i
> 0 = i
> 7 = i
> 0 = i
> 8 = i
> 0 = i
> 9 = i
> 0 = i

 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      06-27-2003
(E-Mail Removed) wrote:
>
> Stephen J. Fromm <(E-Mail Removed)> wrote:
> >
> > In this example, is the scope (a) "renewed" upon each iteration of
> > loop, or (b)common across all iterations? (My impression from
> > compiling code is "(a)").

>
> Correct. The loop body is entered and exited each time the loop
> repeats, so any variables that are declared within the loop body come
> into scope and go out of scope on each iteration.


More precisely, the scope of an identifier is static:
it is a consequence of the lexical structure of the program,
not of its behavior at run-time. The "scope" of an identifier
is the region of the code in which that identifier is associated
with a particular purpose -- its binding, if you will.

If an identifier refers to a data object (as opposed to,
say, an `enum' constant), we can also ask about the "storage
duration" of the object -- its "lifetime." When execution
enters a {}-enclosed block, the data objects for any `auto'
or `register' variables belonging to that block come into
existence. They remain in existence until execution leaves
the block, at which point they return to the limbo whence
they came. If the block is re-entered, new data objects are
created for the new execution; they may (or may not) occupy
the same memory locations as the data objects from the first
execution, but in every essential they are brand-new objects,
independent of those that existed the first time around.

An easy way to observe this independence is through
recursion:

void f(unsigned int depth) {
auto /* for emphasis */ int variable;
printf ("Entering level %u: `variable' is at %p\n",
depth, (void*) &variable);
if (depth > 0)
f(depth - 1);
printf ("Leaving level %u: `variable' is at %p\n",
depth, (void*) &variable);
}

Call this as `f(3)', say, and you'll easily see that the
identifier `variable' refers to different objects at different
executions of the {}-enclosed block that is the function body.

Back to the original question about a `for' loop (`while'
and `do' loops behave exactly the same way) of the form

for (i = 0; i < 10; ++i ) {
int j;
...
}

The scope of the identifier `j' extends from its declaration
to the ending } -- this is the static code region during which
the binding of `j' to a particular data object exists. The
ten executions of the loop body create and destroy ten data
objects for `j' to refer to. It will often turn out that the
ten objects will all occupy the same memory location or register,
but they are different objects nonetheless because their lifetimes
do not overlap. In particular, it is *not* guaranteed that a
value assigned to `j' in one iteration will still be intact
when the next iteration begins.

--
(E-Mail Removed)
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      06-27-2003
>> Stephen J. Fromm wrote:
>> > What are the scoping rules for a for loop?


>"E. Robert Tisdale" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
>> > cat main.c

>> #include<stdio.h>
>>
>> int main(int argc, char* argv[]) {
>> const int n = 10;
>> for (int i = 0; i < n; ++i) {
>> fprintf(stdout, "%d = i\n", i);
>> int i = 0;
>> fprintf(stdout, "%d = i\n", i);
>> }
>> return 0;
>> }


In article <(E-Mail Removed) >
Stephen J. Fromm <(E-Mail Removed)> writes:
>Very interesting example. While the "first i" and "second i" occur
>within the same block, your example makes it appear there are is no
>scoping conflict. Is this because
>(a) scoping is largely dependent on declarations, and declarations
>only extend downwards (here, the declarations *don't* occur in the
>same block, and the "second i" is declared after the first one is used
>but not declared), or
>(b) gcc doesn't conform to some standard,
>(c) c99 is different on this point than ANSI C (I guess that's c89 but
>am not really sure.


It is indeed an interesting example, and the answers to your three
questions are "yes (depending on what you mean by `largely')",
"no", and "no" (Not that gcc, even with -std=c99, quite conforms
to C99 -- but any nonconformance is not the reason the example
works. Further, "ANSI C" can be either or both of both C89 and
C99, depending on who is saying the words.)

According to the draft C99 standard I have handy in text form:

Except for the behavior of a continue statement in the
loop body, the statement

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

and the sequence of statements

{
clause-1 ;
while ( expr-2 ) {
statement
expr-3 ;
}
}

are equivalent ....

We are also told that:

Two identifiers have the same scope if and only if their
scopes terminate at the same point.

Applying the prescribed transformation to the loop:

for (int i = 0; i < n; i++)
{ ... }

produces:

{
int i = 0;
while (i < n) {
{ ... }
i++;
}
}

Note that we now have not one, nor even two, but THREE (!) sets of
scope-affecting "{}"s. The "for" loop's declaration of identifier
i occurs inside the outermost {}s and terminates at the final }.
The second declaration of "i" -- in the "..." part -- occurs inside
the innermost {}s and terminates at the first }. These two "i"s
thus have different scopes, and can (and do) name different objects.

The C99 standard's expansion, in which a "for" loop has at least
two implied "{"s, is the direct answer to your original question.
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
Micah Cowan
Guest
Posts: n/a
 
      06-28-2003
(E-Mail Removed) (Stephen J. Fromm) writes:

> "E. Robert Tisdale" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> > Stephen J. Fromm wrote:
> >
> > > What are the scoping rules for a for loop?
> > >
> > > Example:

> >
> > > cat main.c

> > #include<stdio.h>
> >
> > int main(int argc, char* argv[]) {
> > const int n = 10;
> > for (int i = 0; i < n; ++i) {
> > fprintf(stdout, "%d = i\n", i);
> > int i = 0;
> > fprintf(stdout, "%d = i\n", i);
> > }
> > return 0;
> > }

>
> Thanks for your reply.
>
> Very interesting example. While the "first i" and "second i" occur
> within the same block, your example makes it appear there are is no
> scoping conflict. Is this because
> (a) scoping is largely dependent on declarations, and declarations
> only extend downwards (here, the declarations *don't* occur in the
> same block, and the "second i" is declared after the first one is used
> but not declared), or
> (b) gcc doesn't conform to some standard,
> (c) c99 is different on this point than ANSI C (I guess that's c89 but
> am not really sure.


C99 *is* ANSI C--or more accurately, it is ISO C. It is the newer
standard.

C99 is *very* different on this point than C89, as in C89 both of the
above declarations of i are illegal. In the first case, declarations
are not allowed in the first clause of a for statement; in the second,
declarations must precede all statements at the same block level.

The answer to your question is: none of the above. The reason is that
the first i and second i *don't* occur within the same
block. Declarations occuring in the first clause of a for statement
exist in a block beginning right there, and extending to the end of
the statement (the end of the for loop). The second declaration,
however, exists within a separate, inner block which begins with the
opening { brace, and ends, along with the outer block, with the }
brace.

-Micah
 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      06-28-2003
Micah Cowan wrote:
> (E-Mail Removed) (Stephen J. Fromm) writes:
> > <(E-Mail Removed)> wrote:
> >

.... snip ...
> > >
> > > > cat main.c
> > > #include<stdio.h>
> > >
> > > int main(int argc, char* argv[]) {
> > > const int n = 10;
> > > for (int i = 0; i < n; ++i) {
> > > fprintf(stdout, "%d = i\n", i);
> > > int i = 0;
> > > fprintf(stdout, "%d = i\n", i);
> > > }
> > > return 0;
> > > }

> >

.... snip ...
>
> The answer to your question is: none of the above. The reason
> is that the first i and second i *don't* occur within the same
> block. Declarations occuring in the first clause of a for
> statement exist in a block beginning right there, and extending
> to the end of the statement (the end of the for loop). The
> second declaration, however, exists within a separate, inner
> block which begins with the opening { brace, and ends, along
> with the outer block, with the } brace.


Which is just the sort of thing that makes parsing C such a bear,
and impedes really serious complete description in BNF terms.
That means that a for statement needs to be described by something
like:

for-statement = 'for' <for-block>
for-block = '(' <for-header> ')' <statement-block>

to provide syntactical hooks for permissible declarations. It
gets worse.

--
Chuck F ((E-Mail Removed)) ((E-Mail Removed))
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!


 
Reply With Quote
 
Len Budney
Guest
Posts: n/a
 
      07-10-2003
(E-Mail Removed) (Stephen J. Fromm) wrote:
>
> I assume that's consistent with the example another poster (Tisdale)
> gave?:
>
> for (int i = 0; i < n; ++i) {
> fprintf(stdout, "%d = i\n", i);
> int i = 0;
> fprintf(stdout, "%d = i\n", i);
> }
>
> His example treats the two instances of i differently (as if the
> second were "j", not "i"). I'm assuming this is because "It's value
> is undefined from the beginning of the block until initialised or
> assigned a value."


No. At least, poorly articulated. The scope of the first 'i' is the
for statement and the dependent block--i.e., larger than the block.
The scope of the second 'i' is from its declaration to the end of the
block. The second 'i' hides the first 'i' within its scope--but at the
bottom of the block, the second 'i' passes out of scope, the loop
counter is exposed, and the loop condition is tested correctly.

Also note that the second 'i' behaves differently than if it were 'j',
in that the loop variable cannot be accessed from within the scope of
the second 'i'.

Some compilers, that don't implement C99 correctly (including VC++),
would treat the loop variable as having scope equal to the block
containing the for statement, and would disallow a loop later in the
block using 'i' as its counter.

> By "discretion", "no correct answer," "practical reason," "don't
> depend on it," I assume you mean there's nothing in the standards to
> make it go the way I think it goes.


Indubitably. Once a variable passes out of scope, its location may
contain the last value, another variable's value--in fact, anything.
With optimization turned on, it's very likely to contain something
else.

--Len.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problems with logic operations within loops Interrupt C Programming 46 01-30-2010 10:16 PM
Why no lexical scoping for a method within a class? walterbyrd Python 16 12-18-2008 01:15 AM
Newbie Question about multiple system calls within loops student.matt@gmail.com C Programming 23 07-01-2008 11:03 AM
Loops with loops using html-template Me Perl Misc 2 01-12-2006 05:07 PM
scoping with lambda in loops Ian McMeans Python 8 09-17-2003 03:47 PM



Advertisments