#include // The following program compiles, but there is an // issue with the calculation. // // The program is intended to query the user for up // to 10 real numbers and then print their average. // The user may enter 0 to stop entering numbers // early. // // Can you determine why the program does not work // correctly? // // Try to identify the problem before reading the // explanation below. // Function declarations int main(); // Function definitions int main() { double sum{ 0.0 }; int n{ 0 }; for ( int n{ 0 }; n < 10; ++n ) { double value{}; std::cout << "Enter a real number " << "(0 to quit early): "; std::cin >> value; if ( value == 0.0 ) { break; } sum += value; } std::cout << "The average of your numbers is " << sum/n << "." << std::endl; return 0; } // Explanation: // // The problem is that 'n' is declared twice. // // First, 'n' is declared in the body of main(): // // int n{ 0 }; // // A second local variable named 'n' is then declared // in the initialization statement of the for loop: // // for ( int n{ 0 }; n < 10; ++n ) { // // These are two different local variables. // // The 'n' declared by the for loop shadows the 'n' // declared earlier. Consequently, the loop increments // its own local variable 'n', while the original 'n' // remains unchanged. // // When the loop terminates, the 'n' declared by the // for loop ceases to exist. The expression // // sum/n // // therefore uses the original 'n', which still has // the value 0. // // The solution is to use the original 'n' as the // loop variable rather than declaring a second // variable with the same name: // // int n{ 0 }; // // for ( n = 0; n < 10; ++n ) { // // Query for and process a value. // } // // After the loop terminates, 'n' then contains the // number of non-zero values that were entered. // There is one additional case to consider. // // What happens if the user enters 0 immediately? // // In that case, no values have been entered, so // 'n' is still 0. There is no average to calculate. // // We should therefore check whether n == 0 before // attempting to calculate sum/n. // Here is the corrected program: /* int main() { double sum{ 0.0 }; int n{ 0 }; for ( n = 0; n < 10; ++n ) { double value{}; std::cout << "Enter a real number " << "(0 to quit early): "; std::cin >> value; if ( value == 0.0 ) { break; } sum += value; } if ( n == 0 ) { std::cout << "No numbers were entered." << std::endl; } else { std::cout << "The average of your numbers is " << sum/n << "." << std::endl; } return 0; } */ // If this is still confusing, consider how the // compiler treats the two declarations. // // Despite having exactly the same name, the two // occurrences of 'n' identify different local // variables while inside the for loop. // // We could rename the variable declared by the // for loop without changing what the original // program does: // // int main() { // double sum{ 0.0 }; // int n{ 0 }; // // for ( int slartibartfast{ 0 }; // slartibartfast < 10; // ++slartibartfast ) { // double value{}; // // std::cout << "Enter a real number " // << "(0 to quit early): "; // std::cin >> value; // // if ( value == 0.0 ) { // break; // } // // sum += value; // } // // std::cout << "The average of your numbers is " // << sum/n << "." << std::endl; // // return 0; // } // // It is now much easier to see the problem: // the variable 'n' is initialized to 0 and is // never subsequently changed. // // Declaring a local variable with the same name as // another local variable that is still in scope is // called shadowing. Although C++ permits shadowing, // it can easily result in logic errors such as this.