Given expr1 && expr2, expr1 is evaluated
first. If it evaluates to false, then the entire EXPR will be
false (0 && anything is 0); therefore, expr2 is
not evaluated. This is called short circuit evaluation.

When using the terms true and false,
zero is false and not-zero is true.

The while Statement

The while statement supports iteration (i.e. it is
a repetition control statement). Iteration is the process
of repeating an operation.

The idea of looping in a computer program can be attributed
to Ada Lovelace (01815-01852). Many believe Lovelace wrote
the first "computer program." On 10 December 1980 (Ada's
birthday), the U.S. Defense Department approved the reference
manual for its new computer programming language, called "Ada".

The while statement repeatedly executes a
simple statement or block (i.e. compound statement) until
a conditional EXPR becomes false (i.e. 0).
Each loop iteration is called a cycle.

while (EXPR) // typically, you don't want a semicolon
statement;
EXPR is the "conditional" test used to determine whether the loop
should continue for another cycle, and statement is to be repeated.
If multiple statements need to be executed, then use a compound
statement (or block).
EXPR is evaluated only at the beginning of a loop cycle.
Pseudo-code for a while loop:
top-of-loop
evaluate the EXPR
if EXPR is "true" // i.e. a non-zero value
execute statement
go to top-of-loop
else
go to end-of-loop (i.e. terminate the loop)
end-of-loop
statement
...
//Example: loop until user enters a positive number
int n = -1;
while (n <= 0)
cin >> n;
//Example: print out the numbers 1 through 5
int i = 1;
while (i <= 5) {
cout << i << endl;
i = i + 1;
}

Sentinel Values

One way to terminate (end) a loop is when a particular data value
is entered (e.g. the user enters a -1 or end-of-file is encountered),
a special value that is used to end the loop is called a
sentinel value.

Sentinel values should be defined as manifest (symbolic) constants.
Example:

Infinite Loops

When you use a loop in a program, it is important to make sure that
the condition used to control the loop will eventually become
false, so that the loop can end. A loop
that never finishes is called an infinite loop.

To stop an infinite loop, a special command sequence must be typed
on the keyboard to interrupt the program and forcibly cause it to quit.
This command differs from machine to machine.

Sometimes infinite loops are used by design; therefore, existenance
of an infinite loop does not necessarily imply a program defect.

The do while Statement

The do while statement supports iteration (i.e.
it is a repetition control statement). Iteration
is the process of repeating an operation.

The do while statement repeatedly executes a
simple statement or block (i.e. compound statement) until
a conditional EXPR becomes false (i.e. 0).
Each loop iteration is called a cycle.

do
statement;
while (EXPR); //semicolon must follow the while statement
EXPR is the "conditional" test used to determine whether the loop
should continue for another cycle, and statement is to be repeated.
If multiple statements need to be executed, then use a compound
statement (or block). A compound statement is almost always used.
EXPR is evaluated only at the end of a loop cycle.
Pseudo-code for a do-while loop:
top-of-loop
execute statement
evaluate the EXPR
if EXPR is "true" // i.e. a non-zero value
go to top-of-loop
else
go to end-of-loop (i.e. terminate the loop)
end-of-loop
statement
...
//Example: print out the numbers 1 through 3
int i = 1;
do {
cout << i << endl;
i = i + 1;
} while (i <= 3);
Could the previous loop be rewritten:
int i = 1;
do cout << i++ << endl; while (i <= 3);
How about:
int i = 1;
do cout << i << endl; while(i++ <= 3);

When you know for sure that a loop must cycle at least
once, then a do-while is a good loop construct to use.

set item counter to 0
do {
prompt user for data
get data from user
if (data equals sentinel value)
break;
if (data is junk)
continue; //get more data from the user
process the data
increment the item counter
} while (1);
print the item counter

Comment on Style

The do-while can be difficult to read;
therefore, to help it "stick" out, I suggest
the following.

The for Statement

The for statement supports iteration (i.e.
it is a repetition control statement). Iteration
is the process of repeating an operation.

The for statement repeatedly executes a
simple statement or block (i.e. compound statement)
until a control-EXPR becomes false
(i.e. 0). Each loop iteration is called a cycle.

