C++ - C++ Primer 2

Pointers

Pointers are denoted by a * preceding the name of the identifier in a variable declaration.

Example: 
int *p;

p now points to an integer. To de-reference a pointer, and get access to the actual data, the de-reference operator * must be prefixed to the variable name.

Example: 
*p = 12;

To retrieve the address of a variable, the & operator must be used.

Example: 
int *p, y=10; 
p = &y; 
*p += 1;

Pointers that do not have an initial type can be declared as void, but they must be typecast before being de-referenced. Similarly a pointer to one type can be typecast to another.

Example: 
void *p; 
int y; 
(int *)p = &y; 
*((int *)(p)) = 12;

Pointers are especially useful when used to define advanced data structures like linked lists, trees and queues. In this case the pointers normally point to a struct.

Example: 
struct Complex { 
   float Real, Imaginary 
}; 
typedef struct Complex complex; 
complex ComplexNo, ComplexNoPtr; 
ComplexNo.Real = 1; 
ComplexNoPtr = &ComplexNo; 
(*ComplexNoPtr).Imaginary = -1;

In the above example, the de-reference and index operation being performed in the last line can be replaced with a single operator, ->. Thus it would become:

ComplexNoPtr->Imaginary = -1;

Pointers are very useful to allow functions to modify parameter values. If the address of a parameter is passed instead of its value, then this can be de-referenced to modify the actual value. Obviously this means that the formal parameter must also be a pointer.

Example: 
void Increment ( int *p ) 
{
   (*p)++;
}
void main ()
{
   int x=0;
   Increment (x);
}

Function can also have return values that are pointers.

Example:
int *IncrementPtr ( int *i )
{
   i++;
}

Memory can be allocated to a pointer by using either a standard library function or the new operator. new takes a single parameter, being the type of the variable to be allocated. Allocation with new must be followed by de-allocation with delete.

Example:
int *p = new int;
delete p;

The default non-assigned pointer takes on a value of NULL;

References

The alternative method of passing variable parameters in C++ is through reference variables. References provide an alias for variables i.e. two variables with different namesshare the same data space.

References are declared by an "&" between the type and the variable name.

Example:
int a;
int &i = a;

References in non-parameteric usage must be bound to a variable when declared. This is because, unlike pointers, the reference cannot be made to point to another location later on. In the above example "a" and "i" both access the same data.

In the context of functions, parameters can be declared as references. This is analagous to the "var" type of parameter in Pascal. If the value of the parameter is changed within the function, its actual value changes since the reference is merely an alias. Unlike pointers, reference variables are passed like normal value parameters i.e. their addresses are not taken.

Example:
void Increment ( int &a )
{
   a++;
}
...
   Increment (x);

References are very useful when passing large data structures as parameters even when the parameter is not being changed. This is because internally C only passes the address of the data to the function, making the function call much faster.

Strings

As previously mentioned, strings are defined as arrays of characters. Thus the individual elements of a string can be accessed as if the string were an array. Arrays, on the other hand, are handled internally as pointers to the first element. Thus, a string can be considered as a pointer to the first element of a character array.

In order to manipulate a string, the string must have a data space by defining a character array. However, in order to reference this string or pass it as a parameter to another function, the string can be considered as a pointer to a char viz. the first character in the array.

Example:
char aString[]="Hello";
char *p;

In the above example, the string is given an initial value, but since this initial value is fixed, the compiler can calculate the length and it is not necessary.

Character arrays and character pointers can be interchanged freely, as long as the programmer takes note of the fact that arrays have an associated data space but pointers do not. Thus it is perfectly legal to execute

   p = aString;

but very dubious indeed to execute

   aString = p;

In normal usage, strings are declared as character arrays at the very outset and then passed to functions which manipulate them. Since character arrays and pointers can be interchanged, the formal parameter can be an array and the actual parameter can be a pointer.

Example:
void TestString ( char *s )
{
}
...
   char aString[100];
   TestString (s);

