Bay Conner
Bay Conner

Reputation: 41

C++ Passing By Reference Not Changing Argument

I've been staring at this for about an hour and I honestly have no idea what I'm missing.

#include <iostream>

using namespace std;

void callChain();

double chain(int, int &, int &);

int main()
{
    callChain();
}

void callChain() {
    int totalInches = 53;
    int feet;
    int inches;

    cout << "\nTesting chain for 53 inches: \nExpected result: 15.46 feet: 4 inches: 5" << endl;
    cout << "Actual result: " << chain(totalInches, feet, inches) << " feet: " << feet << " inches: " << inches << endl;
}

double chain(int totalInches, int &feet, int &inches) {
    feet = totalInches / 12;
    inches = totalInches % 12;

    return (feet) * 3.49 + (inches) * .30;
}

The return is correct, so obviously the function is working, but for the life of me I can't figure out why feet and inches aren't changing. Everything is spelled right, I have all my ampersands, but for some reason, the display is showing feet as 8 and inches as 7. I have no idea where those numbers are even coming from.

Upvotes: 2

Views: 95

Answers (3)

Aconcagua
Aconcagua

Reputation: 25518

Just for better illustration of the answers given so far (giving some more details):

std::cout << x is syntactic sugar for operator<<(std::cout, x); as operator<< returns its first argument, std::cout << x << y; gets:

operator<<(operator<<(std::cout, x), y);

Obviously, the first argument to the outer call will be evaluated (e. g. the inner call executed) before the the outer call actually is performed – and this is where any guarantees already end, i. e. as order of argument evaluation is unspecified, the compiler is quite well allowed to evaluate y before the call to the inner operator – including the evaluation of the latter's arguments!

operator<<(operator<<(std::cout, f(x)), x);

Similarly now, the only guarantees here are that f(x) is called before the inner operator is called and the inner operator being called before the outer one; still, the raw x can be evaluated at very first...

Obviously, your compiler starts evaluating the arguments from last to first, most likely due to the calling convention in use (quite likely cdecl; on Windows possibly stdcall)...

The change in the accepted answer introduces a sequence point between the function calls (old, pre-C++11 wording), which ensures that all effects of the previous call are completed before the call to the next function, i. e. (using new C++11 wording):

operator<<(std::cout, f(x)); // is sequenced  b e f o r e  next line
operator<<(std::cout, x);    // is sequenced  a f t e r  previous line

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234635

Remember that << is syntatic sugar for a function call and the order of evaluation of these functions is not necessarily in the order that you think it is. In fact C++ doesn't actually specify the order. So the final parts of you second cout are printing out the starting values of feet and inches.

Call chain(totalInches, feet, inches) in an intermediate step before the second cout, perhaps even in this way (Acknowledge @DavidSchwartz):

cout << "Actual result: " << chain(totalInches, feet, inches);
cout << " feet: " << feet << " inches: " << inches << endl;

Upvotes: 5

iBug
iBug

Reputation: 37217

The evaluation order is unspecified in the ISO C++ standard, according to ostream chaining, output order

To ensure the function is called before those variables are accessed, separate the output chain:

cout << "Actual result: " << chain(totalInches, feet, inches);
cout << " feet: " << feet << " inches: " << inches << endl;

Upvotes: 1

Related Questions