Notes on C++
Home

These primitive and private ‘learning’ notes are not information or instruction for others
Many examples are straight out of Deitel and Deitel

Table of contents

Plan 3

References 3

Comments 4

Includes 4

Variables and identifiers. Data Types 5

The fundamental data types 6

Functions 7

Escape sequence 8

Demonstrating routine, #include, arithmetic, operations, assignment, main, return 0, cout, cin, declarations, integer, double, do, loops, while 9

A routine to illustrate while 10

A routine demonstrating new-style header files and namespaces 11

The exponential routine revisited. This version also demonstrates function prototype, function definition, and the if else structure 12

Multiple statements within an if, nested if, tailors output format to result 13

Experimenting with increment and decrement operators 15

Use of for repetition structure: calculating compound interest 17

Assignments and expressions. Assignment and relational operators 19

A routine that demonstrates counter controlled repetition 21

A routine that demonstrates sentinel controlled repetition and use of iomanip and static_cast 22

Use of switch multiple selection structure 24

Promotion hierarchy for built-in data types 26

Header files 27

C++ Keywords 29

Precedence and Associativity of C++ operators 30

Structured programming 32

Demonstrating cstdlib, ctime, rand, srand, enum 33

Storage classes and scope rules 35

Scope rules 36

Recursion – Fibonacci series 37

Functions with empty parameter lists 38

Inline functions, the const keyword and the #define preprocessor directive 39

Call-by-value and call-by-reference 40

Using constant reference parameters in a call-by-reference 41

References and reference parameters. Returning local variables 42

Default arguments 43

Unary scope resolution operator 44

Function overloading 45

Function templates 46

Pointers, strings and arrays 48

Arrays 51

Multidimensional or Multiple-Subscripted Arrays 53

Arrays as parameters (passing arrays to functions) 55

Arrays of pointers 56

Function pointers 56

Function pointers applied in menu driven systems 57

Character sequences 58

 

/*

Plan

      Update the plan

      Improve the reference list below

Update the precedence and associativity table (use the final table in

            Deitel and Deitel or other reference)

      Study the material by writing or copying routines

      Add headings and table of contents

 

      Consider, elaborate, minimize and modify the following order of study:

 

            Memory, types of memory, bits and bytes

            The ALU

                  16, 32, 64bit processors…

            I / O

            Data and data types

                  Identifiers and variables

                  Character, short, integer, long integer, float, double…

                        Boolean

                  Pointers, strings and arrays

            Identifiers; variables and literals

            Operators

                  Assignment…

            Expressions

            Functions

            Statements and comments; single and multiple line comments

                  lvalues and rvalues

            Programs

                  Console, batch, time-sharing, event-driven

                  Operating system, GUI

 

 

References

I have been using Deitel and Deitel’s ‘C++ How to to Program,’ second edition. At this point, 12/30/2006, I can tell that Deitel and Deitel is not best suited to my needs. I need something more systematic and precise with formal rather than informal explanations (perhaps the informal explanation helps a beginner feel comfortable and thus Deitel and Deitel or similar reference would be a useful supplement)

 

Some resources:

 

C++ Language Tutorial

Complete tutorial from cplusplus.com that covers from basics up to object oriented programming.

www.cplusplus.com/doc/tutorial

 

cplusplus.com - The C++ resources network

Information, Documentation, Reference, Sourcecodes and Forums about C++ programming language.

www.cplusplus.com/

 

C++ - Wikipedia, the free encyclopedia

The C++ programming language standard was ratified in 1998 as ISO/IEC ... In 1983, the name of the language was changed from C with Classes to C++. ...

en.wikipedia.org/wiki/C++

 

Visual C++ Developer Center

Product information, technical resources, samples and downloads, news and reviews.

msdn.microsoft.com/visualc/

 

Stroustrup: C++

Bjarne Stroustrup's information page about the programming language. Also contains links to other sites.

www.research.att.com/~bs/C++.html

Bjarne Stroustrup's Homepage

Developer of the C++ programming language.

www.research.att.com/~bs/homepage.html

 

C/C++ Reference

General C/C++. Pre-processor commands · Operator Precedence · Escape Sequences · ASCII Chart · Data Types · Keywords ...

www.cppreference.com/

 

GCC, the GNU Compiler Collection - GNU Project - Free Software ...

Developed by GNU project as free compiler for GNU system. Front ends: C, C++, Objective-C, Fortran, Java, Ada; libraries for libstdc++, and libgcj.

gcc.gnu.org/

 

Xerces C++ Parser

A validating XML parser written in a portable subset of C++ by the Apache project.

xml.apache.org/xerces-c/

 

C programming.com - Your Resource for C and C++ Programming

A Web site designed to help learning C or C++. Also provides C and C++ programming resources.

www.cprogramming.com/

 

*/

 

 

/*

Comments

multiple

line

comment

*/

 

 

// begin single line comment

 

 

/*

Includes

 

#include <iostream.h>

 

includes input-output stream functions e.g. cin, cout

int main() -- every C++ must have a main function

 

Why int? Because every function must be declared?

*/

/*

Variables and identifiers. Data Types

 

In this section, use has been made of Wikipedia and http://www.cplusplus.com/doc/tutorial/

 

A variable is a portion of memory to store a determined value

 

Variables are distinguished by their ‘identifiers’

 

Identifiers

 

A valid identifier is a sequence of one or more letters, digits or underscore characters that must begin with a letter or underscore (but not a digit)

 

Identifiers can begin with an underscore but this is usually reserved for compiler specific keywords or external identifiers

 

C++ is a case sensitive language

 

An identifier cannot be a C++ keyword. The standard reserved keywords are:

 

asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while

 

Additionally, alternative representations for some operators cannot be used as identifiers since they are reserved words under some circumstances

 

and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq

 

Individual compilers also have compiler specific keywords

 

Bytes

 

A byte is usually eight bits and is also called a ‘character.’ Sometimes (in what is now non-standard use) a byte may refer to four bits. The term ‘octet’ means eight bits and is preferable if ambiguity must be avoided

 

Words

 

In computing, “word” is a term for the natural unit of data used by a particular computer architecture; a word is a fixed-sized group of bits that are handled as a unit by the machine. Word size or word length is an important characteristic of a computer architecture

 

The size of a word is reflected in many aspects of a computer's structure and operation. The majority of the registers in the computer are usually word-sized. The typical numeric value manipulated by the computer is probably word sized. The amount of data transferred between the processing part of the computer and the memory system is most often a word. An address used to designate a location in memory often fits in a word

 

Modern computers usually have a word size of 16, 32, or 64 bits. Many other sizes have been used in the past, including 8, 12, 18, 24, 36, 39, 40, 48, and 60 bits; the slab is an example of an early word size. Some of the earliest computers were decimal rather than binary, typically having a word size of 10 or 12 decimal digits, and some early computers had no fixed word length at all

 

The most common microprocessors used in personal computers have the x86 architecture (for instance, the Intel Pentiums and AMD Athlons). The x86 family includes several generations of achitecture. In the Intel 8086, 80186, and 80286, the word size is 16 bits. In IA-32, the word size is 32 bits. In x86-64, the word size is 64 bits. Yet each implementation also implements the earlier instruction sets too. So Intel calls 16 bits a word in all of them; this usage of word is different from that above

 

The ‘slab’

 

A slab is the word in the NCR 315 computer architecture from NCR Corporation. It has 12 data bits and the parity bit. A slab may contain three digits (with at sign, comma, space, ampersand, point, and minus treated as digits) or two alphabetic characters. A slab may contain a decimal value from -99 to +999

 

A numeric value contains up to eight slabs. If the value is negative then the minus sign is the leftmost digit of this row. There are commands to transform digits into alphanumeric characters or inverse. All these commands use the accumulator which has a maximum length of eight slabs. To accelerate the processing the accumulator works with an effective length

 

The NCR 315 was the follow-on to the NCR 304

 

The fundamental data types

 

A byte can store a relatively small amount of data: one single character or a small integer (generally an integer between 0 and 255)

 

More complex data types are stored by grouping bytes

 

A byte is the smallest amount of memory managed in C++

 

Name and

Declaration

Description

Size*

Range*

char

 

here and

below, the default for

most

compilers

is signed

character or small integer

1byte

signed: -128 to 127
unsigned: 0 to 255

short int
(or short)

short integer

2bytes

signed: -32768 to 32767
unsigned: 0 to 65535

int

integer

4bytes

signed: -2147483648 to 2147483647
unsigned: 0 to 4294967295

long int
(or long)

long integer

4bytes

signed: -2147483648 to 2147483647
unsigned: 0 to 4294967295

bool

boolean value:

      true (any integer

      other than zero) or

      false (the integer 0)

1byte

true or false

float

floating point number.

4bytes

3.4e +/- 38 (7 digits)

double

double precision floating point number

8bytes

1.7e +/- 308 (15 digits)

long double

long double precision floating point number

8bytes

1.7e +/- 308 (15 digits)

wchar_t

wide character

2bytes

1 wide character

 

* The values depend on the architecture of the system. The values shown are those on most 32bit systems. For other systems, the general specification is that int has the natural size of (one word) suggested by the system architecture (one word) and each of the four integer types char, short, int and long be at least as large as the preceding type. Similarly,  each of the floating point types float, double and long double, must provide at least as much precision as the preceding type

 

Declaration of variables

 

All variables must be declared in C++

 

The following are equivalent

      signed int x;     // and

      int x;

 

      short int x;      // and

      short x;

 

      long int x; // and

      long x;

 

*/

 

