Functions

  • User-defined functions as one of the main building blocks of C++ programs. A function provides a convenient way of pack a computational recipe, so that it can be used as often as required. A function definition consists of two parts: interface and body. The interface of a function (also called its prototype) specifies how it may be used. It consists of three entities:
  • The function name. This is simply a unique identifier.
  • The function parameters (also called its signature). This is a set of zero or more typed identifiers used for passing values to and from the function.
  • The function return type. This specifies the type of value the function returns. A function which returns nothing should have the return type void. The body of a function contains the computational steps (statements) that comprise the function.
  • Using a function involves ‘calling’ it. A function call consists of the function name followed by the call operator brackets ‘0’. inside which zero or more comma-separated arguments appear. The number of arguments should match the number of function parameters. Each argument is an expression whose type should match the type of the corresponding parameter in the function interface.
  • When a function call is executed, the arguments are first evaluated and their resulting values are assigned to the corresponding parameters. The function body is then executed. Finally, the function return value (if any) is passed to the caller.
  • Since a call to a function whose return type is non-void yields a return value, the call is an expression and may be used in other expressions. By contrast, a call to a function whose return type is void is a statement.
  • A Simple Function: Following program shows definition of a simplefunction which raises an integer to the power of another, positive integer.
    int Power (int base, unsigned int exponent)
    {
     int result=1;
     for (int = 0; i < exponent; ++i)
     result * base;
    return result;
     }
    


    Parameters and Arguments

  • C++ supports two styles of parameters: value and reference. A value parameter receives a copy of the value of the argument passed to it. As a result, if the function makes any changes to the parameter, this will not affect the argument.
    #include < iostream.h >
    void test(int num)
    {
    num=0;
    cout << “num= ” << num << “\n”;
    }
    int main (void)
    {
    int x= 10;
    test(x);
    cout << "x =" << x ;
    return 0;
    } 
    
  • the single parameter of test() is a value parameter. As far as this function is concerned, num behaves just like a local variable inside the function. When the function is called and x passed to it, num receives a copy of the value of x. As a result, although num is set to 0 by the function, this does not affect x. The Program produces the following output:
  • num =0;
  • X= 10;
  • A reference parameter, on the other hand, receives the argument passed to it and works on it directly. Any changes made by the function to a reference parameter is in effect directly applied to the argument.
  • Within the context of function calls, the two styles of passing arguments are, respectively, called pass-by-value and pass-by-reference. It is perfectly valid for a function to use pass-by-value for some of its parameters and pass-by-reference for others. The former is used much more often in practice.


    Global and Local Scope

  • Everything defined at the program scope level (i.e., outside functions and classes) is said to have a global scope. Uninitialized global variables are automatically initialized to zero. Since global entities are visible at the program level, they must also be unique at the program level. This means that the same global variable or function may not be defined more than once at the global level. Global entities are generally accessible everywhere in the program.
  • Each block in a program defines a local scope. Thus the body of a function represents a local scope. The parameters of a function have the same scope as the function body. Variables defined within a local scope are visible to that scope only. Hence, a variable need only be unique within its own scope. Local scopes may be nested, in which case the inner scopes override the outer scopes.
  • Generally, the lifetime of a variable is limited to its scope. So, for example, global variables last for the duration of program execution, while local variables are created when their scope is entered and destroyed when their scope is exited. The memory space for global variables is reserved prior to program execution commencing, whereas the memory space for local variables is allocated on the fly during program execution.


    Auto Variables

  • Because the lifetime of a local variable is limited and is determined automatically, these variables are also called automatic. The storage class specifier auto may be used to explicitly specify a local variable to be automatic.
     For example:
    void Test (void)
    {
    auto int xyz; // same as: int xyz;
    //.....
    }
    


    Register Variables

  • As mentioned earlier, variables generally denote memory locations where variable values are stored. When the program code refers to a variable (e.g., in an expression), the compiler generates machine code which accesses the memory location denoted by the variable.
  • For frequently-used variables (e.g., loop variables), efficiency gains can be obtained by keeping the variable in a register instead thereby avoiding memory access for that variable.
  • The storage class specifier register may be used to indicate to the compiler that the variable should be stored in a register if possible.
     
    For example:
    for (register int i = 0; i < n; ++i) 
    sum += i;
    
  • Note that register is only a hint to the compiler, and in some cases the compiler may choose not to use a register when it is asked to do so. One reason for this is that any machine has a limited number of registers and it may be the case that they are all in use.
  • Even when the programmer does not use register declarations, many optimizing compilers try to make an intelligent guess and use registers where they are likely to improve the performance of the program.


    Static Variables

  • It is often useful to confine the accessibility of a variable to function. This is facilitated by the storage class specifier static.
  • The variable will remain only accessible within its local scope; however, its lifetime will no longer be confined to this scope, but will instead be global. In other words, a static local variable is a global variable which is only accessible within its local scope.
  • Static local variables are useful when we want the value of a local variable to persist across the calls to the function in which it appears. For example, consider an Error function which keeps a count of the errors and aborts the program when the count exceeds a preset limit:
    void Error (char *message)
    {
    static int count = 0; // static local variable 
    if (++count> limit)
    Abort( );
    }
    
    Example
  • Like global variables, static local variables are automatically initialized to 0.


    Extern Variables and Functions

  • Because a global variable may be defined in one file and referred to in other files, some means of telling the compiler that the variable is defined elsewhere may be needed. Otherwise, the compiler may object to the variable as undefined. This is facilitated by an extern declaration.
  • For example, the declaration:
  • extern int size; // variable declaration
  • informs the compiler that size is actually defined somewhere (may be later in this file or in another file). This is called a variable declaration (not definition) because it does not lead to any storage being allocated for size.
  • It is a poor programming practice to include an initializer for an extern variable, since this causes it to become a variable definition and have storage allocated for it:
  • extern int size = 10; // no longer a declaration!
  • Function prototypes may also be declared as extern, but this has no effect when a prototype appears at the global scope. It is more useful for declaring function prototypes inside a function. For example:
  • double Tangent (double angle)
  • extern double sin(double); // defined elsewhere
  • extern double cos(double); //defined elsewhere return sin(angle) / cos(angle);
  • The best place for extern declarations is usually in header files so that they can be easily included and shared by source files.


    Default Arguments

  • Default argument is a programming convenience which removes the burden of having to specify argument values for all of a function’s parameters. For example, consider a function for reporting errors:
  • void Error (char *message, int severity = 0);
  • Here, severity has a default argument of 0; both the following calls are therefore valid.
  • Error (“Division by zero”, 3); // severity set to 3
  • Error (“Round off error”); //severity set to 0
  • As the first call illustrates, a default argument may be overridden by explicitly specifying an argument.
  • Default arguments are suitable for situations where certain (or all) function parameters frequently take the same values. In Error, for example, severity 0 errors are more common than others and therefore a good candidate for default argument. A less appropriate use of default arguments would be:
  • int Power (int base, unsigned int exponent = 1);
  • Because 1 (or any other value) is unlikely to be a frequently-used one in this situation.
  • To avoid ambiguity, all default arguments must be trailing arguments. Example
  • The following declaration is therefore illegal:
  • void Error (char *message = “Bomb”, int severity); // Illegal!
  • A default argument need not necessarily be a constant. Arbitrary expressions can be used, so long as the variables used in the expression are available to the scope of the function definition (e.g., global variables).
  • The accepted convention for default arguments is to specify them in function declarations, not function definitions. Because function declarations appear in header files, this enables the user of a function to have control over the default arguments. Thus different default arguments can be specified for different situations. It is, however, illegal to specify two different default arguments for the same function in a file.


    Function Overloading

  • The term overloading means ‘providing multiple definitions of’. Overloading ot functions involves defining distinct functions which share the same name, each of which has a unique signature. Function overloading is appropriate for:
  • Defining functions which essentially do the same thing, but operate on different data types.
  • Providing alternate interfaces to the same function.
  • Function overloading is purely a programming convenience. Consider a function, GetTime, which returns in its parameter(s) the current time of the day, and suppose that we require two variants of this function: one which returns the time as seconds from midnight, and one which returns the time as hours, minutes, and seconds. Given that these two functions serve the same purpose, there is no reason for them to have different names. C++ allows functions to be overloaded, that is, the same function to have more than one definition:
  • long GetTime (void); // seconds from midnight
  • void GetTime (int &hours, int &minutes, int &seconds);
  • When Getlime is called, the compiler compares the number and type of arguments in the call against the definitions of GetTime and chooses the one that matches the call. For example: int h,m,s; long t = GetTime( ); // matches GetTime(void) GetTime(h, m, s); // matches GetTime(int&, int&, int&);
  • To avoid ambiguity, each definition of an overloaded function must have a unique signature.
  • Member functions of a class may also be overloaded:
    class Time {
    //...
    long GetTime (void); // seconds from midnight 
    void GetTime (int &hours, int &minutes, int &seconds);
    
  • Function overloading is useful for obtaining flavors that are not possible using default arguments alone. Overloaded functions may also have default arguments:
  • void Error (int errCode, char *errMsg =“”);
  • void Error (char *errMsg); Click here for example


    Command Line Arguments

  • When a program is executed under an operating system (such as DOS or UNIX), it can be passed zero or more arguments. These arguments appear after the program executable name and are separated by blanks. Because they appear on the same line as where operating system commands are issued, they are called command line arguments.
  • As an example, consider a program named sum which prints out the sum of a set of numbers provided to it as command line arguments. Following example illustrates how two numbers are passed as arguments to sum.
  • Prompt > sum 36 12
  • Prompt > 48
  • Command line arguments are made available to a C++ program via the main function.
  • int main (int argc, const char* argv[])
  • This form of main is used when the program is intended to accept command line arguments.
  • The first parameter, argc, denotes the number of arguments passed to the program (including the name of the program itself).
  • The second parameter, argv, is an array of the string constants which represent the arguments.
  • Example: (Strings are converted to real numbers using atof, which is defined in stdlib.h) Click here for example


    Casting

  • For the example given, if the input given as follows Prompt > sum 36 12 Then
  • argc is 3
  • argv[0] is “sum”
  • argv[1] is “10.4”
  • argv[2] is “12.5”


Break Statement << Previous

Next >> Arrays

Our aim is to provide information to the knowledge seekers. 


comments powered by Disqus










Footer1