for ([initialization-step]; [conditional-step]; [increment-step])
statement;
The optional "initialization-step" is executed once before the loop
is ever executed (and before the "conditional-step" is evaluated
for the first time).
The optional "conditional-step" is an EXPR that is evaluated at
the top of the loop. If it is true, then the body of the
for statement is executed; otherwise, flow control jumps to
the first executable statement after the for loop body. If
no conditional-step is specified, then it is taken as
permanently true.
After the body of a for loop has been executed, the optional
"increment-step" is executed.
After the increment-step is executed; the conditional-step
is re-evaluated.
Example:
//print the numbers 1 through 3
int i;
for (i = 1; i <= 3; i = i + 1)
cout << i << endl;

If the body of the for contains multiple statements,
then a compound statement is needed.

All three steps for a for loop are EXPRs.
Most commonly, the initialization-step and the increment-step
are assignments or functions calls, and the conditional-step
is a relational EXPR.

The for is frequently used when there are simple
initialization and increment steps because it keeps the loop
control statements close together and visible at the top of
the loop.

The initialization and increment steps often take advantage
of the sequence operator.

Introduction to Functions

Lowest level ideas become EXPRs, EXPRs are grouped into statements,
and statements are grouped together into blocks and
functions.

A function is a set of statements that have
been collected together and given a name.

Functions break large computing tasks into smaller ones, and
enable people to build on what others have done instead of
starting over from scratch. Functions support reuse.

Functions hide details of operation from parts of the program
that don't need to know about them. Functions support
information hiding.

Functions usually consist of zero or more statements, and a
collection of local data. Functions support
encapsulation.

Programs generally consist of many small functions rather
than a few big ones. Functions support modularity.

Repetitive statements should be grouped into a function.
Functions eliminate duplicate code.

Additional benefits derived from using functions.

improves a program's overall readability by reducing the
conceptual complexity of the program

programs can be implemented in less time (generally,
finding and figuring out how to call a function takes
less time than having to write the function)

makes testing easier

improves the overall quality of the program (functions are
usually well tested and efficiently implemented)

allows programs to be implemented in "parts"

supports problem solving techniques such as
"divide-and-conquer" and
"step-wise refinement"

Functions that perform generic tasks can be added to a
library. Library functions can be used in multiple
programs. The C and C++ languages come with extensive libraries
that contain numerous functions.

Function Terminology

The act of executing a set of statements associated with a function
is known as calling the function. If function A calls function
B, then function A is referred to as the calling
or caller function and function B is the called
function.

