Namespaces-Functions, Scopes, Namespaces, and Headers

Functions, Scopes, Namespaces, and Headers
Functions are the building blocks of a C/C++ program. The elements of a program, including functions, exist within one or more scopes. In C++, there is a special scope called a namespace. The prototypes for all standard functions are declared within various headers. These topics are examined here.

Functions

At the heart of a C/C++ program is the function. It is the place in which all program activity occurs. The general form of a function is
ret-type function_name (parameter list)
{  
  body of function
}
The type of data returned by a function is specified by ret-type. The parameter list is a comma-separated list of variables that will receive any arguments passed to the function. For example, the following function has two integer parameters called i and j and a double parameter called count:
void f(int i, int j, double count)
{ ...
 
Notice that you must declare each parameter separately.
In C89, if a function’s return type is not explicitly specified, it defaults to int. C++ and C99 do not support “default-to-int,” although most compilers will still allow it.
Functions terminate and return automatically to the calling procedure when the last brace is encountered. You may force a return prior to that by using the return statement.
All functions, except those declared as void, return a value. The type of the return value must match the type declaration of the function. Values are returned via the return statement.
In C++, it is possible to create generic

Recursion

In C/C++, functions can call themselves. This is called recursion, and a function that calls itself is said to be recursive. A simple example is the function factr( ) shown here, which computes the factorial of an integer. The factorial of a number N is the product of all the whole numbers from 1 to N. For example, 3 factorial is 1 × 2 × 3, or 6.
// Compute the factorial of a number using recursion.
int factr(int n) 
{
  int answer;

  if(n==1) return 1;
  answer = factr(n-1)*n;
  return answer;
}
 
When factr( ) is called with an argument of 1, the function returns 1; otherwise, it returns the product of factr(n–1) * n. To evaluate this expression, factr( ) is called with n–1. This process continues until n equals 1 and the calls to the function begin returning. When factr( ) finally returns to the original caller, the final return value will be the factorial of the original argument.


Programming Tip 
Although powerful, recursive functions should be used with care. The recursive versions of many routines execute a bit more slowly than the iterative equivalent because of the added overhead of the repeated function calls. Many recursive calls to a function could cause a stack overrun. Because storage for function parameters and local variables is on the stack and each new call creates a new copy of these variables, the stack space could become exhausted. If this happens, a stack overflow occurs. If this happens in the normal use of a debugged recursive function, try increasing the stack space allocated to your program.
When writing recursive functions, you must include a conditional statement somewhere that causes the function to return without the recursive call being executed. If you don't, once you call the function, it will call itself until the stack is exhausted. This is a very common error when developing recursive functions. Use output statements liberally during development so that you can watch what is going on and abort execution if you see that you have made a mistake.
When a function calls itself, new local variables and parameters are allocated storage on the stack, and the function code is executed with these new variables from its beginning. A recursive call does not make a new copy of the function. Only the arguments and local variables are new. As each recursive call returns, the old local variables and parameters are removed from the stack and execution resumes at the point of the recursive call inside the function. Recursive functions could be said to “telescope” out and back.

Function Overloading

In C++, functions can be overloaded. When a function is overloaded,two or more functions share the same name. However, each version of an overloaded function must have a different number and/or type of parameters. (The function return types may also differ, but this is not necessary.) When an overloaded function is called, the compiler decides which version of the function to use based upon the type and/or number of arguments, calling the function that has the closest match. For example, given these three overloaded functions,
void myfunc(int a) {  cout << "a is " << a << endl;
}

// overload myfunc
void myfunc(int a, int b) {
  cout << "a is " << a << endl;
  cout << "b is " << b << endl;
}

// overload myfunc, again
void myfunc(int a, double b) {
  cout << "a is " << a << endl;
  cout << "b is " << b << endl;
}
 
the following calls are allowed:
myfunc(10); // calls myfunc(int)
myfunc(12, 24); // calls myfunc(int, int)
myfunc(99, 123.23); // calls myfunc(int, double)
 
In each case, the type and number of arguments determine which version of myfunc( ) is actually executed.
Function overloading is not supported by C.

Default Arguments

In C++, you may assign a function parameter a default value, which will be used automatically when no corresponding argument is specified when the function is called. The default value is specified in a manner syntactically similar to a variable initialization. For example, this function assigns its two parameters default values:
void myfunc(int a = 0, int b = 10)
{ // ...
 
Given the default arguments, myfunc( ) can be legally called in these
three ways:
myfunc();       // a defaults to 0; b defaults to 10
myfunc(-1);     // a is passed -1; b defaults to 10
myfunc(-1, 99); // a is passed -1; b is passed 99
 
When you create functions that have default arguments, you must specify the default values only once: either in the function prototype or in its definition. (You cannot specify them each place, even if you use the same values.) Generally, default values are specified in the prototype.
When giving a function default arguments, remember that you must specify all nondefaulting arguments first. Once you begin to specify default arguments, there may be no intervening nondefaulting ones.

Prototypes

In C++, all functions must be prototyped. In C, prototypes are technically optional, but strongly recommended. The general form of a prototype is shown here:
ret-type name(parameter list);
In essence, a prototype is simply the return type, name, and parameter list of a function, followed by a semicolon.
The following example shows how the function fn( ) is prototyped:
float fn(float x); // prototype 
 .
  .
  .
// function definition
float fn(float x)
{
  // ...
} 
 
To specify the prototype for a function that takes a variable number of arguments, use three periods at the point at which the variable number of parameters begin. For example, the printf( ) function could be prototyped like this:
int printf(const char *format, ...);
 
When specifying the prototype to an overloaded function, each version of that function must have its own prototype. When a member function is declared within its class, this constitutes a prototype for the function.
In C, to specify the prototype for a function that has no parameters, use void in its parameter list. For example,
int f(void);
 
In C++, an empty parameter list in a prototype means that the function has no parameters; the void is optional. Thus, in C++, the preceding prototype can be written like this:
int f();
 
In C++, you can include void in the parameter list, but doing so is redundant.


Programming Tip 
Two terms are commonly confused in C/C++ programming: declaration and definition. Here is what they mean. A declaration specifies the name and type of an object. A definition allocates storage for it. These definitions apply to functions, too. A function declaration (prototype) specifies the return type, name, and parameters of a function. The function itself (that is, the function with its body) is its definition.
In many cases, a declaration is also a definition. For example, when a non-extern variable is declared, it is also defined. Or, when a function is defined prior to its first use, its definition also serves as its declaration.



Understanding Scopes and Variable Lifetimes

C and C++ define scope rules, which govern the visibility and lifetime of objects. Although there are several subtleties, in the most general sense, there are two scopes: global and local.
The global scope exists outside all other scopes. A name declared in the global scope is known throughout the program. For example, a global variable is available for use by all functions in the program. Global variables stay in existence the entire duration of the program.
A local scope is defined by a block. That is, a local scope is begun by an opening brace and ends with its closing brace. A name declared within a local scope is known only within that scope. Because blocks can be nested, local scopes, too, can be nested. Of course, the most common local scope is the one defined by a function. Local variables are created when their block is entered, and destroyed when their block is exited. This means that local variables do not hold their values between function calls. You can use the static modifier, however, to preserve values between calls.
In C++ and C99, local variables can be declared nearly anywhere within a block. In C89, they must be declared at the start of a block, before any “action” statements occur. For example, the following code is valid for C++ and C99, but not for C89:
void f(int a)
{
  int a;

  a = 10;

  int b; // OK for C++ and C99, but not C89
 
A global variable must be declared outside of all functions, including outside the main( ) function. Global variables are generally placed at the top of the file, prior to main( ), for ease of reading and because a variable must be declared before it is used.
The formal parameters to a function are also local variables and, aside from their job of receiving the value of the calling arguments, behave and can be used like any other local variable.
Namespaces

In C++, it is possible to create a local scope using the namespace keyword. A namespace defines a declarative region. Its purpose is to localize names. The general form of namespace is shown here:

namespace name {
 // ...
}
Here, name is the name of the namespace. For example,
namespace MyNameSpace {
  int count;
}
 
This creates a namespace called MyNameSpace and the variable count is declared inside it.
Names declared within a namespace can be referred to directly by other statements within the same namespace. Outside their namespace, names can be accessed two ways. First, you can use the scope resolution operator. For example, assuming MyNameSpace just shown, the following statement is valid:
MyNameSpace::count = 10;
You can also specify a using statement, which brings the specified name or namespace into the current scope. For example,
using namespace MyNameSpace;
count = 100;
 
In this case, count can be referred to directly because it has been brought into the current scope.
When C++ was originally invented, items declared in the C++ library were in the global (i.e., unnamed) namespace. However, Standard C++ puts all of these items into the std namespace.

The main( ) Function

In a C/C++ program, execution begins at main( ). (Windows programs call WinMain( ), but this is a special case.) You must not have more than one function called main( ). When main( ) terminates, the program is over and control passes back to the operating system.
The main( ) function is not prototyped. Thus, different forms of main( ) may be used. For both C and C++, the following versions of main( ) are valid
:
int main() int main(int argc, char *argv[])
 
As the second form shows, at least two parameters are supported by main( ). They are argc and argv. (Some compilers will allow additional parameters.) These two variables will hold the number of command-line arguments and a pointer to them, respectively. argc is an integer, and its value will always be at least 1 because the program name is the first argument as far as C/C++ is concerned. argv must be declared as an array of character pointers. Each pointer points to a command-line argument. Their usage is shown below in a short program that will print your name on the screen:
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
  if(argc<2)
    cout << "Enter your name.\n";
  else
    cout << "hello " << argv[1];

  return 0;
}
 

Function Arguments

If a function is to use arguments, it must declare variables that accept the values of the arguments. These variables are called the formal parameters of the function. They behave like other local variables inside the function and are created upon entry into the function and destroyed upon exit. As with local variables, you can make assignments to a function’s formal parameters or use them in any allowable C/C++ expression. Even though these variables perform the special task of receiving the value of the arguments passed to the function, they can be used like any other local variable.
In general, subroutines can be passed arguments in one of two ways. The first is called call by value. This method copies the value of an argument into the formal parameter of the subroutine. Changes made to the parameters of the subroutine have no effect on the variables used to call it. Call by reference is the second way a subroutine can have arguments passed to it. In this method, the address of an argument is copied into the parameter. Inside the subroutine, the argument is accessed through this address. This means that changes made to the parameter affect the variable used to call the routine.
By default, C and C++ use call by value to pass arguments. This means that you generally cannot alter the variables used to call the function. Consider the following function:
int sqr(int x)
{
  x = x*x;
  return x;
}
 
In this example, when the assignment x = x * x takes place, the only thing modified is the local variable x. The argument used to call sqr( ) still has its original value.
Remember that only a copy of the value of the argument is passed to a function. What occurs inside the function has no effect on the variable used in the call.

Passing Pointers

Even though C and C++ use call-by-value parameter passing by default, it is possible to manually construct a call by reference by passing a pointer to the argument. Since this passes the address of the argument to the function, it is then possible to change the value of the argument outside the function.
Pointers are passed to functions just like any other value. Of course, it is necessary to declare the parameters as pointer types. For example, the function swap( ), which exchanges the value of its two integer arguments, is shown here:
// Use pointer parameters.
void swap(int *x, int *y)
{
  int temp;

  temp = *x;  // save the value at address x 
  *x = *y;    // put y into x 
  *y = temp;  // put x into y 
} 
 
It is important to remember that swap( ) (or any other function that uses pointer parameters) must be called with the addresses of the arguments. The following fragment shows the correct way to call swap( ):
int a, b;

a = 10;
b = 20;
swap(&a, &b);
 
In this example, swap( ) is called with the addresses of a and b. The unary operator & is used to produce the addresses of the variables. Therefore, the addresses of a and b, not their values, are passed to the function swap( ). After the call, a will have the value 20 and b will have the value 10.

Reference Parameters

In C++, it is possible to automatically pass the address of a variable to a function. This is accomplished using a reference parameter. When using a reference parameter, the address of an argument is passed to the function and the function operates on the argument, not a copy.
To create a reference parameter, precede its name with the & (ampersand). Inside the function, you can use the parameter normally, without any need to use the the * (asterisk) operator. The compiler will automatically dereference the address for you. For example, the following creates a version of swap( ) that uses two reference parameters to exchange the values of its two arguments:
// Use reference parameters. 
void swap(int &x, int &y)
{
  int temp;

  temp = x;  // save the value at address x 
  x = y;     // put y into x 
  y = temp;  // put x into y 
}
 
When invoking swap( ), you simply use the normal function-call syntax. For example,
int a, b;

a = 10;
b = 20;
swap(a, b); 
 
Because x and y are now reference parameters, the addresses of a and b are automatically generated and passed to the function. Inside the function, the parameter names are used without any need for the * operator because the compiler automatically refers to the calling arguments each time x and y are used.
Reference parameters apply only to C++.

Constructors and Destructors

In C++, a class may contain a constructor function, a destructor function, or both. A constructor is called when an object of the class is first created and the destructor is called when an object of the class is destroyed. A constructor has the same name as the class of which it is a member and the destructor’s name is the same as its class, except that it is preceded by a ~. Neither constructors nor destructors have return values.
Constructors may have parameters. You can use these parameters to pass values to a constructor, which can be used to initialize an object. The arguments that are passed to the parameters are specified when an object is created. For example, this fragment illustrates how to pass a constructor an argument:
class myclass {
  int a;
public:
  myclass(int i) { a = i; } // constructor
  ~myclass() { cout << "Destructing..."; }
};

// ...

myclass ob(3); // pass 3 to i
 
When ob is declared, the value 3 is passed to the constructor’s parameter i, which is then assigned to a.
In an inheritance hierarchy, a base class’ constructor is automatically called before the derived class’ constructor. If you need to pass arguments to the base class constructor, you do so by using an expanded form of the derived class’ constructor declaration. Its general form is shown here:
derived-constructor(arg-list) : base1(arg-list),
                                base2(arg-list),  
                                // ...
                               baseN(arg-list) 
{
  // body of derived constructor
}
Here, base1 through baseN are the names of the base classes inherited by the derived class. Notice that a colon separates the derived class’ constructor declaration from the base class specifications, and that the base class specifications are separated from each other by commas, in the case of multiple base classes. Here is an example:
class base {
protected:
  int i;
public:
  base(int x) { i = x; }

  // ...
};

class derived: public base {
  int j;
public:
  // derived uses x; y is passed along to base.
  derived(int x, int y): base(y) { j = x; }

  void show() { cout << i << " " << j << "\n"; }

  // ...
};
 
Here, derived’s constructor is declared as taking two parameters, x and y. However, derived( ) uses only x; y is passed along to base( ). In general, the derived class’ constructor must declare the parameter(s) that it requires as well as any required by the base class. As the example illustrates, any values required by the base class are passed to it in the base class’ argument list specified after the colon.

Function Specifiers

C++ defines three function specifiers: inline, virtual, and explicit. The inline specifier is also supported by C99. inline is a request to the compiler to expand a function’s code inline rather than to call it. If the compiler cannot inline the function, it is free to ignore the request. Both member and nonmember functions may be specified as inline.


Programming Tip 
There are two ways a constructor can initialize member variables. First, it can explicitly assign them values inside the body of the constructor. For example, consider MyClass, shown here, which has two integer data members called numA and numB. These member variables are initialized inside the MyClass constructor.
class MyClass { 
  int numA; 
  int numB; 
public: 
  /* Initialize numA and numB inside the MyClass
     constructor using normal syntax. */ 
  MyClass(int x, int y) { 
    numA = x; 
    numB = y; 
  }
  // ...
};
 
Assigning initial values to member variables numA and numB inside the constructor, as MyClass does, is a common approach, and is the way that member initialization is accomplished for many classes. However, this approach won't work in all cases. For example, if numA and numB were specified as const, like this,
class MyClass {
  const int numA; // const member
  const int numB; // const member
 
then they could not be given values by the MyClass constructor because const variables must be initialized and cannot be assigned values after the fact. Similar problems arise when using reference members, which must be initialized, and when using class members that don't have default constructors. To solve these types of problems, C++ supports a second member initialization syntax, which gives a class member an initial value when an object of the class is created.
The member initialization syntax is similar to that used to call a base class constructor. Here is the general form:
constructor(arg-list) : member1(initializer),  
                        member2(initializer), 
                        // ...
                        memberN(initializer)
{
 // body of constructor
}
 
The members that you want to initialize are specified in a comma- separated list that goes after the constructor's declaration and before the body of the constructor. Notice the use and placement of the colon. You can mix calls to base class constructors with member initializations in the same list.
Here is MyClass rewritten so that numA and numB are const members that are given values using the member initialization syntax.
class MyClass {   const int numA; // const member
  const int numB; // const member
public: 
  // Initialize using initialization syntax.
  MyClass(int x, int y) : numA(x), numB(y) { } 
  // ...
};
 
Here, numA is initialized with the value passed in x, and numB is initialized with the value passed in y. Even though numA and numB are now const, they can be given initial values when a MyClass object is created because the member initialization syntax is used.
One last point: Class members are constructed and initialized in the order in which they are declared in a class, not in the order in which their initializers occur.
A virtual function is defined in a base class and overridden by a derived class. Virtual functions are how C++ supports polymorphism.
The explicit specifier applies only to constructors. Any time that you have a constructor that requires only one argument, you can use either ob(x) or ob = x to initialize an object. The reason for this is that whenever you create a constructor that takes one argument, you are also implicitly creating a conversion from the type of that argument to the type of the class. A constructor specified as explicit will be used only when an initialization uses the normal constructor syntax, ob(x). No automatic conversion will take place and ob = x will not be allowed. Thus, an explicit constructor creates a “nonconverting constructor.”

Linkage Specification

Because it is common to link a C++ function with functions generated by another language (such as C), C++ allows you to specify a linkage specification that tells the compiler how to link a function. It has this general form:
extern "language" function-prototype
As you can see, the linkage specification is an extension to the extern keyword. Here, language denotes the language to which you want the function to link. C and C++ linkages are guaranteed to be supported. Your compiler may support other linkages, too. To declare several functions using the same linkage specification, you can use this general form:
extern"language" {
  function-prototypes
}
The linkage specification applies only to C++. It is not supported by C.

The C and C++ Standard Libraries

Neither C nor C++ have keywords that perform I/O, manipulate strings, perform various mathematical computations, or a number of other useful procedures. These things are accomplished by using a set of predefined library functions that are supplied with the compiler. There are two basic styles of libraries: the C function library, which is supplied with all C and C++ compilers, and the C++ class library, which applies only to C++. Both libraries are summarized later in this guide.
Before your program can use a library function, it must include the appropriate header. In general, headers are usually files, but they are not necessarily files. It is permissible for a compiler to predefine the contents of a header internally. However, for all practical purposes, the standard C headers are contained in files that correspond to their names. The following table shows the standard headers defined by C89, along with those added by the 1995 Amendment 1.
Header
Supports
<assert.h>
The assert( ) macro
<ctype.h>
Character handling
<errno.h>
Error reporting
<float.h>
Implementation-dependent floating-point limits
<iso646.h>
Macros that correspond to various operators, such as && and ^; added in 1995 by Amendment 1
<limits.h>
Various implementation-dependent limits
<locale.h>
Localization
<math.h>
Various definitions used by the math library
<setjmp.h>
Nonlocal jumps
<signal.h>
Signal values
<stdarg.h>
Variable-length argument lists
<stddef.h>
Commonly used constants
<stdio.h>
File I/O
<stdlib.h>
Miscellaneous declarations
<string.h>
String functions
<time.h>
System time and date functions
<wchar.h>
Multibyte and wide-character functions; added in 1995 by Amendment 1
<wctype.h>
Multibyte and wide-character classification functions; added in 1995 by Amendment 1
The following table shows those headers added by C99.
Header
Supports
<complex.h>
Complex arithmetic.
<fenv.h>
The floating-point status flags and other aspects of the floating-point environment.
<inttypes.h>
Standard, portable set of integer type names; also supports functions that handle greatest-width integers.
<stdbool.h>
Boolean data types and defines the macro bool, which helps with C++ compatibility.
<stdint.h>
Standard, portable set of integer type names. This file is included by <inttypes.h>.
<tgmath.h>
Type-generic floating-point macros.

For C++, headers are specified using standard header names, which do not end with .h. Thus, the C++ headers do not specify filenames. Instead, they are simply standard identifiers that the compiler can handle as it sees fit. This means that a header may be mapped to a filename, but this is not required. The C++ headers are shown here. Those associated either directly or indirectly with the Standard Template Library (STL) are indicated.
C++ Header
Supports
<algorithm>
Various operations on containers (STL)
<bitset>
Bitsets (STL)
<complex>
Complex numbers
<deque>
Double-ended queues (STL)
<exception>
Exception handling
<fstream>
Stream-based file I/O
<functional>
Various function objects (STL)
<iomanip>
I/O manipulators
<ios>
Low-level I/O classes
<iosfwd>
Forward declarations for I/O system
<iostream>
Standard I/O classes
<istream>
Input streams
<iterator>
Access to contents of containers (STL)
<limits>
Various implementation limits
<list>
Linear lists (STL)
<locale>
Localization-specific information
<map>
Maps (keys with values) (STL)
<memory>
Memory allocation via allocators (STL)
<new>
Memory allocation using new
<numeric>
General-purpose numeric operations (STL)
<ostream>
Output streams
<queue>
Queues (STL)
<set>
Sets (STL)
<sstream>
String streams
<stack>
Stacks (STL)
<stdexcept>
Standard exceptions
<streambuf>
Buffered streams
<string>
Standard string class (STL)
<typeinfo>
Runtime type information
<utility>
General purpose templates (STL)
<valarray>
Operations on arrays containing values
<vector>
Vectors (dynamic arrays) (STL)

C++ also defines the following headers that correspond to the C headers (except those added by C99).
<cassert>
<cctype>
<cerrno>
<cfloat>
<ciso646>
<climits>
<clocale>
<cmath>
<csetjmp>
<csignal>
<cstdarg>
<cstddef>
<cstdio>
<cstdlib>
<cstring>
<ctime>
<cwchar>
<cwctype>

In standard C++, all of the information relating to the standard library is defined under the std namespace. Thus, to gain direct access to these items, you will need to include the following using statement after including the necessary headers:
using namespace std; 
 
Alternatively, you can qualify each library identifier with std::, such as std::cout, rather than bringing the entire library into the global namespace. However, qualifying each name can get to be tedious.


Programming Tip 
If you are using an older C++ compiler, then it may not support the modern-style C++ headers or the namespace command. If this is the case, then you will need to use the older, traditional-style headers. These use the same names as the modern headers but include the .h (thus, they resemble C headers). For example, the following includes <iostream> using the traditional approach:
#include <iostream.h> 
 
When using the traditional-style header, all of the names defined by the header are placed in the global namespace, not the one defined by std. Thus, no using statement is required.

Followers