Introduction to C++


Contents

Hello World
Simple Input, Output and Arithmetic
Built-In C++ Data Types
Integral Types
The behaviour of the bool type
Floating-Point Types
How to declare the built-in types
C++ Literal Constants
Example Literals
C++ Identifiers
Enumerations
C++ Operators
Comparison and Logical Operators
Arithmetic Operators
Bitwise Operators
Assignment Operators
The if ... else Statement
The ? : Operator
The switch Statement
Loops
The while loop
The do ... while loop
The for loop
Functions in C++
Function Prototypes
C++ Arrays
C++ Structures
Pointers in C++
Pointers and Structures
Pointers and Arrays
The Null Pointer
Command-Line Arguments to Programs


Hello World


/* File:      hello.cpp
 *
 * Purpose:   Hello world application in ANSI C++.
 *
 * Version:   1.0
 *
 * Date:      August 28, 2000
 *
 * Author:    Colin Flanagan
 *
 */

#include <iostream>
using namespace std;

int main() 
{
    cout << "Hello World" << endl;
    return 0;
}

Back to Contents


Simple Input, Output and Arithmetic


// File:      quadratic.cpp                            
//                                                     
// Purpose:   Finds the roots of the quadratic equation
//            ax^2 + bx + c = 0, using the formula     
//            x = (-b +- sqrt( b^2 - 4ac )) / 2a       
//
// Version:   1.1
//
// Date:      October 6, 2000
//
// Author:    Colin Flanagan
//
//

#include <iostream>
#include <cmath>
using namespace std;

int main() 
{
    double a, b, c;
                  
    cout << "Please enter values for a, b and c --> ";
    cin >> a >> b >> c;

    double x = b * b - 4.0 * a * c;

    if ( x < 0 )
        cout << "Roots are imaginary";
    else {
        double sq = sqrt( x );
        cout << "Root 1 = "   << (-b + sq) / (2.0 * a);
        cout << ", Root 2 = " << (-b - sq) / (2.0 * a);
    }
    cout << endl;
    return 0;
}

Back to Contents


Built-In C++ Data Types

Integral Types
Type What it is Typical size (bits)
bool Boolean truth value 8
int standard-width signed integer 32
unsigned standard-width unsigned integer 32
long wide-width signed integer 32-64
unsigned long wide-width unsigned integer 32-64
short narrow-width signed integer 16-32
unsigned short narrow-width unsigned integer 16-32
char character 8
unsigned char unsigned character 8
signed char signed character 8

Back to Contents

Floating-Point Types
Type What it is Typical size (bits)
float single-precision floating-point value 32
double double-precision floating-point value 64
unsigned extended-precision floating-point value 80

Back to Contents

Declaring the Built-In Types

/*
 * File:      datatypes.cpp                            
 *
 * Purpose:   Illustrates how to declare all the essential C++
 *            built-in data types, and prints out a table of
 *            their sizes (in terms of bits of memory needed for 
 *            each).
 *
 * Version:   1.0
 *
 * Date:      September 20, 2000
 *
 * Author:    Colin Flanagan
 *
 */
#include <iostream>
#include <climits>     // needed for value of constant CHAR_BIT
using namespace std;

int main()
{
    bool           b;  // boolean, values "true" or "false".
    int            i;  // standard width signed integer
    unsigned       ui; // standard width natural number
    long           l;  // wide width signed integer
    unsigned long  ul; // wide width unsigned integer
    short          s;  // narrow width signed integer
    unsigned short us; // narrow width unsigned integer
    char           c;  // character (signed or unsigned)
    unsigned char  uc; // unsigned character
    signed char    sc; // signed character

    float          f;  // single-precision floating-point
    double         d;  // double-precision floating-point
    long double    ld; // extended-precision floating-point

    cout << "   Data Type    | Size in Bits\n";
    cout << "----------------+-------------\n";
    cout << " bool           |   " << sizeof(b)  * CHAR_BIT << '\n';
    cout << " int            |   " << sizeof(i)  * CHAR_BIT << '\n';
    cout << " unsigned int   |   " << sizeof(ui) * CHAR_BIT << '\n';
    cout << " long           |   " << sizeof(l)  * CHAR_BIT << '\n';
    cout << " unsigned long  |   " << sizeof(ul) * CHAR_BIT << '\n';
    cout << " short          |   " << sizeof(s)  * CHAR_BIT << '\n';
    cout << " unsigned short |   " << sizeof(us) * CHAR_BIT << '\n';
    cout << " char           |   " << sizeof(c)  * CHAR_BIT << '\n';
    cout << " unsigned char  |   " << sizeof(uc) * CHAR_BIT << '\n';
    cout << " signed char    |   " << sizeof(sc) * CHAR_BIT << '\n';
    cout << " float          |   " << sizeof(f)  * CHAR_BIT << '\n';
    cout << " double         |   " << sizeof(d)  * CHAR_BIT << '\n';
    cout << " long double    |   " << sizeof(ld) * CHAR_BIT << endl;
    return 0;
}