Arguments are a list of EXPRs that are evaluated and whose
values are passed to the function. (Note: C and C++ are "
pass-by-value" languages.) A function does not need to take
arguments. If function A calls function B, then arguments allows
function A to communicate information to function B.

Arguments, if any, that are passed to a function B, are
parameters within function B. Parameters are treated
as initialized local (i.e. auto variables).

When a function is done, it returns to the caller
by executing a return statement.

Functions can "return a value" back to the caller; thus, if
function A calls function B, then the return value allows function B
to communicate with function A.

Before a function can be called, it must be declared. A
function declaration that also includes the type(s) of the parameters
is called a prototype.

Function Prototypes

A function must be declared (i.e. prototyped) before it is used.

Syntax.

return-type function-name(parameter types, if any);

Examples.

int maxValue(int, int);
//returns an int; receives two int values as parameters
float getSalary(void);
//returns a float; doesn't take any parameters
double computeFactorial(int number);
//returns a double; receives an int value
//parameter types can have a tag specified with them, but the
// tag is ignored by the compiler; tags are used for
// documentation purposes only and can help the readability of
// a program; they have what is referred to as function
// prototype scope
char getGrade(short, unsigned char, unsigned char);
//returns a character; receives a short value and two
// unsigned characters as parameters
void abort(void);
//returns nothing; receives nothing

Function prototypes are used by the compiler to help make sure
that functions are called correctly (e.g. correct number of arguments).
They were added to C++ to improve type-checking and were incorporated into
C by the standards committee.

Function prototypes can help ensure that functions are called using:

a compatible return type

the correct number of arguments

parameter conversions/promotions

When prototyping function arguments, only the types of the arguments need to
be specified. If they are given names, then those names have
"function prototype visibility" and are ignored by
the compiler. Names used in function prototypes are for
documentation purposes only.

f() Versus f(void)

In C, f() implies a function that takes any number of
arguments; where in C++ it indicates a function that takes no arguments.

Function Comment Blocks

Every function should begin with a function comment block.
The function comment block contains - at a minimum - the name of the
function, a list of arguments that it receives, a description of its
return value (if any), and a brief description of what the function does.
In addition, any side-effects (or outputs) performed by the function
should be documented.

The following is an example function comment block.

/*
* name: stringCompare
* parameters: char* -- pointer to a string
* char* -- pointer to a string
* returns: 1 if strings are equal; 0 otherwise
* description: compares two strings character by character
* to determine if they are equal
*/

Cay Horstmann says...

"The description of a function comment block does not document
the implementation but the idea."

Calling a Function

A function is called by specifying the function's name,
followed by a left paren, a comma separated list of arguments
(if any) and a right paren. Comma when used in this context
is not the sequence operator.

Example.

int rv = x(200, 210);
//call the function x passing it two values: 200 and 210
//capture the return value from x in the variable rv
abort();
//call the function abort
//no arguments are passed, nor does the function return any value

A function call is a sequence point: every EXPR that comprises an
argument is evaluated prior to the function being called. The order
in which the arguments are evaluated is undefined.

C and C++ are "call-by-value" languages: the arguments
are evaluated and their respective values are passed to the function.

return; //used when the return-type of the function is void
return EXPR;
EXPR is evaluated. The result of the evaluation, if needed,
is converted to the return-type of the function. For example,
if the return-type of the function is int , then
return 3.14;
will cause the 3.14 double to be converted to an int; therefore,
the calling function will be returned the value 3.
Optionally, the return EXPR can be enclosed in parens.
return (EXPR);
return (3.14); or return 3.14;
return (EXIT_SUCCESS); or return EXIT_SUCCESS;
return (i + 3 * j); or return i + 3 * j;
return (i > 4); or return i > 4;

If a function returns a value, then it is the caller's
responsibility to examine the return value.

If a function's return-type is void, then
return statements, if any, cannot have
any expressions.

If a function is called that returns a value and
the return value is ignored by the caller, then
the caller should type-cast the function call
to be (void).

Lifetime and Visibility (scope)

Lifetime is the period, during execution of a program,
in which a variable or function exists (all functions in a program
exist at all times during its execution).

Visibility is the portions of the program in which a variable
or function can be referenced by name (also referred to as
scope (scope units: file, function, block or
function prototype).

Local and Global Variables

Local variables are declared and/or defined within
a block (either a function or a compound statement).

function parameters are local variables

uninitialized (except for parameters)

visible from point of definition to the end of the block

lifetime is from the point of definition to the end of the block

memory is allocated from the stack

memory is de-allocated at the end of the block

Global variables are declared and/or defined outside of
any function.

initialized to zero

visible from the point they are defined to the end-of-source-file
(may be visible in other source files also - see extern)

have permanent lifetimes

memory allocated from the data segment at program startup

memory is never de-allocated

Storage Classes

auto

The auto storage class indicates that
a variable is a local variable and that memory is automatically
allocated/de-allocated. By default, local variables are defined
to be auto; therefore, this storage class
is rarely specified.

Using auto on a global variable is illegal.

Automatic variables are not initialized to any known value.

extern

The extern storage class allows a global
variable to be visible across multiple source files.

A global variable defined in file A can be accessed in file B if and
only if file B contains the following declaration.

Reference Parameters

C++ passes arguments to functions "by value." This calling
mechanism prohibits called functions from modifying the variables
defined in the caller functions.

Reference parameters allows arguments to be passed
"by reference" instead of by value. If you pass an argument
to a function by reference, then the called function can
access that variable.

Passing an argument by reference causes the address of the variable
argument to be passed rather than its value; consequently, the called
function receives a "pointer" to the variable. Although the called
function is dealing with a pointer, pointer notation is not required.

A parameter that is received as a reference becomes an alias
for the variable that was passed.

Reference parameters are often used when passing large arguments
to a function (e.g. a structure). It is more efficient to by
reference than it is to pass by value (less data must be copied).

Suppose we have a function that converts inches to feet and inches.
We have a problem: our function needs to return two pieces of
information, but is allowed to return only one value. One solution
to the problem is to use reference parameters:

Default Function Arguments

Default function arguments can be specified in either the function
definition or prototype (but not both). Convention is to specify them
in the function prototype.

Only the rightmost arguments can be defaulted. Once a default
function argument is used, all remaining arguments must be
default arguments.

Default arguments are useful when a function needs more arguments than
are necessary to handle simple cases; in particular, functions that
construct objects often provide several options for flexibility.

Syntax: data-type function_name(Type param = value);
If param is not passed by the caller, then it will be set
to value .
Example:
void printReport(char filename[], bool condensed = false);
// one argument is required: a filename, but the second is a
// default argument and it defaults to false if not passed
printReport("report.out"); //1
printReport("report.out", true); //2
printReport("report.out", false); //3
//statements 1 and 3 are equivalent

Function Overloading

Function overloading is the ability to give different functions
the same name.

Stroustrup says:

Most often, it is a good idea to give different functions
different names, but when some functions conceptually perform
the same task on objects of different types, it can be more
convenient to give them the same name.

Use descriptive overloaded function names to describe
similar operations, not different behaviors.

When print() is called, the compiler
must figure out which of the functions with the name "print"
is to be invoked. This is done by comparing the types of the
actual arguments with the types of the parameters of all functions
called "print". The function with the best match is called; if none
exist, then a compile-time error.

Definition:

The signature of a function is defined to consist
of the name of a function and its ordered set of parameter data types.

void foo(const char*);
void foo(char*);
These two functions have different signatures.

Return types are not considered in overload resolution.

Functions declared in different scopes do not overload.

If not careful, you can be surprised as to which function is called.
It is poor programming practice to redefine library functions (your
code may end up calling the correct function, but existing code in
the library may end up invoking the wrong function).

Internally, the compiler accomplishes function overloading by
mangling function names. Function name
mangling makes each translated function name unique. A function
name is mangled by adding prefixes and suffixes to the the name.
The prefixes and suffixes are determined in part by the ordered
lists of the function's parameter data types.

Array Initialization

Arrays can be initialized at the time they are defined.

int evenNumbers[5] = { 2, 4, 6, 8, 10 };
note: it is a syntax error if the # of initializers is
greater than the array length (i.e. # of elements)
The elements of the initializer list must be constant
EXPRs. If the number of initializers is less than the
array length, then remaining elements are set to zero.

If an array is initialized when defined, then the length
is not needed -- the compiler will set the length depending
on the number of initializers. If the length of the array
needs to be greater than the number of initializers specified,
then the length must be specified.

float radioStations[] = { 103.1, 93.3, 100.7 };
radioStations has a length of 3; to figure out the length
of the array using code:
sizeof(radioStations) / sizeof(radioStations[0])
sizeof(radiostations) evaluates to the size of the array
and sizeof(radioStations[0]) evaluates to the size of a
single element of the array (recall, an array size is equal
to the length of the array times the size of the array type)
the following EXPR also works to determine the length of
an array sizeof(radioStations) / sizeof(float) but could
result in the defect if the type of the array is changed and
the EXPR is not

There is not a convenient mechanism for initializing all elements
of an array to a single value (exception: it is easy to set all
elements of an array to zero --
int a[10] = { 0 };).

For efficiency, locally declared arrays that are initialized
at definition may be declared to be static.

Defining and Initializing Pointer Variables

When defining a variable, prefixing the variable's name with an
asterik * causes the variable to be a
pointer.

int* iptr; /*define variable iptr that will point to an int variable*/
float * fptr; /*define variable fptr that will point to a float variable*/
char *cptr; /*define variable cptr that will point to a character*/
int i, j;
float f;
char c;
iptr = &i; /*assign the address-of variable 'i' to iptr*/
fptr = &f; /*assign the address-of variable 'f' to fptr*/
cptr = &c; /*assign the address-of variable 'c' to cptr*/
int* iptr2 = &j; /*define and initialize an int pointer*/
iptr = iptr2; /*now iptr points to the variable 'j'*/
note: Placement of the * when defining a pointer variable is
a matter of style -- I like to place the * next to the
data type, but others prefer to place it next to the
variable name. Placing it next to the data type does
require caution when multiple variables are defined on
the same declaration statement. Example:
int* ip1, ip2;
// ip1 is a pointer to an int , but ip2 is a
regular int
int* ip1, *ip2;
// ip1 and ip2 are both pointers to an int

The address-of operator only applies to objects in memory: variables
and array elements.

Locally defined non-static pointers, unless explicitly initialized, are
garbage and using them without initialization can cause a program to
execute incorrectly (or abort).

Global and statically defined pointers are initialized to the
NULL pointer.

Accessing Data Using Pointers

The unary operator * is the
indirection or dereferencing
operator; when applied to a pointer, it accesses
the object the pointer points to.

Pointers and Function Arguments

Since C passes arguments to functions by value, there is no way for
the called function to alter a variable in the calling function. A
way to obtain the desired effect is for the calling program to pass
pointers to the values to be changed.