*/

Functions

Begin and end character; escape character; return; cout and cin

// every function must end with "{"

      cout << "Welcome\n"; // \ is the escape character

     

      return 0; // indicates that the program ended successfully

}

//evey function must end with "}"

*/

 

 

/*

Escape sequence

 

Escape Sequence

Description

\n

New line

\t

Horizontal tab

\r

Carriage return without new line

\a

Alert. Sound system bell

\\

Used to print backslash

\"

Used to print double quote

*/

/*

Demonstrating routine, #include, arithmetic, operations, assignment, main, return 0, cout, cin, declarations, integer, double, do, loops, while

 

A routine to calculate the exponential function that demonstrates #include, arithmetic operations, assignment, main, return 0, cout, cin, declarations, integer and double types, do loops - if the condition is place at the head of the loop it is a while loop in C++ and, unlike other languages there is no ‘do while’

*/

 

#include<iostream.h>

 

int main()

{

      double error, x, term, sum;

      int I, N;

      do {

            cout << "enter x: ";

            cin >> x;

            cout << "enter error: ";

            cin >> error;

            I = 0;

            term = 1.0;

            sum = 0.0;

            do {

                  sum = sum + term;

                  I = I + 1;

                  term = term * x / I;

            } while (term > error);

            cout << "exp(x) = " << sum << endl;

            cout << "enter 0 to continue or 1 to stop ";

            cin >> N;

      } while (N < 1);

      return 0;

}

 

/*

A routine to illustrate while

*/

 

#include <iostream>

using namespace std;

 

/*

If new style headers are used, namespace std must also be used

Introducing do before while below does not work in C++

*/

int main()

{

      int i;

      i = 0;

      while ( i <= 10 ) {

            cout << i << endl;

            i = i + 1;

      }

      cout << endl;

      return 0;

}

/*

A routine demonstrating new-style header files and namespaces

*/

 

#include <iostream> // Most new-style header files do not end with h

 

using namespace std;

 

/*

Namespaces maintain unique names for different software components.

std is used by every header file in the C++ standard library to guarantee

that every feature is unique from other software components.

Programmers should not use namespace std to define new class libraries

*/

 

int main()

{

      int num1;

 

      cout << "Hello world!\n";

      std::cout << "Hello world!\n" << endl;

 

      cout << "Press any character key and enter to end." << endl;

      cin >> num1; // Prevents stand-alone use from exiting after execution

 

      return 0;

}

/*

The exponential routine revisited. This version also demonstrates function prototype, function definition, and the if else structure

 

Note also that there is a modification to compute the exponential for negative numbers which works only because exp- = 1 / exp and the nature of the error for the exponential function

*/

 

#include<iostream.h>

 

double absolute(double); // function prototype

 

int main()

{

      double error, x, term, sum;

      int I, N;

      do {

            cout << "enter x: ";

            cin >> x;

            cout << "enter error: ";

            cin >> error;

            I = 0;

            term = 1.0;

            sum = 0.0;

            do {

                  sum = sum + term;

                  I = I + 1;

                  term = term * absolute(x) / I;

            } while (term > error);

            if ( x < 0.0 )

                  sum = 1.0 / sum;

            cout << "exp(x) = " << sum << endl;

            cout << "enter 0 to continue or 1 to stop ";

            cin >> N;

      } while (N < 1);

      return 0;

}

 

// Function definition

double absolute(double y)

{

      double result;

      if ( y >= 0.0 )

            result = y;

      else

            result = - y;

      return result;

}

/*

Multiple statements within an if, nested if, tailors output format to result

 

A simple routine that uses multiple statements within an if and nested if and tailors output format to result. The routine also uses the relational operators == (is equal to) and != (is not equal to)

*/

 

#include <iostream.h>

 

int main()

{

      int num1, num2;

 

      cout << "Enter two integers on separate lines, and I will tell you\n"

             << "the relationships they satisfy:\n" << endl;

 

      cin >> num1 >> num2;

 

      if ( num1 == num2 )

 

            {cout << endl << "The following relationships exist between " <<                    num1 << " and itself " << endl << endl;

 

                  if ( num1 == num2)

                        cout << num1 << " is equal to itself " << endl;

 

                  if ( num1 <= num2)

                        cout << num1 << " is less than or equal to itself " <<                              endl;

 

                  if ( num1 >= num2)

                        cout << num1 << " is greater than or equal to itself "                              << endl;}

 

      cout << endl;

 

      if ( num1 != num2 )

 

            {cout << endl << "The following relationships exist between " <<                          num1 << " and " << num2 << endl << endl;

 

                  if ( num1 == num2)

                        cout << num1 << " is equal to " << num2 << endl;

 

                  if ( num1 != num2)

                        cout << num1 << " is not equal to " << num2 << endl;

 

                  if ( num1 < num2)

                        cout << num1 << " is less than " << num2 << endl;

 

                  if ( num1 <= num2)

                        cout << num1 << " is less than or equal to " << num2 <<                             endl;

 

                  if ( num1 > num2)

                        cout << num1 << " is greater than " << num2 << endl;

 

                  if ( num1 >= num2)

                        cout << num1 << " is greater than or equal to " << num2                             << endl;}

 

      cout << endl;

 

      return 0;

}

/*

Experimenting with increment and decrement operators

*/

#include <iostream>

using namespace std;

 

 

int main()

{

      int a, b, c, I, N;

 

      do {

            cout << "Enter a: "; cin >> a;

            cout << "Enter b: "; cin >> b;

            cout << "Enter c: "; cin >> c;

 

            cout << "Enter a number from 1 to 10: "; cin >> I; cout << endl;

 

            cout << "Initial values" << endl << "a = " << a << endl

                  << "b = " << b << endl << "c = " << c << endl << endl;

 

            if ( I == 1) {

                  cout << "Demonstrating b += ++a" << endl;

                  b += ++a;

            }

            else if ( I == 2 ) {

                  cout << "Demonstrating ++a" << endl;

                  ++a;

            }

            else if ( I == 3 ) {

                  cout << "Demonstrating ++a" << endl;

                  ++a;

            }

            else if ( I == 4 ) {

                  cout << "Demonstrating a = a - a" << endl;

                  a = a - a;

            }

            else if ( I == 5 ) {

                  cout << "Demonstrating a = b++ + ++c" << endl;

                  a = b++ + ++c;

            }

            else if ( I == 6 ) {

                  cout << "Demonstrating a *= a" << endl;

                  a *= a;

            }

            else if ( I == 7 ) {

                  cout << "Demonstrating a *= b + c" << endl;

                  a *= b + c;

            }

            else if ( I == 8 ) {

                  cout << "Demonstrating a += ++a + ++b + c++" << endl;

                  a += ++a + ++b + c++;

            }

            else if ( I == 9 ) {

                  cout << "Demonstrating a %= a" << endl;

                  a %= a;

            }

            else if ( I == 10 ) {

                  cout << "Demonstrating a /= a" << endl;

                  if ( a == 0 ) {

                        cout << "Divide by zero. Operation not undertaken. " << endl

                              << "No changes in values of a, b, or c" << endl << endl;

                  }

                  else {

                        a /= a;

                  }

            }

            else

                  cout << "No operation chosen. No changes in the values of a, b, or c" << endl;

 

            cout << "Final values" << endl << "a = " << a << endl

                  << "b = " << b << endl << "c = " << c << endl << endl;

            cout << "Enter 0 to continue, another number to stop: "; cin >> N;

      } while ( N == 0 );

     

      return 0;

}

