Home Previous Next

CSC240 :: Lecture Note :: Week 03
Assignments | Code | Handouts | Resources | Email Thurman {Twitter::@compufoo Facebook::CSzero}
{GDT::Bits:: Time  |  Weather  |  Populations  |  Special Dates}

Overview

Assignment(s): #squares (due 10/6/2017)

Code: ``` extremelyodd.cpp | itofi.cpp | RandomInts.cpp | Expressions0.cpp | Expressions1.cpp | Expressions2.cpp | Expressions3.cpp | RelationalOps.cpp | LogicalOps.cpp | Age0.cpp | Age1.cpp | Age2.cpp | NewAge.cpp | ifcode.cpp | Adder.cpp | DoAdder.cpp | ForAdder.cpp ```

### Arithmetic Operators

All arithmetic operators are binary operators (i.e. they take two operands).

```   *     multiply
/     divide
%     modulus (remainder)
-     substraction
```

Important points.

• Divide by 0 is not defined and it causes your program to abort (e.g. ` 10 / 0`).

• Dividing one integer by another (integer division) results in truncation (i.e. the fractional part, if any, is lost)
example: `8 / 3` equals `2`.

• The modulus operator `%` results in the remainder when one integer is divided by another
example: `8 % 3` equals `2` (note: both operands must be integral types).

• `* / %` have higher precedence than `+ -` and associativity is left-to-right .

• Precedence and associativity can be altered by using parenthesis

```   a + b * c       binds as  a + (b * c)
(a + b) * c     ()s used to alter binding
```

{TopOfPage} {Resources}

### Precedence and Associativity of Operators

Whenever you have an EXPR that contains multiple operators, then you must be aware of operator precedence and associativity.

Precedence and associativity are used to "bind" operators with operands.

Every C/C++ book that I have reviewed contains a precedence and associativity chart. Here is a chart that displays the precedence and associativity of some of the operators we learn first.

Unary `+` and `-` have higher precedence than the binary forms.
Operators Associativity
`()   +   -   (type)   sizeof` right to left
`*   /   %` left to right
`+   -` left to right
`=` right to left

Precedence determines the order in which operands are bound to operators. Operators on the same line have the same precedence; rows are in order of decreasing precedence.

Examples:

• The `sizeof` operator is high precedence, whereas the assignment operator `=` has low precedence.
• The multiple operator `*` is a medium precedence operator that has slightly higher precedence that the addition operator `+`.

If an EXPR contains two operators of equal precedence, then associativity is used to bind operators and operands.

An example using the EXPR:    `a + b - c`

```   The + and - operators have equal precedence; therefore, associativity
is used.  They associate left-to-right and we end up with with the
binding  (a + b) - c
```

Precedence and associativity can be altered by using parenthesis.

```   Example expression:  a * b / c

* and / have equal precedence and they associate left-to-right;
therefore, we get the following binding:  (a * b) / c

If we want the operand  b  to be attached to the operand  c,
then we would parenthesis and code the EXPR:  a * (b / c).
```

