14

I have two variables and I want to work with the bigger and the smaller one differently.

My approach:

a = 1;
b = 2;

if (a >= b){
    int c = a;
    int d = b;
}
else{
    int c = b;
    int d = a;
}

I obtained an error of unused variable and when I try to use c and d later, it says

c could not be resolved

Is there a way to solve this?

Stack Danny
  • 7,754
  • 2
  • 26
  • 55
Laura Pinguicha
  • 189
  • 2
  • 6
  • https://en.cppreference.com/w/cpp/language/scope This provides some good guidance on how where you declare stuff in general affects where/how you can then use it at later points in your program – abcalphabet May 03 '19 at 14:22
  • 3
    Duplicate of [Scope of variables in if statements](https://stackoverflow.com/questions/8543167/scope-of-variables-in-if-statements) – jpmc26 May 03 '19 at 15:24

4 Answers4

30

In both cases c and d are scoped to the braces in the if else block, so you can't access them outside that.

You need something of the form

int c, d;
if (a >= b){
    c = a;
    d = b;
} else {
    c = b;
    d = a;
}
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
21

As other have pointed out the issue here is where you declare the variables. You cannot use them outside of the scope they are declared in so you get an error.

If you can use C++17 then you can fix the code by using std::minmax and a structured binding like

int main()
{
    int a = 5, b = 10;
    auto [min, max] = std::minmax(b, a);
    std::cout << min << " " << max;
}

which is really nice because now you don't have variables that are uninitialized for any amount of time.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
6

It's because you are declaring the variables in an if statement.

Logically you may be of the belief that the else in a way guarantees that the variables will be assigned if the declaration is in both the if and also in the else block.

The correct way to do it is to just declare the variables before the if block, otherwise the variables use will be restricted to the scope from which it was declared.

Also, you can do this without the need for an if and else by using ternary operations:

        int a = 1;
        int b = 2;

        int c = a >= b ? a : b;
        int d = b < a ? b : a;

With this type of syntax, you can save yourself the hassle of writing if and else blocks for simple variable assignments. The variable after the ? is the result if the condition is true, and the variable after the : is the result if the condition is false.

Elroy Jetson
  • 938
  • 11
  • 27
  • 1
    The problem is not *setting* variables in an `if` statement, the problem is *declaring* them in there. – Angew is no longer proud of SO May 03 '19 at 12:52
  • 1
    I didn't downvoted, but this is certainly because of the lack of explanations – Cid May 03 '19 at 12:52
  • 2
    It has nothing to do where the variables are "set". It is where where they are declared. This answer really need some fleshing out. – NathanOliver May 03 '19 at 12:52
  • 1
    @Angew understood. Of course this is what I meant. I will edit. – Elroy Jetson May 03 '19 at 12:53
  • `the declaration […] may or may not actually happen` - this is what troubles me. It's also wrong as either branch will be executed so declaration will happen. This is, of course, irrelevant as the scope ends but for someone who doesn't understand the concept of scoping this will enhance their confusion. – Stack Danny May 03 '19 at 13:06
  • 1
    The problem with the ternary approach is that you essentially repeat the condition check. – Bathsheba May 03 '19 at 13:09
  • @Bathsheba true, but I would argue that if the condition check is a constant time operation, such as checking whether an `int` is greater than or less than some other `int`, then the repeating of the condition check is justifiable if it makes the code more readable. Just my perspective. – Elroy Jetson May 03 '19 at 13:11
  • @ElroyJetson: It's *maintainability*, not performance that concerns me here. – Bathsheba May 03 '19 at 13:11
  • @Bathsheba thanks for adding your perspective. I myself believe that by making something more **readable** it actually increases **maintainability** I just think `if` `else` blocks for assigning variables can sometimes be better served as a ternary statement. Just my opinion – Elroy Jetson May 03 '19 at 13:18
  • @StackDanny I agree – Elroy Jetson May 03 '19 at 13:32
  • @ElroyJetson the problem is what if you spot the bug that you got the variables the wrong way round, so you correct it. But now you have to fix it in 2 places. If it becomes more complex in the future you have to maintain the code twice. – Tom Bowen May 03 '19 at 15:08
  • @Tom.Bowen89 aha! Thanks for your explanation, I had never really considered that. I guess my underlying assumption is that your ternary statements should be simple by nature, i.e. if it starts becoming complex then the ternary statement is the wrong tool for the job. But your point is something I had not considered before. I will keep this in mind! – Elroy Jetson May 03 '19 at 15:12
4

That's a scope problem, you are creating the variables inside a scope and they can't be accessed outside

if (a >= b){
    int c = a;  // c and d belongs to that if scope
    int d = b;
}
else{
    int c = b;  // c and d belongs to that else scope
    int d = a;
}

Change your code to this :

a = 1;
b = 2;
int c;
int d;

if (a >= b){
    c = a;
    d = b;
}
else{
    c = b;
    d = a;
}
// You can now call c and d there

A way to shorten that code would be to store the boolean value of a >= b and use it in a ternary expression to set c and d

In example :

a = 1;
b = 2;
bool IsAGreaterOrEqualToB = (a >= b);
int c = ((IsAGreaterOrEqualToB) ? (a) : (b));
int d = ((IsAGreaterOrEqualToB) ? (b) : (a));
Cid
  • 14,968
  • 4
  • 30
  • 45
  • 2
    You've got quite a few brackets there. How come? Also I'd add in some `const` but otherwise yes this is good. Prefer init over assignment! – Lightness Races in Orbit May 03 '19 at 13:02
  • @LightnessRacesinOrbit this is an old habit I have. Like when I return something, I am used to write : `return (MyVar);` – Cid May 03 '19 at 13:04
  • 2
    Okay, but why is that? It just adds noise! `? (a) : (b)` is harder to read than `? a : b` :( – Lightness Races in Orbit May 03 '19 at 13:05
  • @Cid: That is occasionally harmful in C++ by the way. – Bathsheba May 03 '19 at 13:06
  • @LightnessRacesinOrbit that's just an habit, it helped me to separate the differents parts (especially when i wrote some nested ternary) Feel free to edit my answer if you think this may be more readable, answers are made for others – Cid May 03 '19 at 13:10
  • @Bathsheba would you please point me some examples ? I'm curious – Cid May 03 '19 at 13:11
  • @Cid: It wreaks havoc with `decltype(auto)`. See https://stackoverflow.com/questions/24109737/what-are-some-uses-of-decltypeauto – Bathsheba May 03 '19 at 13:12
  • Doesn't it also prevent RVO? Perhaps even the xvalueness of the result, preventing a move (C++17)? – Lightness Races in Orbit May 03 '19 at 13:36
  • https://stackoverflow.com/a/25615981/560648 at least. Really, try to avoid superfluous parens. – Lightness Races in Orbit May 03 '19 at 13:36
  • There's no need for the extra variable. `(a >= b) ? a : b` is at least as clear as `(IsAGreaterOrEqualToB) ? (a) : (b)`, and any reasonable optimizing compiler will recognize the potential for common subexpression elimination, so it's not less efficient either. – Ray May 03 '19 at 14:44