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
Variables and identifiers. Data Types
A routine demonstrating new-style header files and namespaces
Multiple statements within an if, nested if, tailors output format to result
Experimenting with increment and decrement operators
Use of for repetition structure: calculating compound interest
Assignments and expressions. Assignment and relational operators
A routine that demonstrates counter controlled repetition
A routine that demonstrates sentinel controlled repetition and use of iomanip and static_cast
Use of switch multiple selection structure
Promotion hierarchy for built-in data types
Precedence and Associativity of C++ operators
Demonstrating cstdlib, ctime, rand, srand, enum
Storage classes and scope rules
Functions with empty parameter lists
Inline functions, the const keyword and the #define preprocessor directive
Call-by-value and call-by-reference
Using constant reference parameters in a call-by-reference
References and reference parameters. Returning local variables
Unary scope resolution operator
Multidimensional or Multiple-Subscripted Arrays
Arrays as parameters (passing arrays to functions)
Function pointers applied in menu driven systems
/*
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
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:
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++
Product information, technical resources, samples and downloads, news and reviews.
msdn.microsoft.com/visualc/
Bjarne Stroustrup's information page about the programming language. Also contains links to other sites.
www.research.att.com/~bs/C++.html
Developer of the C++ programming language.
www.research.att.com/~bs/homepage.html
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/
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/
*/
/*
multiple
line
comment
*/
// begin single line comment
/*
#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?
*/
/*
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’
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
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 |
short int |
short integer |
2bytes |
signed: -32768 to
32767 |
int |
integer |
4bytes |
signed: -2147483648
to 2147483647 |
long int |
long integer |
4bytes |
signed: -2147483648
to 2147483647 |
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;
*/
*/
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 |
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 |
*/
/*
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;
}
/*
*/
#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;
}
/*
*/
#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;
}
/*
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;
}
/*
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;
}
/*
*/
#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;
}
/*
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;
}
/*
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
*/
/*
*/
// 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;
}
/*
*/
/*
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;
}
/*
*/
#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;
}
/*
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 |
|
*/
/*
Standard library leader file |
Explanation |
Old-style header files |
|
<assert.h> |
Contains macros and information for adding diagnostics that aid program debugging. New version: <cassert> |
<ctype.b> |
Contains function prototypes for functions that test characters for certain 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 execution… 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 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 |
||||||||
*/
/*
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 ?:
*/
/*
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…
*/
/*
*/
// 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;
}
/*
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
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
*/
/*
*/
// 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 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;
}
/*
*/
// 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;
}
/*
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 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;
}
/*
*/
// 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;
}
/*
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;
}
/*
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
*/
/*
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
*/
/*
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;
}
/*
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 (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
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
#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 may contain pointers; a common use of such a data structure is to form an array of strings or string array
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
// 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
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
*/