Back to Contents


C++ Literal Constants

Boolean Literals
true, false
Character Literals
A character literal is a character enclosed in single quotes, e.g., 'a', 'b'. The single quotes are character literal delimiters, they are not part of the literal. To get a character literal containing a single quote, use '\''. Here the quote has been Escaped using the Escape Character backslash (\). To get a character literal containing a backslash, use '\\'. Note also the special escaped sequences '\n' (newline) and '\t' (tab).
String Literals
A string literal is a sequence of zero or more characters (including escape sequences) enclosed in double quotes, e.g., "This is a string literal\n". The double quotes are string literal delimiters, they are not themselves part of the literal. To get a double quote inside a string literal, it is necessary to escape it, e.g., "\"".
Integer Literals
Floating-Point Literals
Example Literals

/*
 * File:      literals.cpp                            
 *
 * Purpose:   Illustration of C++ literal constants
 *
 * Version:   1.0
 *
 * Date:      September 20, 2000
 *
 * Author:    Colin Flanagan
 *
 */
#include <iostream>
using namespace std;

int main()
{
    bool truthvalue = true;
    char c = 'c', newline = '\n', tab = '\t';
    int i = 123;
    unsigned ui = 4294967295U; // This is too big to represent as a 32-bit
                               // signed value.
    int i2 = 4294967295U;      // Compiler accepts this, performs the 
                               // initialisation, but the value in i2 is 
			       // interpreted as signed, hence -ve (as the
			       // MSB of the unsigned literal is set).
    int hi = 0xffffffff;       // This is the same value as ui, but represented
                               // as a hex literal. Note that we are putting 
			       // this in a signed integer, so the result is
			       // -ve (as the MSB of the literal is set).
    int hui = 0xffffffff;      // Again, same value as ui.
    int oi = 0777;             // 0777 is an octal literal.
    long l = 123L;             // 123 is a long literal.
    unsigned long ul = 123UL;  // 123 is now an unsigned long literal.
    float f = 1.2f;
    double d = -1.2e300;

    cout << " truthvalue = " << truthvalue 
         << "\n c = " << c
	 << "\n newline (effect appears between quotes) = \"" << newline << '"'
	 << "\n tab (effect appears between quotes) = \"" << tab << '"'
	 << "\n i = " << i
	 << "\n ui = " << ui
	 << "\n i2 = " << i2
	 << "\n hi = " << hi
	 << "\n hui = " << hui
	 << "\n oi = " << oi
	 << "\n l = " << l 
	 << "\n ul = " << ul 
	 << "\n d = " << d 
	 << "\n f = " << f << endl;


    cout << " size of bool literal (in chars): " << sizeof(true)
         << "\n size of char literal \'c\': " << sizeof('c')
         << "\n size of int literal 123: " << sizeof(123)
         << "\n size of hex literal 0xffffffff: " << sizeof(0xffffffff)
         << "\n size of octal literal 0777: " << sizeof(0777)
         << "\n size of long literal 123L: " << sizeof(123L)
         << "\n size of unsigned long literal 123UL: " << sizeof(123UL)
         << "\n size of unsigned long literal 123ul: " << sizeof(123ul)
         << "\n size of unsigned long literal 123lu: " << sizeof(123lu) 
         << "\n size of unsigned long literal 123LU: " << sizeof(123LU) << endl;

    return 0;
}

Back to Contents


C++ Identifiers

Back to Contents


Enumerations

A C++ Enumeration is a data-type. It differs from the built-in types in that it consists of a set of values specified by the programmer. Once defined, an enumeration is used very much like an integer type.

Enumerations are normally used when we need some constants with meaningful names in a program, but we don't care very much about their values. For example, we can write


