Wednesday, May 5, 2010

Loop variable scope and defining variables

Now let's add some things to this program. For example, let it print the parameters it was started with.
#include
int main(int argc, char* argv[])
{
{
for (int count = 0; count < argc; ++count)
{
cout << count << " : " << argv[count]
<< endl;
}
}
return 0;
}
You can compile and run:
[d:\cppintro\lesson1]gcc parprint.cpp -lstdcpp
[d:\cppintro\lesson1]parprint tripp trapp trull
0 : D:\TMP\PARPRINT.EXE
1 : tripp
2 : trapp
3 : trull
The result is probably not surprising, but if you know C, this does look interesting, does it not? The loop variable used for the "for" loop on is defined in the loop itself. One of the minor, yet very useful, differences from C is that you can leave defining a variable until you need it. In this case, the variable "count" is not needed until the loop, thus we don't define it until the loop. The loop is in an extra block (a { ... } pair is called a block) for compatibility between older and newer C++ compilers. For older C++ compilers, such as Visual Age C++, the variable "count" is defined from the "for" loop and until the "}" before "return". For newer C++ compilers, the variable is defined within the loop only.
Here's a "for" loop convention that's useful when you want your programs to work both with new and old C++ compilers:
If you define a loop variable, and want it valid within the loop only, enclose the loop in an extra block:
{
for (unsigned var = 0; var < max; ++var)
{
...
}
}
If you define a loop variable and want it valid after the loop body, define the variable outside the loop:
unsigned var = 0;
for (; var < max; ++var )
{
...
}
The former guarantees that the loop variable will not be defined after the last "}", be it on a new or old compiler. The latter guarantees that the loop variable *will* be defined after the loop for both new and old compilers.
Usually you don't want to use the loop variable after the loop, so the latter construction is not used frequently.
Let's have a closer look at the rules for when a variable is available and when it is not.
#include
int i = 5; // **1** global variable.
int main(int argc, char**)
{
cout << i << endl; // **2** the global i.
int i = 2; // **3**
cout << i << endl; // **4** i from prev. line
if (argc > 1)
{
cout << i << endl; // **5** prints 2.
int i = 10; // **6**
cout << i << endl; // **7** Prints 10.
}
cout << i << endl; // **8** Prints 2.
cout << ::i << endl; // **9** prints 5
return 0;
}
First we can see two new things. C++ has two kinds of comments. The C style "/*", "*/" pair, and the one line "//" comment. For the latter, everything following "//" on a line is a comment [to the end of line -- Ed].
The other new thing is the parameter list of "main". The second parameter is nameless. C++ allows you to skip the name of a parameter you are not going to use. Normally of course you do not have a parameter in the list that you're not going to use, but the "main" function is supposed to have these parameters (or void) so there's not much choice here. By not giving the parameter a name we save ourselves from a compiler warning like 'Parameter "argv" of function "main" declared but never referenced'.
So then, let's look at the variables.
At **1** a global variable called "i" is defined, and initialised with the value 5.
At **2** this global variable is printed. Yes, there is a variable called "i" in "main" but it has not yet been defined, thus it is the global one that is printed. [Note in the example how the variable "i" in "main" is defined the line after the output at **2**; not just given a value there, but actually declared as a variable there -- Ed]
At **3** the auto variable "i" of "main" is defined. From this point on, trickery is needed (see **9**) to reach the global "i" from within "main," since this "i" hides the name.
This is why, at **4**, the variable defined at **3** is printed, and not the global alternative. The same thing happens at **5**.
At **6** yet another variable named "i" is defined, and this one hides the variable defined at **3** and the global alternative from **1**. The global "i" can still be reached (see **9**), but the one from **3** is now unreachable.
As expected, the variable printed at **7** is the one defined at **6**.
Between **7** and **8** however, the "i" defined at **6** goes out of scope. It ceases to exist, it dies. Thus, at **8** we can again reach the "i" defined at **3**.
At **9** a cheat is used to reach the global "i" from within main. The "::" operator, called the scope operator, tells C++ to look for the name in the global scope, which makes it reach the variable from **1**.
[Note: a good C++ compiler will warn you if you declare a variable with the same name as one already accessible to your function (eg like at **6**), to alert you to the possibility that you are referring to the wrong variable. This is often described as one variable "shadowing" the other one -- Ed]

No comments:

Post a Comment