Experience has shown that the best way to develop and maintain a large program is to construct it from small, simple pieces, or components. This technique is called divide and conquer.
C++ programs are typically written by combining new functions and classes the programmer writes with "prepackaged" functions and classes available in the C++ Standard Library.
Functions allow the programmer to modularize a program by separating its tasks into self-contained units.
The statements in the function bodies are written only once, are reused from perhaps several locations in a program and are hidden from other functions.
The compiler refers to the function prototype to check that calls to a method contain the correct number and types of arguments, that the types of the arguments are in the correct order and that the value returned by the function can be used correctly in the expression that called the function.
There are three ways to return control to the point at which a function was invoked. If the function does not return a result, control returns when the program reaches the function-ending right brace, or by execution of the statement
If the function does return a result, the statement
evaluates expression and returns the value of expression to the caller.
A function prototype tells the compiler the name of a function, the type of data returned by that function, the number of parameters the function expects to receive, the types of those parameters and the order in which the parameters of those types are expected.
The portion of a function prototype that includes the name of the function and the types of its arguments is called the function signature or simply the signature.
An important feature of function prototypes is argument coercioni.e., forcing arguments to the appropriate types specified by the parameter declarations.
Argument values that do not correspond precisely to the parameter types in the function prototype can be converted by the compiler to the proper type as specified by C++'s promotion rules. The promotion rules indicate how to convert between types without losing data.
The element of chance can be introduced into computer applications by using the C++ Standard Library function rand.
Function rand actually generates pseudorandom numbers. Calling rand repeatedly produces a sequence of numbers that appears to be random. However, the sequence repeats itself each time the program executes.
Once a program has been thoroughly debugged, it can be conditioned to produce a different sequence of random numbers for each execution. This is called randomizing and is accomplished with the C++ Standard Library function srand.
Function srand takes an unsigned integer argument and seeds the rand function to produce a different sequence of random numbers for each execution of the program.
Random numbers in a range can be generated with
number = shiftingValue + rand() % scalingFactor;
where shiftingValue is equal to the first number in the desired range of consecutive integers and scalingFactor is equal to the width of the desired range of consecutive integers.
An enumeration, introduced by the keyword enum and followed by a type name, is a set of integer constants represented by identifiers. The values of these enumeration constants start at 0, unless specified otherwise, and increment by 1.
An identifier's storage class determines the period during which that identifier exists in memory.
An identifier's scope is where the identifier can be referenced in a program.
An identifier's linkage determines whether an identifier is known only in the source file where it is declared or across multiple files that are compiled, then linked together.
Keywords auto and register are used to declare variables of the automatic storage class. Such variables are created when program execution enters the block in which they are defined, they exist while the block is active and they are destroyed when the program exits the block.
Only local variables of a function can be of automatic storage class.
The storage class specifier auto explicitly declares variables of automatic storage class. Local variables are of automatic storage class by default, so keyword auto rarely is used.
Keywords extern and static declare identifiers for variables of the static storage class and for functions. Static-storage-class variables exist from the point at which the program begins execution and last for the duration of the program.
A static-storage-class variable's storage is allocated when the program begins execution. Such a variable is initialized once when its declaration is encountered. For functions, the name of the function exists when the program begins execution, just as for all other functions.
There are two types of identifiers with static storage classexternal identifiers (such as global variables and global function names) and local variables declared with the storage class specifier static.
Global variables are created by placing variable declarations outside any class or function definition. Global variables retain their values throughout the execution of the program. Global variables and global functions can be referenced by any function that follows their declarations or definitions in the source file.
Local variables declared with the keyword static are still known only in the function in which they are declared, but, unlike automatic variables, static local variables retain their values when the function returns to its caller. The next time the function is called, the static local variables contain the values they had when the function last completed execution.
An identifier declared outside any function or class has file scope.
Labels are the only identifiers with function scope. Labels can be used anywhere in the function in which they appear, but cannot be referenced outside the function body.
Identifiers declared inside a block have block scope. Block scope begins at the identifier's declaration and ends at the terminating right brace (}) of the block in which the identifier is declared.
The only identifiers with function-prototype scope are those used in the parameter list of a function prototype.
Stacks are known as last-in, first-out (LIFO) data structuresthe last item pushed (inserted) on the stack is the first item popped (removed) from the stack.
One of the most important mechanisms for computer science students to understand is the function call stack (sometimes referred to as the program execution stack). This data structure supports the function call/return mechanism.
The function call stack also supports the creation, maintenance and destruction of each called function's automatic variables.
Each time a function calls another function, an entry is pushed onto the stack. This entry, called a stack frame or an activation record, contains the return address that the called function needs to return to the calling function, as well as the automatic variables for the function call.
The stack frame exists as long as the called function is active. When the called function returnsand no longer needs its local automatic variablesits stack frame is popped from the stack, and those local automatic variables are no longer known to the program.
In C++, an empty parameter list is specified by writing either void or nothing in parentheses.
C++ provides inline functions to help reduce function call overheadespecially for small functions. Placing the qualifier inline before a function's return type in the function definition "advises" the compiler to generate a copy of the function's code in place to avoid a function call.
Two ways to pass arguments to functions in many programming languages are pass-by-value and pass-by-reference.
When an argument is passed by value, a copy of the argument's value is made and passed (on the function call stack) to the called function. Changes to the copy do not affect the original variable's value in the caller.
With pass-by-reference, the caller gives the called function the ability to access the caller's data directly and to modify it if the called function chooses to do so.
A reference parameter is an alias for its corresponding argument in a function call.
To indicate that a function parameter is passed by reference, simply follow the parameter's type in the function prototype by an ampersand (&); use the same convention when listing the parameter's type in the function header.
Once a reference is declared as an alias for another variable, all operations supposedly performed on the alias (i.e., the reference) are actually performed on the original variable. The alias is simply another name for the original variable.
It is not uncommon for a program to invoke a function repeatedly with the same argument value for a particular parameter. In such cases, the programmer can specify that such a parameter has a default argument, i.e., a default value to be passed to that parameter.
When a program omits an argument for a parameter with a default argument, the compiler rewrites the function call and inserts the default value of that argument to be passed as an argument to the function call.
Default arguments must be the rightmost (trailing) arguments in a function's parameter list.
Default arguments should be specified with the first occurrence of the function nametypically, in the function prototype.
C++ provides the unary scope resolution operator (::) to access a global variable when a local variable of the same name is in scope.
C++ enables several functions of the same name to be defined, as long as these functions have different sets of parameters. This capability is called function overloading.
When an overloaded function is called, the C++ compiler selects the proper function by examining the number, types and order of the arguments in the call.
Overloaded functions are distinguished by their signatures.
The compiler encodes each function identifier with the number and types of its parameters to enable type-safe linkage. Type-safe linkage ensures that the proper overloaded function is called and that the types of the arguments conform to the types of the parameters.
Overloaded functions are normally used to perform similar operations that involve different program logic on different data types. If the program logic and operations are identical for each data type, overloading may be performed more compactly and conveniently using function templates.
The programmer writes a single function template definition. Given the argument types provided in calls to this function, C++ automatically generates separate function template specializations to handle each type of call appropriately. Thus, defining a single function template essentially defines a family of overloaded functions.
All function template definitions begin with the template keyword followed by a template parameter list to the function template enclosed in angle brackets (< and >).
The formal type parameters are placeholders for fundamental types or user-defined types. These placeholders are used to specify the types of the function's parameters, to specify the function's return type and to declare variables within the body of the function definition.
A recursive function is a function that calls itself, either directly or indirectly.
A recursive function knows how to solve only the simplest case(s), or so-called base case(s). If the function is called with a base case, the function simply returns a result.
If the function is called with a more complex problem, the function typically divides the problem into two conceptual piecesa piece that the function knows how to do and a piece that it does not know how to do. To make recursion feasible, the latter piece must resemble the original problem, but be a slightly simpler or slightly smaller version of it.
In order for the recursion to eventually terminate, each time the function calls itself with a slightly simpler version of the original problem, this sequence of smaller and smaller problems must eventually converge on the base case.
The ratio of successive Fibonacci numbers converges on a constant value of 1.618.... This number frequently occurs in nature and has been called the golden ratio or the golden mean.
Iteration and recursion have many similarities: both are based on a control statement, involve repetition, involve a termination test, gradually approach termination and can occur infinitely.
Recursion has many negatives. It repeatedly invokes the mechanism, and consequently the overhead, of function calls. This can be expensive in both processor time and memory space. Each recursive call causes another copy of the function (actually only the function's variables) to be created; this can consume considerable memory.