enum months { Jan, Feb, Mar, April, May, June,
              July, Aug, Sept, Oct, Nov, Dec
	    } thismonth, lastmonth;

Given this declaration in a program, we can use:

The first constant in an enumeration has integer value 0, the next 1, etc. You can change this if you want to force the elements of an enumeration to have specific values.


enum revolutions { AMERICAN = 1776, FRENCH = 1789,
		   RUSSIAN = 1917,  CHINESE = 1948 };

The constant AMERICAN of type revolutions has value 1776, etc.

Back to Contents


C++ Operators

C++ has a large set of operators. Operators are used in Expressions along with literals and variables, to generate values.

The C++ operators include:

Back to Contents


Comparison and Logical Operators

Comparison Operators
Operator Purpose Example
expr1 == expr2 Test if expr1 equal to expr2 a == 5
expr1 != expr2 Test if expr1 not equal to expr2 a != 5
expr1 < expr2 Test if expr1 less than expr2 a < 5
expr1 <= expr2 Test if expr1 less than or equal to expr2 a <= 5
expr1 > expr2 Test if expr1 greater than expr2 a > 5
expr1 >= expr2 Test if expr1 greater than or equal to expr2 a >= 5

Logical Operators
Operator Purpose Example
expr1 && expr2 Perform Boolean (logical) AND of expr1 and expr2 a >= 5 && a < 10
expr1 || expr2 Perform Boolean (logical) OR of expr1 and expr2 a <= 5 || a > 10
! expr Perform Boolean (logical) NOT on expr !(a <= 5 || a > 10)

Back to Contents


Arithmetic Operators

Operator Purpose Example
expr1 * expr2 Multiply expr1 by expr2 a * 10
expr1 / expr2 Divide expr1 by expr2 a / 10
expr1 % expr2 Find the remainder when expr1 is divided by expr2 30 % 7
expr1 + expr2 Add expr2 to expr1 a + 7
expr1 - expr2 Subtract expr2 from expr1 a - 7
- expr Negate expr -a
++ var Add 1 to var (preincrement) ++a
var ++ Add 1 to var (postincrement) a++
-- var Subtract 1 from var (predecrement) --a
var -- Subtract 1 from var (postdecrement) a--

Back to Contents


Bitwise Operators

Operator Purpose Example
expr1 & expr2 Bitwise AND of expr1 and expr2 a & 0xff
expr1 | expr2 Bitwise OR of expr1 and expr2 a | 0555
expr1 ^ expr2 Bitwise Exclusive-OR of expr1 and expr2 a ^ 1
~ expr Negate bits of expr ~a
expr1 << expr2 Left shift expr1 by expr2 bit positions a << 1
expr1 >> expr2 Right shift expr1 by expr2 bit positions a >> 2

Back to Contents


Assignment Operators

Operator Purpose Example
var = expr Put result of evaluating expr into var a = 20
var *= expr Multiply var by expr and put result back in var a *= 20
var /= expr Divide var by expr and put result back in var a /= 20
var %= expr Generate var % expr and put result back in var a %= 20
var += expr Add expr to var and put result back in var a += 20
var -= expr Subtract expr from var and put result back in var a -= 20
var &= expr Bitwise AND expr with var and put result back in var a &= 20
var |= expr Bitwise OR expr with var and put result back in var a |= 20
var ^= expr Bitwise Exclusive-OR expr with var and put result back in var a ^= 20
var <<= expr Left shift contents of var by expr bits and put result back in var a <<= 2
var >>= expr Right shift contents of var by expr bits and put result back in var a >>= 2

Back to Contents


The if ... else Statement

This is the basic decision statement in C++. It comes in two flavours, with and without an else block.

if (<Boolean Expression>)
    <if-part>
else
    <else-part>
and

if (<Boolean Expression>)
    <if-part>

Examples:


/*
 * File:      ifelse.cpp                            
 *
 * Purpose:   Illustrates the use of C++ if and if-else.
 *
 * Version:   1.0
 *
 * Date:      September 20, 2000
 *
 * Author:    Colin Flanagan
 *
 */
#include <iostream>
using namespace std;