/*

Use of for repetition structure: calculating compound interest

 

Notes

Using the for structure

 

  The general format for the for is:

 

        for (expression1; expression2; expression3)

            statement

 

  where

      the two semi-colons are always required

     

      expression1 initializes the loop control variable

 

      expression2 is the loop continuation condition; if initially false

      the body of the for is not performed and control goes to the statement

      following the for

 

      expression3 increments (changes) the control variable

 

      the expressions may be comma separated lists of operations that

        evaluate from left to right (the comma has lowest precedence of

        all operators in C++; the value and type of a comma separated

        list is the value and type of the right-most expression of the list;

        comma separated expressions in C++ are used most commonly in for

        statements when several variables must be initialized and incremented

 

      the expressions are optional e.g. expression1 may be omitted if, if e.g.,

        the control variable is initialized elsewhere; if expression2 is omitted

        C++ assumes the continuation is true, creating an infinite loop;

        expression3 may omitted if, e.g., the increment is not needed or

        is calculated in the body of the for

 

      the statement can be a single line statement or a compound statement:

 

        {

            statements

        }

 

  In most cases, the structure has an equivalent while structure

 

        expression1;

        while ( expression2 ) {

            statement

            expression3;

        }

*/

 

// routine

#include <iostream>

#include <iomanip>

#include <cmath>

// alternate #include <math.h>

 

using namespace std;

 

int main()

{

      int years;

      double amount, principal, rate;

 

      cout << "Enter data:" << endl;

 

      cout << setw (35) << "Principal in dollars and cents: ";

      cin >> principal;

 

      cout <<  setw (35) << "Interest as a fraction: ";

      cin >> rate; cout;

 

      cout <<  setw (35) << "Years as a whole number: ";

      cin >> years; cout << endl;

 

      cout << "Output:" << endl;

 

      cout << setw (7 ) << "Year" << setw( 14 )

            << "Amount" << endl;

     

      for ( int year = 0; year <= years; year++ ) {

            amount = principal * pow ( 1.0 + rate, year );

            cout << setw ( 7 ) << year

                  << setiosflags( ios::fixed | ios::showpoint )

                  << setw( 14 ) << setprecision (2)

                  << amount << endl;

      }

 

      cout << endl;

 

      return 0;

}

/*

Assignments and expressions. Assignment and relational operators

 

The form of an assignment and an example of an assignment statement in C++ is:

 

      variable = expression

 

a = 10

 

An expression is formed by combining constants and variables according to rules of combination

 

In C++ an assignment statement itself has a value. The value of an assignment statement is the value that is placed in the left variable

 

It is easy to mistakenly enter ‘=’ where ‘==’ is intended. For example:

 

      if ( x == 10 )

            x = 5;

 

may mistakenly be written:

 

      if ( x = 10 )

            x = 5;

 

There are two cases

      x is initially 10. The value of x == 10 is true; therefore in the first if

      the assignment is executed and x is set to 5

 

      x is initially not 10. In the first if, there is no (re) assignment and

      the value of x is unchanged

 

In the second if statement, the effect of the assignment is, regardless of the initial value, to first assign the value to 10. The assignment statement itself has the value 10 which is taken in C++ to be true (any value other than 0 is ‘true’ while 0 is ‘false’) and therefore x is assigned to 5

 

Arithmentic assignment and increment and decrement operators

 

Since assignment statements have a value a variable can be set equal to an assignment statement. For example

 

      b = (a = 7)

 

first sets a to 7 and then sets b to the value of the assignment which is also 7. Therefore, given the associativity of the assignment operator, the foregoing assignment(s) can be rewritten

 

      b = a = 7

 

Similarly, the following sets all variables to 0:

 

      d = c = b = a = 0

 

Expressions of the form

 

      variable = variable operator expression

 

Can be rewritten

 

      variable operator= expression

 

As examples

 

      c += 3 is equivalent to c = c + 3

      c += a + b is equivalent to c = c + a + b

 

Similarly

 

      c -= 0 is equivalent to c = c – 0

      c *= a + b is equivalent to c = c * ( a + b )

      c /= 5 is equivalent to c = c / 5

      c %= 9 is equivalent to c = c % 9

 

The increment and decrement operators are defined as follows

 

Operator

Name

Sample expression

Explanation

++

preincrement

++variable

Increment the variable by 1, then use the its in the expression in which it resides

++

postincrement

variable++

Use the current value of the variable in the expression in which it resides, then increment it by 1

--

predecrement

--variable

Decrement the variable by 1, then use the its in the expression in which it resides

--

postdecrement

variable--

Use the current value of the variable in the expression in which it resides, then decrement it by 1

 

Examples. In the following a is 4 and b is 5 before the statement is executed:

 

      a++

 

and

 

      ++a

 

both result in the value 5 being assigned to a. In,

 

      b = 10 * (a++)

 

and

 

      b = 10 * (++a)

 

the results are different. In both cases, the the value of a is reassigned as 5. However, in the first, the value assigned to b is 50, whereas in the second it is 40. Since both forms of ++ (pre and post) have precedence over *, the parentheses are unnecessary

 

*/

/*

A routine that demonstrates counter controlled repetition

*/

 

// Class average with counter-controlled repetition

 

#include <iostream>

using namespace std;

 

int main()

{

      int total,

            gradeCounter, // # of grades entered

            grade,

            average;

 

      //initialize

      total = 0;

      gradeCounter = 0;

 

      //process

      while ( gradeCounter < 10 ) {

            cout << "Enter grade: ";

            cin >> grade;

            total = total + grade;

            gradeCounter = gradeCounter + 1;

      }

 

      //output and end

      average = total/10;

      cout << "Class average is " << average << endl;

 

      return 0;

}

/*

A routine that demonstrates sentinel controlled repetition and use of iomanip and static_cast

*/

 

/*

Class average with sentinel controlled repetition

 

Demonstrates use of <iomanip> or <iomanip.h> for parametrized stream manipulators such as setprecision and setiosflags

 

Note that ios::fixed causes a floating-point value to be output in fixed-format (not scientific) notation and ios::showpoint results in the decimal point being

shown even trailing decimal zeros. The bitwise inclusive or operator (|) is used

to separate multiple options in a setiosflags call

 

The cast operator static_cast is used to create a temporary floating-point copy

of the operand 'total' in static_cast < float > (total). This is an explicit

conversion. The C++ compiler does not evaluate expressions which contains

different data types. Therefore in the expression

 

  static_cast< float >(total) / gradeCounter,

 

the int variable is promoted to float; this is an example of a promotion or

implicit conversion operation in which all variables in an expression are

promoted to its highest type (see promotion hierarchy below

*/

 

#include <iostream>

#include <iomanip>

using namespace std;

 

int main()

{

      int total,

            gradeCounter, // number of grades entered

            grade;

      float average;

 

      //initialize

      total = 0; gradeCounter = 0;

 

      //process

      cout << "Enter grade or enter -1 to end: ";

      cin >> grade;

 

      while ( grade != -1 ) {

            total = total + grade;

            gradeCounter = gradeCounter + 1;

            cout << "Enter grade or enter -1 to end: ";

            cin >> grade;

      }

 

      //output and return

      if ( gradeCounter !=0 ) {

            average = static_cast< float >(total) / gradeCounter;

            cout<< endl << "Number of grades entered is " << gradeCounter << endl;

            cout << "Class average is " << setprecision (2)

                  << setiosflags( ios::fixed | ios::showpoint )

                  << average << endl << endl;

      }

      else

            cout << "No grades were entered" << endl << endl;

 

      return 0;

}

/*

Use of switch multiple selection structure

*/

#include <iostream>

using namespace std;

 

int main()

