5.7.2. Defining Functions


Defining functions

One of the most important features of C++, or of almost any programming language, is your ability to define new functions. You write a large piece of software by breaking it into a collection of small functions, each with a specific purpose.

The general form of a function definition is

  R name(arguments)
  {
    body
  }
where In the body, statement
  return E;
indicates that the function is finished and that its result is the value of expression E.

Here are some example functions.

  // Return the integer that is one larger than n.

  int successor(int n)
  {
    return n+1;
  }


  // Return the larger of x and y.  (This is
  // equivalent to the max function from the
  // algorithm library, except that larger requires
  // its arguments to be of type double.)

  double larger(double x, double y)
  {
    if(x > y)
    {
      return x;
    }
    else
    {
      return y;
    }
  }


  // Return the largest of x, y and z.

  double largest(double x, double y, double z)
  {
    return larger(x, larger(y,z));
  }


  // Return true of n is prime and false if n is
  // not prime.
  //
  // Requirement: n > 1.

  bool isPrime(long n)
  {
    //-------------------------------------------
    // We try potential factors up to the square
    // root of n, rounded to the nearest integer.
    //-------------------------------------------

    long s = (long)(sqrt(n) + 0.5);

    for(int k = 2; k <= s; k++)
    {
      if(n % k == 0)
      {
        return false;
      }
    }
    return true;
  }

Using your functions

As the definition of largest suggests, you should feel free to use the functions that you have defined as tools for defining other functions.

Use your defined function the same way you would a function from the library. For example,

  if(isPrime(2*y+1))
  {
    printf("%i is prime\n", 2*y+1);
  }
uses isPrime in a test. Notice that the form of the argument 2*y+1 is not required to match the name, n, used to refer to it in the definition of isPrime. Only the types must match. For any expression E of type long, isPrime(E) yields true if the value of expression E is prime. The argument name, n, in the definition of isPrime is just a convenient way to refer to the number that is passed within the body of isPrime.

When you use a function, you are said to call that function, and expression larger(7,4) is a function call expression.


Do not write types in function calls

After seeing a type in front of each argument in a function definition, some students try to write types in function calls too. Do not write types in function calls. For example,

  double z = largest(a, b, c);
makes sense. But
  double z = largest(double a, double b, double c);
does not make sense. You are not defining function largest here, so get rid of the types.


Each call runs the function

Do not try to do anything special to get a function to run. A function call expression automatically runs the function. Sometimes inexperienced programmers are not sure how to get the result of a function, and write something like

  isPrime(x);
  if(isPrime(x)) 
  {
    ...
  }
believing that expression isPrime(x) in the if-statement refers to the answer produced by the statement just before it. But, since this program contains expression isPrime(x) twice, the function is called twice. The first statement calls isPrime(x) and just throws away its result. Get rid of it.


The mechanics of a function call

When a function is called, a new frame is created for it in the run-time stack. That frame holds all of the variables and parameters that the function uses. When the function returns, its frame is destroyed.

It is important to realize that a function's variables are associated with a frame, not with the function itself. When we look at recursion the distinction will become very important.


Exercises

  1. Define a function sqr(x) that takes a real number x (type double) and returns the square of x (also of type double). For example, sqr(10.0) should return 100.0. Also write a contract for this function. Answer

  2. Without using the abs function, define function absoluteValue(n) that takes an int n and returns its absolute value. Also write a contract for this function. Answer

  3. Define a function isPerfect(n) that takes a positive integer n and yields true of n is perfect and false if not. Also write a contract for this function. See question 3 on the page on while-loops for a definition of a perfect number. Answer

  4. Using your isPerfect function from the preceding exercise, define a function nextPerfect(n) that returns the smallest perfect number that is greater than n. Assume that n is a positive integer. For example, nextPerfect(1) = 6. Answer

  5. Suppose that function dbl is defined by

      int dbl(int x)
      {
        return 2*x;
      }
    
    Is the following allowed in C++?
      int z = 10;
      int y = dbl(int z);
    
    Answer

  6. Is the following function definition allowed?

      int dbl(int x)
        return x*x;
    
    Answer

  7. Rewrite the following two statements as one statement. Assume that function f has no side-effects and that variable q is not needed for anything else.

      int q = f(w);
      int r = f(q);
    
    Answer

  8. Suppose function g is defined as follows.

      int g(int n)
      {
        if(n > 3) 
        {
          return 0;
        }
        else 
        {
          return 2*n+3;
        }
      }
    
    What is the value of expression g(3)? Answer

  9. Using function g from the preceding problem, what is g(g(3))? Answer

  10. Write a C++ definition of function seconds(ms), which takes an integer value ms representing some number of milliseconds (thousandths of a second) and returns a real number that is ms in seconds. For example, seconds(2001) = 2.001. Answer