int main()
{
    char ch;

    cout << "Please enter a character "; cin >> ch;

    if ( ch >= 'A' && ch <= 'Z' )  
        cout << "Uppercase";
    else if ( ch >= 'a' && ch <= 'z' ) {
        cout << "Lowercase, converting to uppercase";
	ch += 'A' - 'a';  // ch = (ch - 'a') + 'A';
    }
    else if ( ch >= '0' && ch <= '9' )
        cout << "Digit";
    else
        cout << "Not alphanumeric";

    if ( ch == '.' || ch == ',' || 
         ch == '?' || ch == '!' )
        cout << ", punctuation";

    cout << ": '" << ch << '\'' << endl;
    return 0;
}

Back to Contents


The ? : Operator

This special operator allows simple if ... else decisions to be made in a very compact style.


max = (a > b) ? a : b;

Here max gets assigned the value of the expression following the ? if the Boolean preceding it is true, and gets assigned the value of the expression following the : if the Boolean is false.

It is equivalent to the if ... else code:


if ( a > b )
    max = a;
else
    max = b;

Back to Contents


The switch Statement

The switch statement is an alternative approach to handling multiway branches.


if ( ch == '+' )       acc += value;
else if ( ch == '-' )  acc -= value;
else if ( ch == '*' )  acc *= value;
else if ( ch == '/' )  acc /= value;
else
    cout << "Error" << end;
can be coded, using a switch statement, as:

switch ( ch ) {
    case '+' :  acc += value;  break;
    case '-' :  acc -= value;  break;
    case '*' :  acc *= value;  break;
    case '/' :  acc /= value;  break;
    default  :  
        cout << "Error" << end;
	break;
}

Back to Contents


The while loop

This is the simplest type of looping construct found in C++. It consists of a while keyword, followed by a Boolean Expression enclosed in parentheses, followed by a Loop Body, which is either a single statement or a block of statements. Before the loop body can be executed, the Boolean expression must be evaluated. If the Boolean is true, the loop body is executed, and the while loops back to evaluate the Boolean again. If the Boolean is false, the loop exits, and execution of the program continues with the following statement.


int i = 0;
while ( i < 10 ) {
    cout << i << ' ';
    i++;
}
cout << "Loop done" << endl;
Output of this is:

0 1 2 3 4 5 6 7 8 9 Loop done

Back to Contents


The do ... while loop

The do ... while loop is similar to the while loop, but the Boolean test occurs after the loop body. This means that the loop body of a do ... while loop is always executed at least once.


int i = 10;
do {
    cout << i << ' ';
    i++;
} while ( i < 10 );
cout << "Loop done" << endl;
Output of this is:

10 Loop done

The equivalent while loop would not execute its loop body at all if i were initially 10.

Back to Contents


The for loop

The for loop is the most important type of loop construct in C++. It is similar to a while loop, but it also allows for the initialisation and incrementing of loop variables to occur in the for loop header.


for (int i = 0; i < 10; i++) cout << i << ' ';
cout << "Loop done" << endl;

This has the same effect as the while loop shown earlier. If fact, any for loop may always be rewritten as an equivalent while loop.


int i;
float fact10;

for (i = 2, fact10 = 1.0f; i <= 10; i++)
    fact10 *= i;

i = 2;
fact10 = 1.0f;
while (i <= 10) {
    fact10 *= i;
    i++;
}

The for loop is very flexible in C++.

Back to Contents


Functions in C++

Functions in C++ are one way to divide code up into manageable units. We have already seen one C++ function, main, which must be part of every C++ program. All other C++ functions have a similar syntax to main.

<Return Type> <Function Name> ( <Parameter List> ) {
     <Statement>
        .
        .
        .
     <Statement>
}

/*
 * File:      function.cpp                            
 *
 * Purpose:   Illustrates the use of C++ functions.
 *
 * Version:   1.0
 *
 * Date:      October 5, 2000
 *
 * Author:    Colin Flanagan
 *
 */
#include <iostream>
#include <iomanip>
using namespace std;

/* ----------------------------------------------------------
 *
 * f:         Calculate f(x) = 2x^2 + 3x + 4
 *
 * Input(s):  x, a float
 *
 * Output(s): none
 *
 * Returns:   f(x), a float
 *
 */

float f(float x) {
    return (2.0f * x + 3.0f) * x + 4.0f;
}

/* ----------------------------------------------------------
 *
 * main
 *
 */

int main()
{
    for (float val = -1.0f; val <= -0.5f; val += 0.05f) 
	cout << right << fixed << setprecision(2) << setw(5) 
	     << val << " | "
	     << right << fixed << setprecision(4) << setw(7) 
	     << f(val) << '\n';
    return 0;
}