{

      int grade,                    // one grade

            aCount = 0,             // number of A's

            bCount = 0,

            cCount = 0,

            dCount = 0,

            fCount = 0,

            nStudents = 0;

 

      float cum_score = 0.0;        // used to calculate the average grade

     

      cout << "Enter the letter grades." << endl

            << "Enter the EOF character to end input." << endl;

 

      while ( ( grade = cin.get() ) != EOF) {

 

            switch ( grade ) {

 

                  case 'A':

                  case 'a':

                        ++aCount;

                        cum_score = cum_score + 4;

                        nStudents = nStudents + 1;

                        break;

 

                  case 'B':

                  case 'b':

                        ++bCount;

                        cum_score = cum_score + 3;

                        nStudents = nStudents + 1;

                        break;

 

                  case 'C':

                  case 'c':

                        ++cCount;

                        cum_score = cum_score + 2;

                        nStudents = nStudents + 1;

                        break;

 

                  case 'D':

                  case 'd':

                        ++dCount;

                        cum_score = cum_score + 1;

                        nStudents = nStudents + 1;

                        break;

 

                  case 'F':

                  case 'f':

                        ++fCount;

                        nStudents = nStudents + 1;

                        break;

 

                  case '\n': // ignore newlines,

                  case '\t': // tabs,

                  case ' ':  // and spaces in input

                        break;

 

                  default:

                        cout << "Invalid letter. Reenter grade." << endl;

                        break; // optional

            }

      }

 

      cout << "\n\nResults."

            << "\n\n Totals for each letter grade:"

            << "\n  A: " << aCount

            << "\n  B: " << bCount

            << "\n  C: " << cCount

            << "\n  D: " << dCount

            << "\n  F: " << fCount

            << "\n\n The total number of grades is: " << nStudents;

 

      if ( nStudents > 0 ){

            cout << "\n The average grade on a 4.0 scale is: "

                  << cum_score / nStudents << endl << endl;

      }

 

      return 0;

}

/*

Promotion hierarchy for built-in data types

 

Data types

 

long double

 

double

 

float

 

unsigned long int

(synonymous with unsigned long)

long int

(synonymous with long)

unsigned int

(synonymous with unsigned)

int

 

unsigned short int

(synonymous with unsigned short)

short int

(synonymous with short)

unsigned char

 

short

 

char

 

 

*/

 

/*

Header files

 

Standard library leader file

Explanation

Old-style header files

<assert.h>

Contains macros and information for adding diagnostics that aid pro­gram debugging. New version: <cassert>

<ctype.b>

Contains function prototypes for functions that test characters for cer­tain properties, and function prototypes for functions that can be used to convert lowercase letters to uppercase letters and vice versa. New version: <cctype>

<£loat.h>

Contains the floating-point size limits of the system. New version: <cfloat>

<limits.h>

Contains the integral size limits of the system. New version: <climits>

<math.h>

Contains function prototypes for math library functions. New version: <cmath>

<stdio.h>

Contains function prototypes for the standard input/output library functions and information used by them. New version: <cstdio>

<stdlib.h>

Contains function prototypes for conversions of numbers to text, text to numbers, memory allocation, random numbers, and various other utility functions. New version: <cstdlib

<string.h>

Contains function prototypes for C-style string processing functions. New version: <cstring>

<time.h>

Contains function prototypes and types for manipulating the time and date. New version: <ctime>

<iostream.h>

Contains function prototypes for the standard input and standard output functions. New version: <iostream>

<iomanip.h>

Contains function prototypes for the stream manipulators that enable formatting of streams of data. New version: <iomanip>

<fstream.h>

Contains function prototypes for functions that perform input from files on disk and output to files on disk. New version: < fstream >

New-style header files

<utility>

Contains classes and functions that are used by many standard library header files

<vector>, <list>, <deque>, <queue>, <stack>, <map>, <set>, <bitset>

The header files contain classes that implement the standard library containers. Containers are use to store data during a program’s execu­tion… part of the “Standard Template Library”

<£unctional>

Contains classes and functions used by algorithms of the standard library

<memory>

Contains classes and functions used by the standard library to allocate memory to the standard library containers

<iterator>

Contains classes for manipulating data in the standard library containers

<algorithm>

Contains functions for manipulating data in the standard library containers

<exception>, <stdexcept>

These header files contain classes that are used for exception handling

<string>

Contains the definition of class string from the standard library

<sstream>

Contains function prototypes for functions that perform input from strings in memory and output to strings in memory

<locale>

Contains classes and functions normally used by stream processing to process data in the natural form for different languages (e.g., monetary formats, sorting strings, character presentation, etc.)

<limits>

Contains a class for defining the numerical data type limits on each computer platform

<typeinfo>

Contains classes for run-time type identification (determining data types at execution time)

*/

/*

C++ Keywords

C and C++ keywords

auto

break

case

char

const

continue

default

do

double

else

enum

extern

float

for

goto

if

int

long

register

return

short

signed

sizeof

static

struct

switch

typedef

union

unsigned

void

volatile

while

 

 

 

C++ only keywords

asm

bool

catch

class

const_cast

delete

dynamic_cast

explicit

false

friend

inline

mutable

namespace

new

operator

private

protected

public

reinterpret_cast

 

static_cast

template

this

throw

true

try

typeid

typename

using

virtual

wchar_t

*/

/*

Precedence and Associativity of C++ operators

Operator

Type

Associativity

::

binary scope resolution

left to right

::

unary scope resolution

 

()

parentheses

left to right

[]

array subscript

 

.

member selection via object

 

->

member selection via pointer

 

++

unary postincrement

 

--

unary postdecrement

 

typeid

run-time type information

 

dynamic_cast< type >

run-time type-checked cast

 

static_cast< type >

compile-time type-checked cast

 

reinterpret_cast< type >

cast for non-standard conversions

 

const_cast< type >

cast away const-ness

 

++

unary preincrement

right to left

--

unary predecrement

 

+

unary plus

 

-

unary minus

 

1

unary logical negation

 

~

unary bitwise complement

 

( type )

C-style unary cast

 

sizeof

determine size in bytes

 

&

address

 

*

dereference

 

new

dynamic memory allocation

 

new [ ]

dynamic array allocation

 

delete

dynamic memory deallocation

 

delete [ ]

dynamic array deallocation

 

*

pointer to member via object

left to right

->*

pointer to member via pointer

 

*

multiplication

left to right

/

division

 

%

modulus

 

+

addition

left to right

-

subtraction

 

<<

bitwise left shift

left to right

>>

bitwise right shift

 

<

relational less than

left to right

<=

relational less than or equal to

 

>

relational greater than

 

>=

relational greater than or equal to

 

==

relational is equal to

left to right

!=

relational is not equal to

 

&

bitwise AND

left to right

^

bitwise exclusive OR

left to right

|

bitwise inclusive OR

left to right

&&

logical AND

left to right

||

logical OR

left to right

?:

ternary conditional

right to left

=

assignment

right to left

+=

addition assignment

 

-=

subtraction assignment

 

*=

multiplication assignment

 

/=

division assignment

 

%=

modulus assignment

 

&=

bitwise AND assignment

 

^=

bitwise exclusive OR assignment

 

|=

bitwise inclusive OR assignment

 

<<=

bitwise left shift assignment

 

>>=

bitwise right shift with sign

 

,

comma

left to right

Note that C++ specifies the order of evaluation of operands only of four operators: &&, ||, the comma(,) operator and the ternary operator ?:

*/

/*

Structured programming

 

Program units are small and execute a small number of tasks

 

Except the interface, the variables and methods of each module are hidden from other modules

 

The units of structured programs are the sequence, the selection structure, and the repetition structure. While C++ has seven structures: the sequence, the if, the if else, the case structure, the for, the while and the do, these may be reduced to three: the sequence, the if, and the while

 

The simplest program is the input-action-output. Programs may be built by (1) replacing any action by two actions in sequence, (2) any action by any control structure, and (3) repeating 1 and 2 in any order for any finite number of times

 

Structured programming can implement any algorithm

 

Structured programming is written to make the structure transparent e.g. indentation of blocks, declaration of all variables…

 

*/

/*

Demonstrating cstdlib, ctime, rand, srand, enum

*/

 

// A game of craps

// Demonstrating cstdlib, ctime, rand, srand, enum

#include <iostream>

#include <cstdlib>

#include <ctime>

 

using namespace std;

 

int rollDice (void); // fn prototype

 

int main()

{

      enum Status { CONTINUE, WON, LOST };

      int sum, myPoint;

      Status gameStatus;

 

      srand( time( NULL ) );

      sum = rollDice();                                           // first roll

 

      switch ( sum ) {

            case 7:

            case 11:

                  gameStatus = WON;

                  break;

            case 2:

            case 3:

            case 12:

                  gameStatus = LOST;

                  break;

            default:                                                    // remember point

                  gameStatus = CONTINUE;

                  myPoint = sum;

                  cout << "Point is " << myPoint << endl;

                  break;                                                      // optional

      }

 

      while ( gameStatus == CONTINUE ) {                    // keep rolling

            sum = rollDice();

 

            if ( sum == myPoint )                                 // win by making point

                  gameStatus = WON;

            else if ( sum == 7 )                                  // lose by making 7

                  gameStatus = LOST;

      }

 

      if ( gameStatus == WON )

            cout << "Player wins" << endl;

      else

            cout << "Player loses" << endl;

 

      return 0;

}

 