Use parenthesis if you are ever in doubt about the precedence and associativity rules. [Note: it is possible to overuse ()'s.]

GDT::Resource::C++:: Precedence chart that includes all operators.

{TopOfPage} {Resources}

### Relational Operators

Relational operators are used to compare the value of two expressions (EXPRs).

  ==    != expr1 == expr2 equals expr1 != expr2 not equals expr1 > expr2 greater than expr1 < expr2 less than expr1 >= expr2 greater than or equal to expr1 <= expr2 less than or equal to

The operators that are made up of two characters cannot have any whitespace between. For example: `= =` would be treated as two separate assignment operators and would result in a compile-time error. `==` is used to test two operands for equality.

It is easy to sometimes use the equality operator in lieu of the assignment operator and vice versa. You must remember the following.

```   ==   is the relational equality operator; it compares two operands
for equality and evaluates to either 0 (false) or 1 (true)

=    is the assignment operator; it copies the value of the operand
on the right-hand side to the operand on the left-hand side; the
EXPR evaluates to the value that was copied (i.e. assigned)
```

Examples.

```   int thisCourse = 100;   /* 100 assigned to thisCourse */
int nextCourse = 205;   /* 205 assigned to nextCourse */

thisCourse == nextCourse   /* evaluates to 0 (false) */
thisCourse != nextCourse   /* evaluates to 1 (true) */
thisCourse > nextCourse    /* evaluates to 0 */
thisCourse < nextCourse    /* evaluates to 1 */
thisCourse >= nextCourse   /* evaluates to 0 */
thisCourse <= nextCourse   /* evaluates to 1 */
```

GDT::C++::Code:: RelationalOps.cpp

{TopOfPage} {Resources}

### The `if` Statement and `else` Clause

The `if` is a selection control statement. It is a keyword of the language. It has the following syntax.

```   if (EXPR)
statement';
statement'';

If  EXPR  evaluates to true (i.e. not zero), then  statement'  is
executed followed by statement''; otherwise,  statement'  is skipped
and the flow control of the program jumps to  statement''.

if (netWorth > 1000000)
cout << "you are rich (at least money wise)";
netWorth = netWorth * 2;   //let us double our net worth
```

Typically, there is no semicolon after the `if`. If there is, then the body of the `if` is simply a `NULL` (empty) statement. In many cases, this is a defect with your program (i.e. it is done by accident, not design).

```   if (netWorth < 0)
;  //do nothing...
```

If more than one statement needs to be executed when an `if` EXPR is true, then a compound statement. should be used. A compound statement is a collection of zero or more statements enclosed in braces `{}`.

Compound statements are terminated by the closing brace `}` -- not a semicolon.

```   if (EXPR) {
statement';
statement'';
}                //note that there is no semicolon
statement''';

If EXPR evaluates to true, then both statement' and statement''
are executed followed by statement'''; otherwise, statement' and
statement'' are skipped and the flow control of the program jumps
to statement'''.

isSuperStar = false;
bonus = 0;

...

if (battingAvg > 300) {
isSuperStar = true;
bonus = 10000;
}
number = 55;
```

Every `if` statement can have a corresponding `else` clause which is executed whenever the `if` is false (i.e. 0). Syntax.

```   if (EXPR)
statement';
else
statement'';
statement''';

If EXPR is true, then statement' is executed, the else clause is
skipped and the flow control of the program jumps to statement''';
otherwise, statement' is skipped, statement'' is executed and
the flow control of the program jumps to statement'''.

if (netWorth > 1000000)
cout << "you are rich (with respect to money)";
else
cout << "you are rich in other ways";
```

An `else` clause cannot be used without a corresponding `if` statement. Example.

```   int i = 10;

...

else   //not allowed -- there is no if statement
cout << "this is not legal\n";
```

The body of an `if` construct can be any type of statement. Examples.

```   if (EXPR) EXPR;      //the body is an expression statement
if (EXPR) return EXIT_SUCCESS;  //body is a return statement
if (EXPR) ;          //body is a null statement
if (EXPR) { }        //body is an empty compound statement
if (EXPR) if (EXPR)  //body is another if statement
```

An `if` statement containing another `if` is referred to as a nested if. There is no limit to the amount of nesting that can occur. Examples.

```   if (EXPR)
if (EXPR')
statement';
statement'';

If EXPR is true, then EXPR' is evaluated; otherwise,
flow control jumps to statement''.  If EXPR' is evaluated
and it evaluates to true, then statement' is executed;
otherwise, flow control jumps to statement''.

if (age >= 100)
if (gender == 'M')
cout << "old man look at my life";

if (age >= 100)
if (gender == 'M')
if (iq > 120)
cout << "smart old man look at my life";
cout << endl;
```

When using `if` statements, it is a good programming practice to use indentation to aid readability. The body of an `if` statement should be indented three or four spaces.

In all cases, each `if` can have a corresponding `else` clause.

```   if (EXPR)
if (EXPR')
statement';
else
statement'';
statement''';

The top-most  if  does not have an  else  clause, whereas the
inner-most  if  does.  If EXPR evaluates to false, then
flow control jumps to statement'''; otherwise, EXPR' is
evaluated.  If it evaluates to true, then statement' is
executed; otherwise, statement' is skipped and statement'' is
evaluated.  Regardless of which statement is executed,
flow control jumps to statement'''.
```

Caution is required to make sure that `else` clauses match up to the correct `if` construct.

```   if (age > 100)
if (gender == 'M')
cout << "you are an old man";
else
cout << "you are a young person";

If age is greater than 100, then  if (gender == 'M')  will
be executed.  If the gender is 'M', then the correct statement
will print, but if the gender is not 'M', then the
"you are a young person" message will print.

To correct this problem, a compound statement is needed to
"tie" the  else  clause with the outer-most  if  statement.

if (age > 100) {
if (gender == 'M')
cout << "you are an old man";
} else
cout << "you are a young person";

Now if age > 100, then the body of the  if  is executed;
otherwise, flow control jumps to the  else  clause.
```

GDT::C++::Code:: Age0.cpp and Age1.cpp and Age2.cpp

{TopOfPage} {Resources}

### Logical Operators

Logical operators are used to "connect" expressions. Where relational operators are used to compare two values, logical operators take boolean operands and combine them to form boolean values.

  !     && !expr NOT expr1 && expr2 AND expr1 || expr2 OR

The `!` operator is a high-precedence unary operator, while `&&` and `||` are medium-precedence binary operators. AND has slightly higher precedence than OR.

Examples.

```   int i = 10, j = 5, k = 0;

i == 10 && j == 5     yields the value 1 (true)
i == 5  && j == 5     yields the value 0 (false)
i == 10 || j == 5     yields the value 1
i == 5  || j == 10    yields the value 0
!i                    yields the value 0
!k                    yields the value 1
!k && k               yields the value 0
```

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.

GDT::C++::Code:: LogicalOps.cpp

{TopOfPage} {Resources}

### A Joke Having To Do With Loops

Example of 21st century Informatics?

```   Q: How do you keep a computer programmer in the
shower all day long?

A: Give them a shampoo with a label that says
"rinse, lather, repeat."
```

Berkeley.edu::Jester--The Online Joke Recommender is a "computer program that rates jokes and gives suggestions based on each user's personal sense of humor."

{TopOfPage} {Resources}

### 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:

```   const int EXIT_VALUE = -1;
int n = EXIT_VALUE + 1;
while (n != EXIT_VALUE) {
cout << "Enter a number (" << EXIT_VALUE << " to exit): ";
cin >> n;
}
```
##### 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 following are infinite loops that do nothing
while (1)
;  //null statement

int i = 99;
while (i != 0) ;

while (true) ;  //C++ only...

while (!false) { }  //C++ only....

while (43 == 43) ;
```

{TopOfPage} {Resources}

### 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);

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.

• place the `do` on a line by itself
• always use a compound statement
• the body of the loop should be indented (of course)
• place the closing `while` on a line by itself

{TopOfPage} {Resources}

### 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.

```   for (i = 0, j = 99; i < n; i = i + 1, j = j - 1)
do_something;
```

{TopOfPage} {Resources}

### 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.

{TopOfPage} {Resources}

### 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.

{TopOfPage} {Resources}

### 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);
```

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.

In C++, `f()` and `f(void)` are equivalent.

{TopOfPage} {Resources}

### Function Definitions

The function definition contains the statements that comprise a function. The definition of a function is also referred to as its implementation.

Function statements are enclosed in {}'s and are referred to as the function body.

The body of a function consists of zero more variable declarations/definitions and zero or more statements.

Examples:

```   int x(int n1, int n2) {
//this is the function body...
}

void y(float f, char c, int i) {
//this function doesn't return a value; it takes three
//   parameters (a float, a char and an int)
...
if (i) return;
...
}
```
When a function is defined, each parameter, if any, must be specified with a type and a name. Parameter type-name pairs are separated by comma's (these comma's are not the sequence operator).