Back to Contents


Function Prototypes

A Function Prototype is a Declaration of a function without its corresponding Definition. It looks like the header of a function without the body.

Function Prototypes are used in C++ to allow the definitions of functions to be placed in multiple source files. As long as a C++ compiler has access to a function prototype, it can generate the appropriate code for a function call. The actual code needed to implement the function may be compiled separately and later linked to the code of its caller to generate an executable file.

Example: Consider the function f above. It is not necessary to have access to the definition of f in order to compile the code for main, all the compiler needs to do this is know:

in order to generate code for a call to f within main. Here is a version of the file function.cpp which contains a function prototype for f, but does not contain its definition.

#include <iostream>
#include <iomanip>
using namespace std;

float f(float x);   // Function prototype for f.

int main()
{
    for (float val = -1.0f; val <= -0.5f; val += 0.05f) 
	cout << right << fixed << setprecision(2) << setw(5) 
	     << val << " | "
	     << right << fixed << setprecision(4) << setw(7) 
	     << f(val) << '\n';
    return 0;
}
A separate source file contains the definition of f. Note that the function prototype is terminated by a semicolon in place of a function body.

This technique of Separate Compilation allows large projects to be broken up into a number of smaller units. These smaller units compile quickly and are linked together to generate an executable file.

It may be necessary for a function prototype to be visible in multiple source files. Rather than repeat the function prototype in the various source files, with the associated possibility of incorrect definition, it is common practice in C++ to group sets of related function prototypes into a Header File, and use an #include directive to incorporate the header file into a source file where these function prototypes are needed. Since there is now only one function prototype for a function (held in the header file), errors are much less likely to occur than if the function prototype is re-written in each source file where it is needed.

The appropriate header file is commonly also #included in the source file where a function is defined. Strictly speaking, this is not necessary, the function prototype does not include any information which is required in order to compile the function definition. However, the practice is very useful because it serves as a consistency check, a guarantee that the various uses of a function and its implementation are agreed about what its interface should look like.

Here is the earlier example divided up into a header file f.h, and two source files, f.cpp and main.cpp. file.


#ifndef F_HEADER
#define F_HEADER 1
/*
 * File:      f.h
 *
 * Header file containing function prototype for function
 * f(x).  Definition iof f(x) in file f.cpp.
 *
 */

float f(float x);
#endif

/*
 * File:      f.cpp
 *
 */
#include "f.h"         // Include header for function f(x).

/* --------------------------------------------------------
 *
 * f:         Calculate f(x) = 2x^2 + 3x + 4
 *
 * Input(s):  x, a float
 *
 * Output(s): none
 *
 * Returns:   f(x), a float
 *
 */

float f(float x) {
    return (2.0f * x + 3.0f) * x + 4.0f;
}

/*
 * File:      main.cpp
 *
 */
#include <iostream>
#include <iomanip>
#include "f.h"         // Include header for function f(x).
using namespace std;

int main()
{
    for (float val = -1.0f; val <= -0.5f; val += 0.05f)
	cout << right << fixed << setprecision(2) << setw(5)
	     << val << " | "
	     << right << fixed << setprecision(4) << setw(7)
	     << f(val) << '\n';
    return 0;
}

A final point about function prototypes. The formal parameter names in a function prototype are dummies. They are not needed. All that you need in a function prototype is the data type of each formal parameter, (e.g., "float f(float);" is fine). However, including formal parameter names in function prototypes is perfectly legal and may help to make the prototype more readable, so you are encouraged to do it.

Back to Contents


C++ Arrays

C++ allows single and multi-dimensional arrays of data elements. Declarations are made by including the size of the array associated with a variable in square brackets after its name:

char a[7], buff[256];
int vals[35];
float v[3];
double matrix[3][3];
Here we have declared a to be a 7-element array of chars. buff is also an array of chars, but has 256 elements. vals is an array of ints with 35 elements, and v is an array of floats with 35 elements. All these arrays are 1-dimensional. Array matrix, on the other hand, is 2-dimensional, comprising 9 doubles.

Accessing the elements of an array makes use of the Array Subscript operator ([ ]). Here is an example program which sorts an array of 5 values read from the standard input.