int rollDice ( void )

{

      int die1, die2, workSum;

 

      die1 = 1 + rand() % 6;

      die2 = 1 + rand() % 6;

 

      workSum = die1 + die2;

 

      cout << "Player rolled " << die1 << " + " << die2

            << " = " << workSum << endl;

 

      return workSum;

}

/*

Storage classes and scope rules

 

In C++ identifiers have been used for variable names and names of user defined functions. Attributes of identifiers include name, type, size and value

 

Each identifier in a program has further attributes that include storage class, scope and linkage

 

Storage class determines the period during which the identifier exists in memory. Some exist for the entire execution of the program, some are repeatedly created and destroyed, and others exist only briefly

 

Scope is where the identifier can be referenced in a program. Some identifiers can be referenced throughout a program, while others can be referenced from only limited portions of a program

 

An identifier’s linkage determines for a multiple-source-file program whether an identifier is known only in the current source file or in any source file with proper declarations

 

C++ provides four storage class identifiers: auto, register, extern, and static that help determine the storage class, scope and linkage of identifiers

 

Storage class specifiers are automatic or static

 

The auto and register keywords declare variables of automatic storage class. Such variables exist for the duration that the block in which they are declared is active

 

Only variables can be of automatic storage class. The following declaration declares the floating variables x, y to be of automatic storage class

 

      auto float x, y;

 

Local variables are of automatic storage class (simply, ‘automatic variables’) by default, so the keyword auto is rarely used

 

An example of a register declaration is

 

      register int counter = 1;

 

The declaration suggests to the compiler be placed in one of the computer’s high speed registers; whether the compiler actually does this will depend on the availability of registers. The purpose of the register class is to save time on intensively used variables such as counters and totals. Regardless of whether counter is placed in a register in the above example, the declaration results in counter being an integer variable initialized to 1

 

The register keyword can be used only with local variables and function parameters

 

Variables and functions may be of static storage class (static identifiers.) Such variables exist from the point at which program execution begins. For variables, storage is allocated and initialized once when program execution begins. For functions, the name of the function exists when the program begins execution. However, even though variables and functionnames exist throughout execution of the program, this does not mean that they can be referenced throughout the program – storage class and scope are separate issues

 

There are two types of identifiers with static storage class: external identifiers (such as global variables and function names) that default to storage class specifier extern and local variables declared with the storage class specifier static e.g.

 

      static int count = 1;

 

Global variables are created by placing variable declarations outside any function definition and can be referenced by any function that follows their declarations or definitions in the file

 

Local variables declared with keyword static are known only in the function in which they are defined but unlike automatic variables they retain their values when the function is exited. All numeric variables of static storage class are initialized to zero unless explicitly initialized in the program

 

Scope rules

 

The four scopes that an identifier can have are function scope, file scope, block scope, and function-prototype scope. A fifth scope is class scope

 

An identifier declared outside any function has file scope. An identifier with file scope is known in all functions in the file from the point at which the identifier is declared to the end of the file. Some identifiers with file scope are global variables, function definitions, and function prototypes placed outside a function

 

Labels are the only identifiers with function scope (a label is an identifier followed by a colon e.g. start: and used, e.g., in switch structures as case labels and in goto statements.) Labels can be used anywhere in the function in which they appear but cannot be referenced from outside

 

Identifiers declared inside a block have block scope which begins at the identifier’s declaration and ends at the terminating right brace (}) of the block. Local variables declared at the beginning of a function have block scope as do function parameters, which are also local variables of the function. Any block may contain variable declarations. When nested blocks have identifiers of the same name, the ‘outer identifier’ is hidden until the inner block terminates and when executing in the inner block, the inner block sees the value of its own not local identifier and not the value of the identically named identifier in the enclosing block

 

The only identifiers with function-prototype scope are the optional identifiers used in the parameter list of a function prototype that requires only variable types; identifiers with function-prototype scope are ignored by the compiler and can be reused elsewhere in the program without ambiguity

 

*/

 

/*

Recursion – Fibonacci series

*/

 

// Recursive Fibonacci function

#include <iostream>

using namespace std;

 

long fibonacci( long );

 

int main()

{

      long sentinel = 1, result, number;

 

      while ( sentinel != -1 ) {

            cout << "Enter an integer whose Fibonacci number ” <<

<< “is to be calculated: ";

            cin >> number;

            result = fibonacci ( number );

            cout << "Fibonacci(" << number << ") = " << result << endl << endl;

            cout<< "Enter -1 to stop, any other number to continue: ";

            cin >> sentinel;

      }

 

      return 0;

}

 

// Recursive definition of function fibonacci

long fibonacci( long n )

{

      if ( n == 0 || n == 1 )       // base case

            return n;

      else

            return fibonacci ( n- 1 ) + fibonacci ( n - 2 );

}

/*

Functions with empty parameter lists

*/

// Functions with emtpty paramenter lists i.e. that take no arguments

#include <iostream>

using namespace std;

 

void functionA ( void );

void functionB ();

 

int main()

{

      functionA();

      functionB();

 

      return 0;

}

 

void functionA()

{

      cout << "Demonstrating functions with empty parameter lists" << endl << endl;

      cout << "functionA( void ) takes no arguments" << endl << endl;

}

 

void functionB()

{

      cout << "functionB() also takes no arguments "

            << "and shows an alternate way to declare a function "

            << "with an empty parameter list" << endl << endl;

}

/*

Inline functions, the const keyword and the #define preprocessor directive

*/

// Using inline functions to calculate the volume of a sphere

// An inline function specifies that the compiler may replace each occurrence

// of the function in the program by the function code instead of incurring

// the overhead of a function call. This makes the code longer

// The compiler generally places the code inline for only the simplest functions

 

#include <iostream>

#define PI 3.141592654

// the #define directive here results in 'PI' being replaced by the replacement

// text (3.141592654) in all occurrences

using namespace std;

 

inline float sphere ( const float r ) { return (4 * PI / 3) * r * r * r; }

// The const declaration informs the compiler that the function does not

// modify the variable

 

int main()

{

      float radius;

 

      cout << "A routine to calculate the volume of a spere " << endl << endl

            << "Enter the radius of the sphere: ";

      cin >> radius;

 

      cout << "The volume of a cube with side " << radius << " is: "

            << sphere ( radius ) << endl;

 

      return 0;

}

/*

Call-by-value and call-by-reference

In C++ call-by-value is the default

      (in Visual Basic, call-by-reference is default)

 

In a call-by-value, a copy the arguments value is made and passed to the called function. Thus, memory and timeoverheads are incurred but the value of the called argument is not changed even if the called function changes the value of the copy

 

In a call-by-reference, if the value of the argument is changed in the called function, the changed value is returned to the calling function (this may lead to logic errors)

 

In C++ there are two ways to to call-by-reference. One is by using reference parameters and the second is by use of pointers (which is safer since it clearly indicates call-by-reference)

 

A reference parameter is declared as follows with an 'ampersand'

 

      int &count

*/

 

// Comparing call-by-value and call-by-reference

 

#include <iostream>

using namespace std;

 

int squareByVal ( int );

void squareByRef ( int & );

// The foregoing shows the manner of declaring the call-by-reference

 

int main()

{

      int x = 2, z = 4;

 

      cout << "x = " << x << " before squareByVal\n"

            << "Value returned by squareByVal: "

            << squareByVal ( x ) << endl

            << "x = " << x << " after squareByVal\n" << endl;

 

      cout << "z = " << z << " before squareByRef" << endl;

      squareByRef ( z );

      cout << "z = " << z << " after squareByRef" << endl;

 

      return 0;

}

 

int squareByVal( int a )

{

      return a *= a;    // caller’s argument is not modified

}

 

void squareByRef ( int &cRef )

{

      cRef *= cRef;     // caller’s argument is modified

}

 

/*

Using constant reference parameters in a call-by-reference

 

Using a constant reference parameter to simulate the appearance and security of a call-by-value and avoid the overhead of copying and passing a large object

*/

 

// References must be initialized

#include <iostream>

using namespace std;

 

int main()

{

      int x = 3,

            &y = x;     // y is now an alias for x

 

      cout << "x = " << x << endl << "y = " << y << endl;

      y = 7;

      cout << "x = " << x << endl << "y = " << y << endl;

 

      return 0;

}

 

