1

I've just began my journey in coding and i've been using cs50's IDE. everytime I declare an integer in the main body of do function, I get an error for using undeclared indentifier when I try using the same integer in the body of while function, is this not allowed? if yes, why so?

Here's the code for reference -

do{

   int n = get_int("Height: ");

  }

while(n < 1 || n > 8);
Kirill
  • 7,580
  • 6
  • 44
  • 95

5 Answers5

2

The body (sub-statement) of the do-while statement forms a block scope. All that is declared within this block scope have the life-time limited by the bounds of the block (if not have the storage specifier static). But in any case such a declaration is invisible outside the block. So the variable n declared in this do while loop

do{

   int n = get_int("Height: ");

  }

while(n < 1 || n > 8);

is not alive outside the body (sub-statement) of the loop.

You have to declare the variable before the loop like

int n = 0;
do{

   n = get_int("Height: ");

  } while(n < 1 || n > 8);

According to the C Standard (6.8.5 Iteration statements) the do-while statement is defined like

do statement while ( expression ) ;

and

5 An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Yes you can. You can define them in any block of code including complex statement.

Bear in mind that the scope of those variables is the block they are declared in so in your case the do ... while() loop.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
0___________
  • 60,014
  • 4
  • 34
  • 74
0

Since C99, you can declare automatic variables in any scope, including nested block scopes like the one you show.

However, the variable declared only exists inside that scope. At the closing brace ... it vanishes.

So, the reason you get an undeclared identifier error in the while statement is that the identifier ceased existing at the } immediately before the while.

For reference:

void foo(int a)     /* a will exist for the entire body of the function */
{
    int b = 2 * a;  /* so will b */
                    /* c is introduced at the start of the for statement ... */
    for (int c = a; c < b; ++c)
    {
        int d = c;  /* d is initialized and destroyed on each iteration */
    }               /* ... but c lasts until the end of the whole for statement,
                       which is here */

    do
    {                   /* d will be initialized on every iteration */
        int d = bar();  /* just like the (unrelated) d in our for loop above */
    }                   /* and disappear at the end of each iteration */
    while (d != a);     /* ERROR - d doesn't exist here */
} /* a and b finally go out of scope */

FYI. in C89 - 99, you had to declare variables at the start of a block scope (typically the top-level function scope), after the opening { but before any other statements. This isn't true any more, but you may still see old code in the old style.

Useless
  • 64,155
  • 6
  • 88
  • 132
  • 1
    I love this: "since C99". The guys who ask it were not even born before C99 :). For them it is a prehistory. – 0___________ May 12 '20 at 19:14
  • 2
    Way to make me feel old :D – Useless May 12 '20 at 19:15
  • @P__J__, Isn't MS's current compiler based on C89? So not not exactly prehistory. (Though I believe said compiler does accept the style of declarations in question.) – ikegami May 12 '20 at 19:16
  • 2
    "In C89 you had to declare variables at the start of functions" - not true. It had to be at the start of a *scope*, but not necessarily the start of a function. – psmears May 12 '20 at 19:18
  • Hmm, was it K&R C that only supported variable declarations at function scope? OK, you're right, it _was_ a long time ago. – Useless May 12 '20 at 19:23
  • @ikegami no MS compiler is mainly C++. C compilation option is left for some historical reasons probably. – 0___________ May 12 '20 at 20:42
0

Caution: This answer shows an obscure construction.

If you are using GCC, check out this library. You can write something like this:

do(int n){

   n = get_int("Height: ");

  }

while(n < 1 || n > 8);
DaBler
  • 2,695
  • 2
  • 26
  • 46
0

The answers previous given are all good but you might have noticed a cautionary tale from all this. There is still a lot of code around that uses the C89 and before conventions, that has subsequently been added to modern projects. So beware of the following:

void my_old_function(int val)
{ 
    /* define old C89 variables, often including i,j, or k,  usually unitililized. */
    int i;  

    for (i=0; i<val; i++)
    {
        /* our legacy code */
    }

    // some modern edit in C99 or after
    do {
        int i = 0;
        // more new code

        i++;
    } while(i < val);  // not what you think it is !!!!
}

I have come across this code before. Crazy hard to find when the function is more that 70 or 80 lines (page length).
As a personal reminder to myself when dealing with inherited code, I usually do a quick scan looking for uninitialized automatics, which were common back in the day, and move them or given them better names.

bd2357
  • 704
  • 9
  • 17