/*
 * File:      sort.cpp                            
 *
 * Purpose:   Sorts an array of 5 integers read
 *            from the standard input.
 *            A simple bubble sort is used.
 *
 * Version:   1.0
 *
 * Date:      October 6, 2000
 *
 * Author:    Colin Flanagan
 *
 */
#include <iostream>
using namespace std;

int main()
{
    const int MAX = 5;
    int elements[MAX], i;

    cout << "Enter " << MAX << " integer values to sort --> ";
    for (i = 0; i < MAX; i++)  cin >> elements[i];

    bool swappedElements = true;
    while ( swappedElements ) {
        swappedElements = false;
	int j;
	for (i = 0, j = 1; j < MAX; i++, j++)
	    if ( elements[i] > elements[j] ) {
		int temp = elements[i];
		elements[i] = elements[j];
		elements[j] = temp;
		swappedElements = true;
            }		
        for (i = 0; i < MAX; i++)  cout << elements[i] << ' ';
        cout << endl; 
    }
    cout << "Sorted elements: ";
    for (i = 0; i < MAX; i++)  cout << elements[i] << ' ';
    cout << endl; 
    
    return 0;
}

Multi-dimensional arrays are "arrays of arrays". For example, matrix[3][3] is an array of size 3, where each of its elements is also an array of size 3. Access to multi-dimensional arrays just requires multiple [ ] operators. Here is code which calculates and outputs the inverse of a 2 x 2 matrix. It is a good example of the use of multi-dimensional arrays.


#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double m[2][2], invM[2][2];

    for (int i = 0; i < 2; i++)     // Read in matrix m.
        for (int j = 0; j < 2; j++)
	    cin >> m[i][j];

    // Calculate "ad - bc", the scale factor for the
    // inverse. This must be non-zero if the matrix
    // has an inverse.
    double adbc = m[0][0] * m[1][1] - m[0][1] * m[1][0];

    if ( adbc == 0.0 )
        cout << "matrix has no inverse" << endl;
    else {
        // Inverse calculation using the well-known
	// formula.
        invM[0][0] =  m[1][1] / adbc;
        invM[1][1] =  m[0][0] / adbc;
        invM[0][1] = -m[0][1] / adbc;
        invM[1][0] = -m[1][0] / adbc;

        // Code to display the inverse.
        cout << fixed << setprecision(5);	
	for (int i = 0; i < 2; i++) {
	    for (int j = 0; j < 2; j++) {
	        cout << setw(9) << invM[i][j];
		if ( j == 0 ) cout << ", ";
	    }
	    cout << '\n';
	}
    }
    return 0;
}

Arrays may be passed to functions. A function which accepts a 1-dimensional array as an argument does not need to specify the array size in its formal argument list.


#include <iostream>
using namespace std;

const int VECTOR_SIZE = 3;

float innerprod(float v1[], float v2[]);
void readVector(float v[]);

//------------------------------------------------------------------
//
// Function:	    main
//

int main()
{
    float v1[3], v2[3];

    cout << "Enter vector 1 (" << VECTOR_SIZE << " elements) --> ";
    readVector(v1);
    
    cout << "Enter vector 2 (" << VECTOR_SIZE << " elements) --> ";
    readVector(v2);

    cout << "The inner product of v1 and v2 = " << innerprod(v1, v2) 
         << endl;
    return 0;
}

//------------------------------------------------------------------
//
// Function:	    innerprod
//
// Inputs:	    Two vectors of floats, both of size VECTOR_SIZE.
// Outputs:	    None.
// Returns:	    A float.
// Purpose:	    Calculates the inner product of the argument
//                  vectors.
// Side Effects:    None.
//

float innerprod(float v1[], float v2[]) 
{
    float acc = 0.0f;
    for (int i = 0; i < VECTOR_SIZE; i++) acc += v1[i] * v2[i];
    return acc;
}

//------------------------------------------------------------------
//
// Function:	    readVector
//
// Input:	    A vector of floats, of size VECTOR_SIZE.
// Output:	    The same vector, with its contents modified to
//		    values read from the standard input.
// Returns:	    Nothing.
// Purpose:	    Reads elements into vector supplied as actual
//		    parameter.
// Side Effects:    Modifies actual parameter to call.
//

void readVector(float v[])
{
    for (int i = 0; i < VECTOR_SIZE; i++) cin >> v[i];
}