If the return-type is not specified, then it defaults to `int`. You should get in the habit of always explicitly specifiying the return-type.

Parameters can be thought of as initialized local variables (i.e. space is allocated for them from the stack and they are initialized to the value of the arguments that are passed).

Variables declared inside of a function body are visible only with that block of code. These variables are referred to as a "local" variables.

A function definition can contain multiple return statements; however, many programmers are of the opinion that a function should have only one exit point.

A stub function is a function that contains no statements.

{TopOfPage} {Resources}

### 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."

{TopOfPage} {Resources}

### 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.

{TopOfPage} {Resources}

### Function Return Value

A function communicates back to the caller by "returning" a value.

The type of value returned by a function (i.e. the return-type) is specified when the function is defined. If the return-type is not specified, then it defaults to `int`.

A function does not have to return a value. In these cases, the return-type `void` is used.

Other points.

• Functions can return at most one value.
• A function returns to the caller by executing a `return` statement.
• Functions can have multiple `return` statements. (Although structured programming purists don't like this.)
• A function returns to the function that called it.

The syntax of the `return` statement is as follows.

```   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)`.

```   (void) printf("hello, world\n");
```

{TopOfPage} {Resources}

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)
• memory allocated from the data segment at program startup
• memory is never de-allocated
##### 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.