Library Functions

Each of the standard header files in C defines a set of library functions that can be used in standard C programs and, possibly also C++ programs.

stdio.h has defines standard input and output functions. printf and scanf were commonly used in C to do output and input.

Example:
printf ("Hello %s %u", aString, anInteger);

The first parameter to both printf and scanf is a string that specifies a general output pattern. This pattern includes special codes for insertion of variable values and their formatting. %s specifies that the first variable (second parameter) is a string and %u specifies that the second variable (third parameter) is an integer. Similarly, there exist codes to output all the basic data types.
There are also formatting codes to specify width and precision (for floating point numbers).

conio.h defines a set of functions to communicate with the console. There are functions to move the cursor, define windows and input and output single characters.

string.h defines functions to manipulate strings. These are absolutely vital because of the internal pointer representation of strings. In C you cannot assign one string to another. Instead you have to use the standard function strcpy, which copies the contents of one string into the other. Similarly, there are functions to compare, truncate, concatenate and search through strings.

Example:
strcpy (aString, "Hello");

mem.h and alloc.h together define a set of functions to allocate and deallocate memory.

dos.h defines DOS-specific functions.

iostream.h defines the C++ version of standard input and output.

windows.h defines the standard MS-Windows functions.

owl.h defines the Object Windows Library API for windows programming.

There are various other header files that contain specific sets of functions. Usually it is possible to deduce what the header file contains from its name. Thereafter, by either getting help or opening the header file, its contents can be ascertained.

Projects and Makefiles

In C the processes of compiling and linking a program are separate and distinct. Each source file is first compiled into an object file. Then all the object files are linked together into an executable file.

To increase modularity, functions related to each aspect of the program are grouped into separate source files. Each source file contains a set of functions. Since a function in one module may use the functions contained in the others, it has to have function headers for them. This means that each "external" function used must be specified at the top of the file. Generally, programmers tend to create general purpose modules that are used by many other modules. It would be a waste of time and disk space to include the same headers at the top of every file, so the headers are stored separately in a header file. This header file is then included using an #include directive.

To specify which files must be linked to form the executable, a makefile is normally created. This lists the command to link the object files as well as the names of the files themselves. Although makefiles are still popular in some environments (like Unix), PC-based compilers use alternative means of specifying object files. Turbo C++ uses a project file, which stores a bit more information than makefiles. Visual C++ automatically maintains the list of object files.

Each source file (with .CPP extension) has an associated header file (with .H extension). The source file contains a set of functions, including "main" if it is the main program module. The header file contains function prototypes and variable declarations. All variables declared in header files must be declared properly in a source module and declared as extern in the header file.

Sample C++ Program - Hello World

// comments can be inserted with either 
// or
/* like this */
// standard include file for input and output functions viz. printf 
#include <stdio.h> 
// standard include file for string functions viz. strcpy 
#include <string.h> 
// definition of a node in the linked list 
struct _Word { 
   char Name[100]; 
   struct _Word *Next; 
}; 
typedef struct _Word Word; 
// global variables for the head and tail of the linked list 
Word *Head=NULL, *Tail=NULL; 
// global constant 
const char CarriageReturn[]="\n"; 
// function to add a word to the linked list 
void AddWord ( const char *s = CarriageReturn ) 
{ 
   Word *p=new Word; 
   p->Next=NULL; 
   strcpy (p->Name, s); 
   if (Head==NULL) 
      Head=p; 
   else 
      Tail->Next=p; 
   Tail=p; 
} 
// function to display the contents of the linked list 
void ListWords () 
{ 
   Word *p = Head; 
   while (p!=NULL) 
   { 
      printf ("%s", p->Name); 
      p=p->Next; 
   } 
} 
// main function 
void main () 
{ 
   AddWord ("Hello"); 
   AddWord (); 
   AddWord ("World"); 
   AddWord (); 
   ListWords (); 
}