/*

References and reference parameters. Returning local variables

*/

// Returning local variables

#include <iostream>

using namespace std;

 

void test1 ( int, int, int & ); // Function prototype

void test2 ( int, int, int ); // Function prototype

 

int main()

{

      int x = 1, y = 1, z;

 

      z=1;

      test1 ( x, y, z );

      cout << "Using test1 which calls-by-reference, z = " << z << endl;

     

      z=1;

      test2 ( x, y, z );

      cout << "Using test2 which calls-by-value, z = " << z << endl;

     

      return 0;

}

 

void test1 ( int a, int b, int &c)

{

      c = a + b;

      cout << "Using test1 which calls-by-reference, local variable c = " << c << endl;

}

 

void test2 ( int a, int b, int c)

{

      c = a + b;

      cout << "Using test2 which calls-by-value, local variable c = " << c << endl;

}

/*

Default arguments

 

It is useful to specify default arguments when a function call

commonly specifies a particular value of an argument.

Default values should be specified in the first occurrence of

the function - typically in the prototype

 

Default arguments must be the rightmost (trailing) arguments in a

function's parameter list

 

When calling a function with two or more default arguments, if an

omitted argument is not the rightmost argument in the argument

list, all arguments to the right of that argument must also be

omitted

 

Default arguments can be constants, global variables, or function

calls

 

Default arguments can also be used with inline functions

*/

#include <iostream>

using namespace std;

 

int vol ( int length = 1, int width = 1, int height = 1 );

/* In the prototype, variable names are provided for clarity

The following for is also valid

 

      int vol ( int = 1, int = 1, int = 1 );

 

The default values could be specified in the function itself

by placing the function before its first call i.e. by replacing

the prototype by the definition:

 

      int vol( int length = 1, int width = 1, int height = 1 )

      {

            return length * width * height;

      }

*/

 

int main()

{

      cout << "Default volume = vol() = " << vol()

            << "\n\nIf l = 10, w = 1, h = 1, volume = vol ( 10 )       = "

                  << vol( 10 )

            << "\n\nIf l = 10, w = 6, h = 1, volume = vol ( 10, 6 )    = "

                  << vol( 10, 6 )

            << "\n\nIf l = 10, w = 6, h = 4, volume = vol ( 10, 6, 4 ) = "

                  << vol( 10, 6, 4 )

            << endl << endl;

      return 0;

}

 

int vol( int length, int width, int height )

{

      return length * width * height;

}

/*

Unary scope resolution operator

 

Used to reference a global variable when a local variable of

the same name is in scope. Is not necessary if the global

variable name is not the name of a local varaible in scope

 

Cannot be used to reference a local variable outside its

scope

*/

 

#include <iostream>

#include <iomanip>

using namespace std;

 

const double PI = 3.14159265358979;

 

int main()

{

      const float PI = static_cast< float > ( ::PI );

 

      cout << setprecision ( 20 )

            << "\n  Local float value of PI = " << PI

            << "\nGlobal double value of PI = " << ::PI << endl << endl;

     

      return 0;

}

 

 

/* Output

  Local float value of PI = 3.1415927410125732

Global double value of PI = 3.14159265358979

*/

/*

Function overloading

 

Enables several functions of the same name to be defined as long as

these functions have different sets of parameters (at least far as

their types are concerned

*/

 

 

#include <iostream>

#include <iomanip>

using namespace std;

 

int square ( int x ) { return x * x; }

 

double square ( double x ) { return x * x; }

/* May be better to write

double square ( double y ) { return y * y; }

*/

 

int main()

{

      cout << "The type integer square of the integer 7 = square ( 7 ) = " << square ( 7 )

            << "\nThe type double square of double 7.5 = " << square ( 7.5 )

            << endl;

     

      return 0;

}

/*

Output:

The type integer square of the integer 7 = square ( 7 ) = 49

The type double square of double 7.5 = 56.25

 

Output if the double function definition is eliminated:

The type integer square of the integer 7 = square ( 7 ) = 49

The type double square of double 7.5 = 49

*/

/*

Function templates

 

If program logic and operations are identical for each data type

of an overloaded function, overloading may be performed compactly

and conveniently by using function templates. A single template

definition is written and, for each argument type in calls

to the function, C++ automatically generates a separate function

to handle the type appropriately. Thus, defining a single

template defines a family of functions

 

All function template definitions begin with the template

keyword followed by a list of formal type parameters to the

template enclosed by angle brackets < and >. The formal

type parameters are either built in or user defined types

to specify the types of arguments and type of return and to

declare variables in the body of the function. The function

definition follows as for any function

*/

#include <iostream>

using namespace std;

 

template < class T >

T maximum ( T value1, T value2, T value3 )

{

      T max = value1;

 

      if ( value2 > max )

            max = value2;

 

      if ( value3 > max )

            max = value3;

 

      return max;

}

 

int main()

{

      int int1, int2, int3;

 

      cout << "Input three integer values: ";

      cin >> int1 >> int2 >> int3;

      cout << "The maximum integer value is: "

            << maximum ( int1, int2, int3 )           // int version

            << endl << endl;

     

      double double1, double2, double3;

 

      cout << "Input three double values: ";

      cin >> double1 >> double2 >> double3;

      cout << "The maximum double value is: "

            << maximum ( double1, double2, double3 )        // double version

            << endl << endl;

     

      char char1, char2, char3;

 

      cout << "Input three chareger values: ";

      cin >> char1 >> char2 >> char3;

      cout << "The maximum char value is: "

            << maximum ( char1, char2, char3 )        // char version

            << endl << endl;

     

      return 0;

}

/*

Pointers, strings and arrays

 

A pointer is a variable that contains the memory address of another variable i.e. a pointer ‘points to another variable’

 

The reference operator ‘&’ may be read ‘address of’ and used in a statement as follows:

 

      xPtr = &x;        // results in the address of x being assigned to xPtr

 

 

Declaring pointers. Since it is a variable, a pointer must be declared:

 

      int x, *xPtr;     // Declares x to be an integer and xPtr to be a pointer

                        // to an integer

                        // The declaration probable states the programmer’s

                        // intent that xPtr will point to x. This but may

                        // be helpful to keep track but is neither

                        // necessary nor a result of the declaration

 

                        // The use of the suffix ‘Ptr’ in the name of a pointer

                        // is not necessary but may be helpful in making code

                        // easier to manage and read

 

In declarations each pointer must be explicitly identified

 

      int x, y,         // Declares x, y and yPtr to be integers and only
          *xPtr, yPtr   // xPtr to be a pointer (to an integer)

 

      int x, y,         // Declares x and y be integers and only
          *xPtr, yPtr   // and xPtr and yPtr to be pointers

 

Pointer types. Pointers can point to a variable of any data type and must be so declared:

 

      int * number;

      char * character;

      float * greatnumber;

      double * verygreatnumber;

 

The blank space after * is optional e.g. the following are equivalent:

 

      int * number;

      int *number;

 

 

Pointers can point to pointers:

 

      char a;

      char *b;

      char **c;   // c is a pointer to a pointer of type char

 

      b = &a;     // address of a is assigned to b; b now contains address of a

      c = &b;     // address of b is assigned to c

 

? I don’t know whether there is any limit to ‘depth of pointer assignment’ e.g. is the following valid?

 

      int ********************************************************c;

 

The following program successfully ran on Microsoft Visual C++6.0:

*/

 

#include <iostream>

using namespace std;

 

int main()

{

      int x, y,

            *xPtr = &x, *yPtr = &y,

            **zPtr = &xPtr,

            ***wPtr = &zPtr,

            ****aPtr = &wPtr,

            *****bPtr = &aPtr,

            ******cPtr = &bPtr,

            *******dPtr = &cPtr,

            ********ePtr = &dPtr,

            *********fPtr = &ePtr,

            **********gPtr = &fPtr,

            ***********hPtr = &gPtr,

            ************iPtr = &hPtr,

            *************jPtr = &iPtr;

 

      cout << "xPtr = &x    = " << xPtr << endl

            << "zPtr = &xPtr = " << zPtr << endl

            << "wPtr = &zPtr = " << wPtr << endl

            << "aPtr = &wPtr = " << aPtr << endl

            << "bPtr = &aPtr = " << bPtr << endl

            << "cPtr = &bPtr = " << cPtr << endl

            << "dPtr = &cPtr = " << dPtr << endl

            << "ePtr = &dPtr = " << ePtr << endl

            << "fPtr = &ePtr = " << fPtr << endl

            << "gPtr = &fPtr = " << gPtr << endl

            << "hPtr = &gPtr = " << hPtr << endl

            << "iPtr = &hPtr = " << iPtr << endl

            << "jPtr = &iPtr = " << jPtr << endl;

 

 

      return 0;

}

 

