2
#include <stdio.h>
#include <cs50.h>

int main(void)
{
    do
    {
        //ask for input with 1-8
        int height = get_int("Height: ");
    }
    while (height > 0);
}

And I got the error code: use of undeclared identifier "height" (in the while statement) I'm completely green to programming and I have no idea how to fix this. Can someone help?

Frankie_C
  • 4,764
  • 1
  • 13
  • 30
  • 1
    upper "do" line add "int height;" and then don't use type definition for the height in the loop. if before you define the variable so you can direct use it afterwards. – Bart Jan 15 '22 at 22:16
  • 1
    The scope of a variable declared in a block is local to that block. When you leave the `do` block it doesn't exist anymore. Define it at an upper scope level. – Frankie_C Jan 15 '22 at 22:17
  • It does *seem* like what you have should work, but sadly, `height` is defined in between the curly braces, and the `while` construct of the loop is technically outside of those braces (that block). You can look up "local variable scoping in C" for more details about how it works. – lurker Jan 15 '22 at 22:31
  • The problem: You declare the variable(height) in the 'do' block, but use it outside the block. Simple solution: move the declarition to the position before the 'do' block. Reference: https://en.cppreference.com/w/c/language/scope – Zongru Zhan Jan 17 '22 at 07:56

3 Answers3

3

The scope of the variable height is the body of the do..while loop. The condition of this loop is outside of the body, therefore height is not in scope in the loop condition.

Move the definition of height outside of the loop.

int height;
do
{
    //ask for input with 1-8
    height = get_int("Height: ");
}
while (height > 0);
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Alternatively, one could use `while (1) { int height = get_int("Height: "); if (height <= 0) break; }` to avoid "leaking" the variable. – ikegami Jan 15 '22 at 22:19
  • seems like the variable is needed - the purpose of the loop is to ask for the height and presumable use it further on – pm100 Jan 15 '22 at 22:33
  • @pm100 yes, to use it later on _inside_ the loop, as the loop terminates when height is zero. – Dúthomhas Jan 15 '22 at 23:14
  • Not having the condition include the scope of the body is one of the things that I personally think was a design mistake in C. – Dúthomhas Jan 15 '22 at 23:24
  • 1
    @Dúthomhas: Might be nice sometimes, but then there would be an asymmetry between `while` and `do … while` since we cannot extend the scope of something declared inside the body to the controlling expression of the `while` in the same way. – Eric Postpischil Jan 16 '22 at 00:38
  • @EricPostpischil Perhaps. There is no _technical_ reason for the limitation, as C++’s extended `while` syntax shows. And considerations about whether there should be symmetry in `while` and `do-while` loops is opinion. My opinion is that “symmetry” shouldn’t be a thing here and that both loops could easily share scope with condition and body. History doesn’t care about either of our opinions, though. It is what it is. – Dúthomhas Jan 16 '22 at 03:33
3

Height is not visible (nor exists) after the closing brace of the do body block. You must declare it outside of the loop. I've marked the points where height ceases to exist in comments below:

int main(void)
{
    do
    {
        //ask for input with 1-8
        int height = get_int("Height: ");
    } // <- the scope and visibility of height ends here
    while (height > 0); // ... so it doesn't exist here.
}

the solution is to declare height before the do keyword, as in:

int main(void)
{
    int height;
    do
    {
        //ask for input with 1-8
        height = get_int("Height: ");
    }
    while (height > 0); // now, height is visible here.
} // <-- visibility and scope of height ends here.

Another thing is that, if your intention is to ask for a height and repeat the question until height > 0, then you should write while (height <= 0) instead, (you repeat the question while the answer is not correct)

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
-1

EDIT: It has been pointed out to me that I misread your loop’s termination condition. (Sorry, insomnia.)

Possible Answer 1

As I read it, you appear to want to repeatedly do something with positive values of height, and terminate when an invalid value is given.

To make that happen, the correct thinking on this should be:

  1. Get a value
  2. If the value is zero, terminate the loop
  3. Else do stuff with the value

Hence:

while (true)
{
  int height = get_int("Height: ");
  if (height <= 0) break; // invalid height terminates loop

  // use height here //
}

Possible Answer 2

If your desire is to repeatedly ask for a height until the user gives you a valid value in order to continue, then the only answer is to move the value declaration out of the loop, as anything declared local to the loop will not be usable outside of the loop:

int height;
do {
  height = get_int("Height: ");
} while (height is not valid);

// use height here //

This is exactly as Luis Colorado explains, because he was awake enough to properly read your loop condition.

Useful stuff for C++ people finding this by title only

As I had previously misread the solution to terminate if height becomes zero (a common semaphore for homework problems involving integers), and because C++ people will also find this answer, I had also given a C++ solution where the condition and body share locality as follows:

In current versions of C++ you can integrate the variable into the loop condition:

while (int height = get_int("Height: "))
{
  // use height here //
}

I think this is true of C++11 or later, but it might have been introduced in C++14, IDK and don’t care to look it up. You should be using nothing less than C++17 these days...

This solution only works for variables that can be converted to truthy values — in this case, the loop terminates when height is zero.

In OP’s particular case, this won’t work.

Now go vote for Mr Colorado’s answer, because it explains the locality problem better.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39