Arrays in C++ may be Explicitly Initialised when they are declared. If a 1-dimensional array is explicitly initialised it is not necessary to give its size, as C++ can work this out by counting the elements.


int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
Here primes is a 1-dimensional array of size 9.

Explicit initialisation applies to multi-dimensional arrays as well. However, in this case you have to specify the sizes of all the dimensions except the major one.


double matrix[][3] = { { 10.0, 20.0, 30.0 },
                       { 40.0, 50.0, 60.0 } };
Here matrix is a 2-dimensional array containing 2 1-d arrays each of size 3.

String literals in C++ are a type of array (array of char). A string literal consists of the characters of the string, terminated by a Null Character, automatically inserted by the C++ compiler to indicate "end of string". Hence, the character literal "Hi" has three elements, 'H', 'i' and '\0' (the C++ notation for the null character). The null character always has an integer value of zero.

Arrays of char may be explicitly initialised by using string literals.


char hello[] = "Hello";
This creates a 6-element array of char. Hello[0] is 'H', Hello[1] is 'e', and Hello[5] is '\0'.

The fact that a null character is guaranteed to appear at the end of a properly formed string literal is used extensively in C++ manipulation of arrays of char.


void to_uppercase(char s[])
{
    for (int i = 0; i < 1000 && s[i] != '\0'; i++)  
        if ( s[i] >= 'a' && s[i] <= 'z' ) s[i] += 'A' - 'a';
}

Back to Contents


C++ Structures

A Structure in C++ is a Composite Data Type, i.e., a way to group together a number of data elements and treat them as a unit. Example: a Date could be made up of integers representing the day, month and year:

struct Date {
    int day;
    int month;
    int year;
};
Now Dates can be declared in C++ programs just as if they were built-in types.

Access to the members of a structure is performed using the Dot Operator (".").


#include <iostream>
using namespace std;

struct Date {
    int day;
    int month;
    int year;
};

char monthNames[][4] = { "Jan", "Feb", "Mar", "Apr", 
                         "May", "Jun", "Jul", "Aug", 
			 "Sep", "Oct", "Nov", "Dec" };

void displayDate(Date d);

int main()
{
    Date today, last_year;

    today.day = 10;
    today.month = 10;
    today.year = 2000;

    Date tomorrow = today;
    tomorrow.day++;

    last_year = today;  last_year.year--;

    cout << "Today is "; displayDate(today);
    cout << "\nTomorrow will be "; displayDate(tomorrow);
    cout << "\nLast year was "; displayDate(last_year);
    cout << endl;
    return 0;
}

void displayDate(Date date) 
{
    cout << monthNames[date.month-1] << ' ' 
         << date.day << ", " << date.year;
}

The fields within a structure do not have to be homogeneous. They may be of differing types.


struct student {
    int   id_number;
    float qca;
    char  firstname[40];
          lastname[40];
          middleinitial;
};

Back to Contents


Pointers in C++

In C++ a Pointer is a variable which holds the Memory Address of another variable as its contents.

Pointers have types, i.e., a given pointer variable is only allowed to point to (i.e., contain the address of) other variables of a certain type. Thus C++ has "pointers to int", "pointers to float", "pointers to char", etc., but a pointer to an int may only point to an int variable, never a char variable or a float variable.

Pointers are declared very much like any other variables, except that they have a special symbol, (the asterisk, "*") to denote that they are pointers and not standard variables.


char ch, *chptr;
int x, y, *pi;
float f, *pf;
double *pointerToDouble;
Here chptr is a pointer to a char, pi is a pointer to an int, pf is a pointer to a float, and pointerToDouble is a pointer to a double. Note how declarations of pointers may be mixed with declarations of ordinary variables (ch, x, y, & f).

Note that declaring a pointer does not initialise it. All the pointers above may be assumed initially to contain random values. Attempting to use an uninitialised pointer in a program will usually cause a run-time error (often the compiler will warn you if it thinks a pointer - or any variable - is being used before it is initialised).

To initialise a pointer to point to a valid variable requires the use of the Address-Of operator ("&"). Here is code which declares and initialises a pointer to an integer.


int value = 22, *ptr;

ptr = &value;          // "ptr" now contains the address of "value".

To get at the value of a variable via a pointer requires the use of the Dereference operator (the asterisk, "*").


int value = 22, *ptr;

ptr = &value;          // "ptr" now contains the address of "value".