```	extern type variable_name;

extern int errno;  /* errno is defined in some other file */
```

Use of `extern` results in a declaration -- not a definition. In other words, an `extern` declaration does not result in the allocation of memory.

It is not legal to initialize an external variable at the time it is declared (i.e. `extern float rate = 5.3;` is illegal).

##### static

When `static` is applied to a global variable, then it limits the scope of an object to the rest of the file (i.e. it cannot be externally declared in other source files).

When `static` is applied to a local variable, then it causes the local variable to remain in existence across function calls providing private, permanent storage within a single function.

When `static` is applied to a function, then the function is visible only to the source file in which is defined (in a way, the function is made "private").

##### register

A register is a high speed memory location located on the CPU.

The `register` storage class is used on local variables that are going to be accessed many times (for example, loop control variables).

• register usage can result in smaller/faster programs
• using `register` is often times ignored by the compiler
• applies only to locals and parameters
• cannot use the address-of operator

{TopOfPage} {Resources}

### 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:

```   int convertInches(int totalInches, int& feet);
// the & after the type  int  indicates that the function
// receives a reference to an  int

...

int feet;
int inches = convertInches(80, feet);
// feet is passed by reference; no special notation is needed

...

/**
The function receives the total inches.  The return value
of the function is the inches, and the feet are copied
into the reference parameter supplied as the 2nd argument.
**/

int convertInches(int totalInches, int& feet) {
const int INCHES_PER_FOOT = 12;
feet = totalInches / INCHES_PER_FOOT;
}
```

{TopOfPage} {Resources}

### 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
```

{TopOfPage} {Resources}

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.
```   Good:
int max(int, int);        //find max of two ints
float max(float, float);  //find max of two floats

Not so Good:
void draw(Image*);        //draw an image
void draw(Card*);         //draw a card
```
The following is an example of an overloaded function:
```   void print(int), print(double), print(long), print(char),
print(int, int), print(double, double);

char c;
short s;
int i;
float f;

print(c);            // invoke print(char)
print(i);            // invoke print(int)
print(s);            // invoke print(int); s promoted to int
print(f);            // invoke print(double); f promoted to double
print('A');          // invoke print(char); 'A' is a char
print(200);          // invoke print(int); 200 is an int
print(200L);         // invoke print(long); 200L is a long
print(99.9);         // invoke print(double); 99.9 is a double
print(i, i);         // invoke print(int,int)
print(i, 'a');       // invoke print(int,int); 'a' promoted to int
print(s, 'A');       // invoke print(int,int); s - 'A' promoted to int
//! print(1.1L);     // ambiguous -- compiler can't decide
print(200L, i);      // invoke print(int,int);
//! print(i, 3.14);  // ambiguous -- compiler can't decide
```
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.

Criteria used to determine a match (partial):
1. exact match of function call arguments with an overloaded function signature
2. trivial conversions (exact match after applying promotions to argument data types -- char ==> int, short ==> int, float ==> double)
3. exact match after applying promotions and standard conversions to argument data types (float ==> int, double ==> float)
4. exact match after programmer defined conversions (e.g. typecast)
Note:  `const`  arguments can be distinguished from non-`const` arguments.
```	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.

```	print(200);             // mangled name: print_Fi
print(float(3.14));     // mangled name: print_Ff
```

C: C++: Java: no yes yes

{TopOfPage} {Resources}

Home Previous Next