Thread: Making functions execute at certain times

  1. #1
    Registered User
    Join Date
    Sep 2007
    Posts
    127

    Making functions execute at certain times

    Hi.

    I started programming a couple of weeks ago. I'm going through that C++ Without Fear book recommended on this site. I'm on page 107.

    Basically, I made this program that calculates factorials (with some help from the answers on the CD I admit). It's below.

    In the get_factorials function, I've added in a second variable, int b, so that I can set this after I have printed out "Factorials = ". If I don't do this, get_factorials runs itself and outputs stuff prematurely (yeah I know I should probably have given b different names in main and get_factorials).

    Is there a way of coding it so that it waits until you actually want it to run, without wasting code like int b etc.?

    Thanks.

    Code:
    #include <iostream>
    #include <math.h>
    using namespace std;
    
    // int b is only necessary below to stop it acting prematurely
    
    int get_factorials(int n, int b);
    
    int main() {
        int n, b;
        while(1) {
        cout << "Enter a number (0 to exit) and press ENTER: ";
        cin >> n;
        if (n == 0)
           break;
        cout << "Factorial(" << n << ") = ";
        b = 20;               // This is just to stop the get factorials function running
                              // and putting all the "n *" stuff out early. 
        cout << get_factorials(n, b);
        cout << endl;
        }
        return 0;
    }
    
    int get_factorials(int n, int b) 
    {
         if (n > 0)
         {
             cout << n;
             if (n > 1)
                cout << "*";
             else 
                  cout << " = ";
             return n * get_factorials(n-1, b); 
         }
         else
            return 1;
    }

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You don't even use b anywhere. You pass it along, but you never, in any way, query its value. It's totally impossible that it has any influence on the behaviour of your program, aside from consuming stack space. Just remove it completely, both in main and get_factorials - the program should do exactly the same thing.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I suspect that the problem will be solved by reading this:
    http://faq.cprogramming.com/cgi-bin/...wer=1045779938
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I suppose the question was about output formatting. OP's code gives this output:
    Enter a number (0 to exit) and press ENTER: 5
    Factorial(5) = 5*4*3*2*1 = 120
    If the printing was all done at one line, the output would be:
    Code:
    cout << "Factorial(" << n << ") = " << get_factorials(n, b);
    
    Enter a number (0 to exit) and press ENTER: 5
    5*4*3*2*1 = Factorial(5) = 120
    It is not the unused argument that makes any difference, but that the outputting is all one chained cout << call.

    I'm not sure whether you'd get the same results with all compilers and compiler settings, but the cout << call would first evaluate function calls in the chain, and as get_factorials - as a side-effect - is also outputting to cout, this would be printed first (as in the second one-line example).

    Wouldn't simply writing cout << get_factorials(n) as a separate statement solve the problem?

    Or rather avoiding "couting" side-effects altogether, by letting each function perform one task:
    Code:
    //function's job is to print a factorial in a specially formatted way
    //function doesn't return anything, so you won't be tempted to call it like
    //cout << ... << print_formatted_factorial(n);
    void print_formatted_factorial(int max) 
    {
        cout << "Factorial(" << max << ") = ";
        for (int i = 1; i < max; ++i) {
            cout << i << "*";
        }
        cout << max << " = " << factorial(max) << '\n';
    }
    
    //function's job is to calculate a factorial
    int factorial(int n)
    {
        int fac = 1;
        for (int i = 2; i <= n; ++i) {
            fac *= i;
        }
        return fac;
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Thanks for all the responses.

    Anon, you're getting to the problem, I think. Actually this is just weird, because I just tried compiling and running the program I posted just now. Basically, this time the output was the same whether I included the second int in get_factorials or not. So the problem's disappeared.

    I don't really understand this because the other day before I posted it, I got the formatting problem as you described it, Anon. I don't think the compiler (Bloodshed Dev-C++) was set up any differently or anything, either.

  6. #6
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    I think what you want it to use cout<<flush; to print the cout buffer before calculating get_factorials().
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Execution order of various parts of C++ source code is defined using so-called "sequence points". C++ specifies that statements before a sequence point are fully executed before any statements after the sequence point are executed. (By the "as if" rule, a compiler may re-order the statements if the effect is the same.) Statements without an intervening sequence points are executed in unspecified order.
    Code:
    cout << max << " = " << factorial(max) << '\n';
    Here, there are 5 parts:
    1) The << max operation.
    2) The << " = " operation.
    3) The call to factorial.
    4) The << result of factorial operation.
    5) The << '\n' operation.

    There are no relevant sequence points. Although there is one at the beginning and the end of the function execution, this merely means that none of the other 4 parts may be executed interleaved with statements from within the function; it doesn't influence when the function as a whole is executed.
    Execution order is therefore partially specified by data dependencies: every << operation depends on the result of the one to its left. (And thus indirectly on all operations to its left.)
    Thus:
    2 depends on 1.
    4 depends on 2.
    5 depends on 4.
    In addition, because the result of the function is needed to write it, 4 also depends on 3. No other dependencies exist. Thus, the following execution orders are valid:
    1 2 3 4 5
    1 3 2 4 5
    3 1 2 4 5
    Which one is used is unspecified - it depends on the compiler, its options, or even the CPU and its current state (Some CPUs sometimes re-order statements.) The additional argument may have well convinced the compiler to execute the function at a different time.
    As it happens, if 3 is executed before 2 or even 1, the output of your program is different from what you expect.

    King Mir: flushing will have absolutely no effect except possibly making the compiler arrange the code yet another way..
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    So, if I have
    Code:
    cout << foo() << bar();
    then it is unspecified whether foo() will be called before bar() or the other way round? (MingW calls bar() first.)

    But if I have
    Code:
    cout << foo();
    cout << bar();
    then the compiler can't reorder anything and foo() will be called first?

    And the moral is, if your function has side-effects, avoid calling it in a complex statement that involves other function calls?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Exactly.

    (Of course, the compiler might inline foo and bar in the second example and reorder their instructions anyway. But it has to prove that the observable behaviour of the program stays the same.)
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems with file pointer in functions
    By willie in forum C Programming
    Replies: 6
    Last Post: 11-23-2008, 01:54 PM
  2. Void Functions Help
    By bethanne41 in forum C++ Programming
    Replies: 1
    Last Post: 05-09-2005, 05:30 PM
  3. Functions and Classes - What did I do wrong?
    By redmage in forum C++ Programming
    Replies: 5
    Last Post: 04-11-2005, 11:50 AM
  4. Passing a function name as a variable to execute it?
    By Zuul in forum C++ Programming
    Replies: 2
    Last Post: 01-03-2002, 12:42 PM
  5. Passing data/pointers between functions #2
    By TankCDR in forum C Programming
    Replies: 1
    Last Post: 11-02-2001, 09:49 PM