cout << value << ' ';  // Print contents of "value" variable.

cout << *ptr << '\n';  // Print contents of "value", but access
                       // via pointer "ptr", using dereference.
(Note that C++ has several uses for the asterisk: as a way of declaring pointers; as a way of dereferencing them; and as a multiplication operator. Be careful you understand what context an asterisk is being used in.)

Pointers and Structures

Pointers to structures may be declared in a similar way to pointers to any of the built-in types. For example, given the Date structure from above, we may declare: Date today, *ptoday;, where today is a variable of type Date and ptoday is a pointer to a variable of type Date.

C++ has a special operator to allow the elements of a structure to be accessed via a pointer. We could use (*ptoday).day to access the day field of variable today via dereferencing through ptoday, or we may use ptoday->day to achieve the same result. The Arrow operator ("->") allows direct access to the fields of a structure through a pointer to that structure.


Date today, *ptoday;

ptoday = &today;       // "ptoday" now contains the address of "today".

ptoday->day = 10;      // Modify fields of "today" thru pointer, using
ptoday->month = 10;    // arrow operator.
ptoday->year = 2000;

cout << today.day      // today.day = 10 (modified thru pointer)
     << '/'
     << today.month    // today.month = 10
     << '/'
     << today.year;    // today.year = 2000

Pointers and Arrays

Pointers and arrays have a special relationship in C++.


int i, primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, -1 };

for (i = 0; primes[i] > 0; i++) cout << primes[i] << ' ';

for (i = 0; *(primes+i) > 0; i++) cout << *(primes+i) << ' ';

for (int *pptr = primes; *pptr > 0; pptr++) cout << *pptr << ' ';

The Null Pointer

Sometimes it is convenient to specify that a pointer variable currently doesn't hold a valid address. Such a pointer is called a Null Pointer, and is specified in C++ by using the constant 0. Any pointer can be assigned this value, and any pointer containing this value is null, i.e., currently not pointing at anything.

Here is an example of the use of null pointers. A structure can be defined to contain a pointer to structures of the same type. This allows the structure to be used to build a linked-list.


struct node {
    int id;        // student id number
    char name[40]; // student name
    node *next;    // next node in list
};
The following is a function which traverses such a linked list looking for a particular student id and returns the name of that student if a match is found. If no match is found, a null pointer is returned.

char *search(node *listNode, int id)
{
    while ( listNode != 0 && listNode->id != id )
        listNode = listNode->next;

    return (listNode ? listNode->name : 0);
}

Note for C programmers: C++ does not make use of the preprocessor macro NULL. Anywhere a C program would use NULL, the C++ style is to use 0.

Back to Contents


Command-Line Arguments to Programs

C++ allows the use of Command-Line Arguments to pass information to programs from the command line. To make use of command-line arguments in a program, we must declare the main function in a special way:

int main(int argc, char *argv[])
Here the first parameter, argc, will be filled in by the operating system with the number of command-line arguments passed to the program when it is run. The second parameter is an array of pointers to null-terminated arrays of char which are the string representations of the arguments themselves.

The two formal parameters may have any names you like, but it is traditional in C and C++ programming to call them argc and argv. (argument count and argument vector). They must have the types shown above, however.

Here is a program which echoes back the command-line parameters is receives:


/*
 * Program:	echoargs
 *
 * Purpose:	Illustrate the use of command-line arguments by echoing all
 *		such arguments back to the user.
 *
 */
 
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    cout << argc << " command-line parameters were passed to the program.\n";
    for (int i = 0; i < argc; i++)
        cout << "Argument[" << i << "] is :" << argv[i] << '\n';
    return 0;
}
If you run this program you will notice that argv[0] is the name of the program itself. C++ always returns the name of the currently executing program as its first command-line parameter. Subsequent parameters will appear in successive elements of argv:

F:\modules\c++\notes> echoargs hello world, my name is Colin
7 command-line parameters were passed to the program.
Argument[0] is :F:\modules\c++\notes\echoargs.exe
Argument[1] is :hello
Argument[2] is :world,
Argument[3] is :my
Argument[4] is :name
Argument[5] is :is
Argument[6] is :Colin
It is the operating system which is responsible for breaking up the command line into parameters. It normally splits the command line up by separating parameters where whitespace appears.

Back to Contents


Colin Flanagan / 19-October-2000