With the following output:

 

xPtr = &x    = 0012FF7C

zPtr = &xPtr = 0012FF74

wPtr = &zPtr = 0012FF6C

aPtr = &wPtr = 0012FF68

bPtr = &aPtr = 0012FF64

cPtr = &bPtr = 0012FF60

dPtr = &cPtr = 0012FF5C

ePtr = &dPtr = 0012FF58

fPtr = &ePtr = 0012FF54

gPtr = &fPtr = 0012FF50

hPtr = &gPtr = 0012FF4C

iPtr = &hPtr = 0012FF48

jPtr = &iPtr = 0012FF44

 

/*

 

Initializing pointers

 

Pointers should be initialized to prevent pointing to unknown or uninitialized memory locations

 

Pointers may be initialized when declared or in assignment statements:

 

      int y = 5;

      int *yPtr = &y;

 

or, equivalently,

 

      int y = 5;

      int *yPtr;

      yPtr = &y;

 

Null and void pointers

 

A pointer may be initialized to an address 0 (or NULL.) The following groups of statements are equivalent:

 

      int *p;

      p = 0;

 

      int *p = 0;

 

      int *p;

      p = NULL;

 

      int *p = NULL;

 

NULL is a symbolic constant defined in several standard library header files but in C++ 0 is preferred. The null pointer does not point to anything. When a null pointer is assigned, it is converted to a pointer of the appropriate type. 0 is the only integer value that can be directly assigned to a pointer without first castint the integer to a pointer type

 

Void pointers

 

In C++, void represents the absence of type, so void pointers are pointers that point to a value that has no type (and thus also an undetermined length and undetermined dereference properties)

 

This allows void pointers to point to any data type, from an integer value or a float to a string of characters

 

A void pointer cannot be directly dereferenced (since we have no type to dereference to.) Therefore, a void pointer must be changed to a definite pointer type (by type-casting) before dereferencing it

 

One of the uses of void pointers is to pass generic parameters to a function

 

The dereference operator * which may be read ‘value in the address of’ or ‘value pointed by’

 

Given

 

      int x = 7, y;

      int *xPtr = &x;

      y = *xPtr;        // results in being assigned the value 7

 

Note that a derererenced pointer is also a valid lvalue for assignment. The following are equivalent

 

      int y, *yPtr = &y;

      y = 7;

 

      int y, *yPtr = &y;

      *yPtr = 7;

 

&y, however, is not a valid lvalue

 

Since C++ allows pointers to pointers & may operate on pointer and non-pointer variables. However, * operates only on pointers

 

Arrays

 

Arrays (and strings considered below) may be regarded as (‘are roughly’) constant pointers to the address of the first element (of the array or string)

 

An array is a set of consecutive memory locations and a constant pointer to the address of the first element

 

The following declares a single-subscript array, numbers, of twenty integers (requiring a memory allocation for of twenty integers and, as will be seen, a constant pointer numbers) and an integer pointer p:

 

      int numbers [ 20 ], *p;

 

The following assignment is valid:

 

      p = numbers;

 

but since numbers is a constant pointer, the following is not:

 

      numbers = p;      // error

 

An array can be initialized in a declaration:

 

      int numbers [ 5 ] = { 1, 2 };

 

initializes numbers [ 0 ] to 1, numbers [ 1 ] to 2 and the remaining three elements to 0

 

However, the declaration:

 

      int numbers [ 5 ];

 

does not initialize the elements which may be done as in the following:

 

#include <iostream>

using namespace std;

 

#include <iostream>

using namespace std;

 

int main()

{

      int numbers [ 5 ], i;

 

      for ( i = 0; i < 5; i++ ) {

            numbers [ i ] = i;

            cout << "numbers [ " << i << " ] = " << numbers [ i ] << endl;

      }

 

      cout << endl;

 

      cout << "*numbers = " << *numbers << endl << endl;

 

      cout << "Showing that *( numbers + 5 ) and numbers [ 5 ] are identical."

            << endl << endl

            << "*( numbers + 5 ) = " << *(numbers + 5) << endl

            << "numbers [ 5 ] = " << numbers [ 5 ] << endl << endl

            << "Also note that" << endl

            << "*( numbers - 20 ) = " << *(numbers - 20) << endl

            << "numbers [ -20 ] = " << numbers [ -20 ] << endl << endl;

 

      cout << "Interestingly, the above also shows that numbers [ 5 ] exists"

            << endl

            << "even though it was not declared." << endl

            << "This is because of the operator character of []." << endl

            << "numbers [ 5 ] is the content of the address of numbers + 5"

            << endl

            << "Also demonstrated is 'pointer arithmetic.' Which permits only"

            << endl << endl

            << "addition - adding a number to the address of a pointer, and"

            << endl

            << "subtraction - subracting a number from the address of a pointer"

            << endl

            << "Note that while this demonstrates the meaning of [] it is not"

            << endl

            << "necessarily useful in programming" << endl << endl;

 

      return 0;

}

 

whose output is:

 

numbers [ 3 ] = 3

numbers [ 4 ] = 4

 

*numbers = 0

 

Showing that *( numbers + 5 ) and numbers [ 5 ] are identical.

 

*( numbers + 5 ) = 1245120

numbers [ 5 ] = 1245120

 

Also note that

*( numbers - 20 ) = 1254792

numbers [ -20 ] = 1254792

 

Interestingly, the above also shows that numbers [ 5 ] exists

even though it was not declared.

This is because of the operator character of [].

numbers [ 5 ] is the content of the address of numbers + 5

Also demonstrated is 'operator arithmetic.' Which permits only

addition - adding a number to the address of a pointer, and

subtraction - subracting a number from the address of a pointer

Note that while this demonstrates the meaning of [] it is not

necessarily useful in programming

 

 

 

Offset operator [ ] and pointer arithmentic

 

The square bracket combination [] is the a dereference operator called the offset operator; it dereferences and offsets: it adds the number in brackets to the address being dereferenced

 

In the above, numbers, is a constant pointer. numbers [ 0 ] is simply numbers dereferenced and thus *numbers and numbers [ 0 ] are identical

 

The following are also identical:

 

      *( numbers + 5 )

      numbers [ 5 ]

 

numbers [ i ] is the value contained in the memory location i

 

note that the number of memory locations that *( numbers + i + 1 ) is removed from *( numbers + i ) depends on the type to which numbers points; this is because a single element of a ‘larger’ type, e.g. double, occupies more addresses than a small one such as char

 

These concepts are demonstrated in the above program

 

Multidimensional or Multiple-Subscripted Arrays

 

Two-dimensional arrays are useful in representing information arranged in rows and columns or, in mathematical applications, matrices. By convention, the first subscript is the row number while the second is the column number

 

C++ has no limit to the number of subscripts and C++ compilers support at least 12 array subscripts

 

A multidimensional array a[ 2 ][ 3 ][ 4 ] has the same number of elements as a single dimensional array a [ 2 * 3 * 4 ] or a [ 24 ]. In the case of the single dimensional array, the representation of the array in memory is constant pointer to the address the first element and the value of each element. In the case of the multidimensional array the representation also includes array variable also stores the depth of each dimension

 

Thus a multidimensional array is a set of consecutive locations in memory, a set of dimensional depths, and a constant pointer to the address of the first elemtn

 

A two dimensional array with two rows and three columns may be declared:

 

      int b[ 2 ][ 3 ];

 

The declaration serves to reserve memory for the array. An array may be declared and initialized:

 

      int b[ 2 ][ 2 ] { { 1, 2}, { 3, 4 } };

 

 

A variety of concepts regarding declaring, initializing, input and output is demonstrated in the next two routines.

 

// Multiple subscripted arrays: initializiation

 

#include <iostream>

using namespace std;

 

int main()

{

      int a[ 2 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 } }; // each inner group is a                                                            //row of values

      int b[ 2 ][ 3 ] = { 1, 2, 3, 4, 5, 6 }; // reads row by row

 

      cout << "Values of array a and b by row are:\n";

 

      cout << a[ 0 ][ 0 ] << " " << a[ 0 ][ 1 ] << " "  << a[ 0 ][ 2 ] << "\n";

      cout << a[ 1 ][ 0 ] << " " << a[ 1 ][ 1 ] << " "  << a[ 1 ][ 2 ] <<                 "\n\n";

 

      cout << b[ 0 ][ 0 ] << " " << b[ 0 ][ 1 ] << " "  << b[ 0 ][ 2 ] << "\n";

      cout << b[ 1 ][ 0 ] << " " << b[ 1 ][ 1 ] << " "  << b[ 1 ][ 2 ] <<                 "\n\n";

 

// Omitted elements are initialized to zero:

      int e[ 2 ][ 3 ] = { { 1, 2 }, { 4, 5, 6 } }; // each inner group is a row

                                                      //of values

      int f[ 2 ][ 3 ] = { 1, 2, 3, 4, 5 }; // reads row by row

 

      cout << "Values of arrays e and f by row are:\n";

 

      cout << e[ 0 ][ 0 ] << " " << e[ 0 ][ 1 ] << " "  << e[ 0 ][ 2 ] << "\n";

      cout << e[ 1 ][ 0 ] << " " << e[ 1 ][ 1 ] << " "  << e[ 1 ][ 2 ] <<                 "\n\n";

 

      cout << f[ 0 ][ 0 ] << " " << f[ 0 ][ 1 ] << " "  << f[ 0 ][ 2 ] << "\n";

      cout << f[ 1 ][ 0 ] << " " << f[ 1 ][ 1 ] << " "  << f[ 1 ][ 2 ] <<                 "\n\n";

 

      return 0;

}

Output:

Values of array a and b by row are:

1 2 3

4 5 6

 

1 2 3

4 5 6

 

Values of arrays e and f by row are:

1 2 0

4 5 6

 

1 2 3

4 5 0

 

// Multiple subscripted arrays: input output

Arrays as parameters (passing arrays to functions)

 

#include <iostream>

using namespace std;

 

void prntArr( int[][ 3 ] );         // Prototypes

void inputArr( int[][ 3 ] );  // Must declare size for all elements except first

 

int main()

{

      int a[ 2 ][ 3 ] = { 1, 2, 3, 4, 5, 6 };

      int b[ 2 ][ 3 ];

 

      cout << "Values of array a arranged by row:\n";

      prntArr ( a );

 

      cout << "Enter array b:\n";

      inputArr ( b );

 

      cout << "Values of array b arranged by row:\n";

      prntArr ( b );

 

 

      return 0;

}

 

void prntArr ( int c[][ 3 ] )

{

      for (int i = 0; i < 2; i++ ) {

 

            for (int j = 0; j < 3; j++ ) {

                  cout << c[ i ][ j ] << " ";

            }

 

            cout << endl;

      }

      cout << endl;

}

 

void inputArr ( int c[][ 3 ] )

{

      for (int i = 0; i < 2; i++ ) {

 

            cout << "Row " << i + 1 << " Press return after each element\n";

            for (int j = 0; j < 3; j++ ) {

                  cin >> c[ i ][ j ];

            }

 

      }

      cout << endl;

}

Output:

Values of array a arranged by row:

1 2 3

4 5 6

 

Enter array b:

Row 1 Press return after each element

1

3

5

Row 2 Press return after each element

7

9

11

 

Values of array b arranged by row:

1 3 5

7 9 11

 

Arrays of pointers

 

Arrays may contain pointers; a common use of such a data structure is to form an array of strings or string array

 

Function pointers

 

A function pointer is a constant pointer that contains the starting address in memory of the function’s code

 

 

Just as an array name is the identifier of a constant pointer that contains the address of the first element of the array, a function name is the identifier of a constant pointer that contains the starting address in memory of the function’s code

 

C++ allows operations with pointers to functions. The typical use of this is for passing a function as an argument to another function, since these cannot be passed dereferenced. In order to declare a pointer to a function we have to declare it like the prototype of the function except that the name of the function is enclosed between parentheses () and an asterisk (*) is inserted before the name:

 

//  Function pointer example

#include <iostream>

using namespace std;

 

int addition ( int a, int b ) { return (a+b); }

 

int subtraction (int a, int b) { return (a-b); }

 

int (*minus)(int,int) = subtraction;

 

int operation ( int x, int y, int ( *functocall )( int, int ) )

{

  int g;

 

  g = ( *functocall )( x, y );

 

  return ( g );

}

 

int main ()

{

  int m, n;

 

  m = operation ( 7, 5, addition );

  cout << "m = " << m << endl;

 

  n = operation ( 20, m, minus );

  cout << "n = " << n << "\n\n";

 

  return 0;

}

Output:

m = 12

n = 8

 

Function pointers applied in menu driven systems

// Demonstrating menu driven systems

#include <iostream>

using namespace std;

 

int addition ( int a, int b ) { return (a+b); }

int subtraction (int a, int b) { return (a-b); }

 

int operation ( int x, int y, int ( *functocall )( int, int ) )

{

  int g;

 

  g = ( *functocall )( x, y );

 

  return ( g );

}

 

 

int main ()

{

  int m, n, selector, endChar;

// fptr is an array of 2 pointers to functions that each takes two integer arguments

// and returns an integer

  int (*fPtr[ 2 ]) ( int, int ) = { addition, subtraction };

 

        cout << "Computes sum or difference\n\n";

 

  do {

        cout << "Enter first number, m: ";

        cin >> m;

        cout << "Enter second number, n: ";

        cin >> n;

 

        cout << "\nEnter 0 to add, 1 to subtract: ";

        cin >> selector;

 

        cout << "\n" << "Result = " << operation( m, n, fPtr [ selector ] ) << "\n\n";

 

        cout << "Enter 1 to continue, any other number to exit: ";

        cin >> endChar;

        cout << endl;  

  }

  while ( endChar == 1 );

 

  return 0;

}

Output:

Computes sum or difference

 

Enter first number, m: 12

Enter second number, n: 3

 

Enter 0 to add, 1 to subtract: 0

 

Result = 15

 

Enter 1 to continue, any other number to exit: 1

 

Enter first number, m: 12

Enter second number, n: 3

 

Enter 0 to add, 1 to subtract: 1

 

Result = 9

 

Enter 1 to continue, any other number to exit: 4

 

 

Character sequences

 

Consider the code:

 

#include <iostream>

using namespace std;

 

int main()

{

      char pal [ 10 ] = { 'H', 'e', 'l', 'l', 'o', '\0' };

      int i;

 

      cout << "pal = ";

      for ( i = 0; i < 10; i ++ ) {

            cout << pal [ i ];

      }

 

      cout << endl;

 

      cout << "pal [ 9 ] = " << pal [ 9 ] << endl

            << "pal [ -50 ] = " << pal [ -50 ] << endl

            << "pal [ 60 ] = " << pal [60 ] << endl;

           

      cout << endl;

 

      return 0;

}

 

with output:

 

pal = Hello

pal [ 9 ] =

pal [ -50 ] = ╠

pal [ 60 ] = α

 

The above shows one way to initialize a string or character array

 

It also demonstrates again the pointer character of arrays because even though memory has not been allocated to pal [ - 50 ] or pal [ 60 ] they have values. It also demonstrates that the memory allocation is character type

 

An alternative initialization is

 

      char pal [ 10 ] = "Hello";

 

The following, however, are not valid because pal is a constant pointer

 

      pal = "Hello";

      pal = { 'H', 'e', 'l', 'l', 'o', '\0' };

 

The following keyboard input method will work. The following code replaces the declarations of the above routine

 

      char pal [ 10 ] = "";

      int i, nchar;

 

      cout << "Enter number of characters you will enter ";

      cin >> nchar;

      cout << "Enter the text ";

 

      for ( i = 0; i < nchar; i++ ) {

            cin >> pal [ i ];

      }

 

with output:

 

Enter number of characters you will enter 5

Enter the text Hello

pal = Hello

pal [ 9 ] =

pal [ -50 ] = ╠

pal [ 60 ] = α

 

Note that pal is initialized to "" because otherwise the following is output:

 

Enter number of characters you will enter 5

Enter the text Hello

pal = Hello╠╠╠╠╠

pal [ 9 ] = ╠

pal [ -50 ] = ╠

pal [ 60 ] = α

 

The following is a more efficient version and has the same output as the above version (without ‘garbage’)

 

      char pal [ 10 ] = "";

      int i, nchar;

 

      cout << "Enter some text ";

      cin >> pal;

 

This works because cin and cout support null terminated sequences of characters

 

Note that the escape sequence  ‘\0’ is an end of sequence character

*/