C++ Tutorials
C++ Tutorials
2. Basic Syntaxes
2.1 Revision
Below is a simple C++ program that illustrates the important programming constructs (sequential flow, while-loop,
and if-else) and input/output. Read "Introduction To C++ Programming for Novices and First-time Programmers"
if you need help in understanding this program.
1/*
2 * Sum the odd and even numbers, respectively, from 1 to a given upperbound.
3 * Also compute the absolute difference.
4 * (SumOddEven.cpp)
5 */
6#include <iostream> // Needed to use IO functions
7using namespace std;
8
9int main() {
10 int sumOdd = 0; // For accumulating odd numbers, init to 0
11 int sumEven = 0; // For accumulating even numbers, init to 0
12 int upperbound; // Sum from 1 to this upperbound
13 int absDiff; // The absolute difference between the two sums
14
15 // Prompt user for an upperbound
16 cout << "Enter the upperbound: ";
17 cin >> upperbound;
18
19 // Use a while-loop to repeatedly add 1, 2, 3,..., to the upperbound
20 int number = 1;
21 while (number <= upperbound) {
22 if (number % 2 == 0) { // Even number
23 sumEven += number; // Add number into sumEven
24 } else { // Odd number
25 sumOdd += number; // Add number into sumOdd
26 }
27 ++number; // increment number by 1
28 }
29
30 // Compute the absolute difference between the two sums
31 if (sumOdd > sumEven) {
32 absDiff = sumOdd - sumEven;
33 } else {
34 absDiff = sumEven - sumOdd;
35 }
36
37 // Print the results
38 cout << "The sum of odd numbers is " << sumOdd << endl;
39 cout << "The sum of even numbers is " << sumEven << endl;
40 cout << "The absolute difference is " << absDiff << endl;
41
42 return 0;
43}
For examples,
// Each of the following lines is a programming statement, which ends with a semi-colon (;)
int number1 = 10;
int number2, number3 = 99;
int product;
product = number1 * number2 * number3;
cout << "Hello" << endl;
Block : A block (or a compound statement) is a group of statements surrounded by braces { }. All the statements
inside the block is treated as one unit. Blocks are used as the body in constructs like function, if-else and loop,
which may contain multiple statements but are treated as one unit. There is no need to put a semi-colon after the
closing brace to end a complex statement. Empty block (without any statement) is permitted. For examples,
// Each of the followings is a "complex" statement comprising one or more blocks of statements.
// No terminating semi-colon needed after the closing brace to end the "complex" statement.
// Take note that a "complex" statement is usually written over a few lines for readability.
if (mark >= 50) {
cout << "PASS" << endl;
cout << "Well Done!" << endl;
cout << "Keep it Up!" << endl;
}
if (number == 88) {
cout << "Got it" << endl;
} else {
cout << "Try Again" << endl;
}
i = 1;
while (i < 8) {
cout << i << endl;
++i;
}
int main() {
...statements...
}
Additional white spaces and extra lines are, however, ignored, e.g.,
// same as above
int sum
= 0 ;
double average ;
average = sum / 100.0;
Formatting Source Codes : As mentioned, extra white spaces are ignored and have no computational
significance. However, proper indentation (with tabs and blanks) and extra empty lines greatly improves the
readability of the program, which is extremely important for others (and yourself three days later) to understand
your programs. For example, the following hello-world works, but can you understand the program?
#include <iostream>
using namespace std;int main(){cout<<"Hello, world!"<<endl;return 0;}
Braces : Place the beginning brace at the end of the line, and align the ending brace with the start of the
statement.
Indentation : Indent the body of a block by an extra 3 (or 4 spaces), according to its level.
For example,
/*
* Recommended Programming style.
*/
#include <iostream>
using namespace std;
// blank line to separate sections of codes
int main() { // Place the beginning brace at the end of the current line
// Indent the body by an extra 3 or 4 spaces for each level
return 0;
} // ending brace aligned with the start of the statement
Most IDEs (such as CodeBlocks, Eclipse and NetBeans) have a command to re-format your source code
automatically.
Note: Traditional C-style formatting places the beginning and ending braces on the same column. For example,
/*
* Traditional C-style.
*/
#include <iostream>
using namespace std;
int main()
{
if (mark >= 50) // in level-1 block, indent once
{
cout << "You Pass!" << endl; // in level-2 block, indent twice
}
else
{
cout << "You Fail!" << endl;
}
}
A preprocessor directive, which begins with a # sign (such as #include, #define), tells the preprocessor to perform
a certain action (such as including a header file, or performing text replacement), before compiling the source code
into object code. Preprocessor directives are not programming statements, and therefore should NOT be
terminated with a semi-colon. For example,
#include <iostream> // To include the IO library header
#include <cmath> // To include the Math library header
#define PI 3.14159265 // To substitute the term PI with 3.14159265 in this file
// DO NOT terminate preprocessor directive with a semi-colon
In almost all of the C++ programs, we use #include <iostream> to include the input/output stream library header
into our program, so as to use the IO library function to carry out input/output operations (such as cin and cout).
3.2 Identifiers
An identifier is needed to name a variable (or any other entity such as a function or a class). C++ imposes the
following rules on identifiers:
An identifier is a sequence of characters, of up to a certain length (compiler-dependent, typically 255
characters), comprising uppercase and lowercase letters (a-z, A-Z), digits (0-9), and underscore "_".
White space (blank, tab, new-line) and other special characters (such as +, -, *, /, @, &, commas, etc.) are not
allowed.
An identifier must begin with a letter or underscore. It cannot begin with a digit. Identifiers beginning with an
underscore are typically reserved for system use.
An identifier cannot be a reserved keyword or a reserved literal (e.g.,int, double, if, else, for).
Identifiers are case-sensitive. A rose is NOT a Rose, and is NOT a ROSE.
Caution : Programmers don't use blank character in names. It is either not supported, or will pose you more
challenges.
Variable Naming Convention
A variable name is a noun, or a noun phrase made up of several words. The first word is in lowercase, while the
remaining words are initial-capitalized, with no spaces between words. For
example, thefontSize, roomNumber, xMax, yMin, xTopLeft and thisIsAVeryLongVariableName. This convention
is also known as camel-case.
Recommendations
1. It is important to choose a name that is self-descriptive and closely reflects the meaning of the variable,
e.g., numberOfStudents or numStudents.
2. Do not use meaningless names like a, b, c, d, i, j, k, i1, j99.
3. Avoid single-alphabet names, which is easier to type but often meaningless, unless they are common names
like x, y, z for coordinates, i for index.
4. It is perfectly okay to use long names of says 30 characters to make sure that the name accurately reflects
its meaning!
5. Use singular and plural nouns prudently to differentiate between singular and plural variables. For example,
you may use the variable row to refer to a single row number and the variable rows to refer to many rows
(such as an array of rows - to be discussed later).
3.3 Variable Declaration
To use a variable in your program, you need to first "introduce" it by declaring its name and type, in one of the
following syntaxes:
Syntax Example
Example,
1#include <iostream>
2using namespace std;
3
4int main() {
5 int number; // Declared but not initialized
6 cout << number << endl; // Used before initialized
7 // No warning/error, BUT unexpected result
8 return 0;
9}
Constant Naming Convention: Use uppercase words, joined with underscore. For
example, MIN_VALUE, MAX_SIZE.
3.5 Expressions
An expression is a combination of operators (such as addition '+', subtraction '-', multiplication '*', division '/')
and operands (variables or literal values), that can be evaluated to yield a single value of a certain type. For example,
1 + 2 * 3 // give int 7
The RHS shall be a value; and the LHS shall be a variable (or memory address).
Syntax Exam
// Assign the literal value (of the RHS) to the variable (of the LHS)
variable = literal-value; number = 88;
// Evaluate the expression (RHS) and assign the result to the variable (LHS)
variable = expression; sum = sum +
The assignment statement should be interpreted this way: The expression on the right-hand-side (RHS) is first
evaluated to produce a resultant value (called rvalue or right-value). The rvalue is then assigned to the variable on
the left-hand-side (LHS) (or lvalue, which is a location that can hold a rvalue). Take note that you have to first
evaluate the RHS, before assigning the resultant value to the LHS. For examples,
number = 8; // Assign literal value of 8 to the variable number
number = number + 1; // Evaluate the expression of number + 1,
// and assign the resultant value back to the variable number
The symbol "=" is known as the assignment operator. The meaning of "=" in programming is different from
Mathematics. It denotes assignment instead of equality. The RHS is a literal value; or an expression that evaluates
to a value; while the LHS must be a variable. Note that x = x + 1 is valid (and often used) in programming. It
evaluates x + 1 and assign the resultant value to the variable x. x = x + 1 illegal in Mathematics. While x + y =
1 is allowed in Mathematics, it is invalid in programming (because the LHS of an assignment statement must be a
variable). Some programming languages use symbol ":=", "←", "->", or "→" as the assignment operator to avoid
confusion with equality.
3.7 Fundamental Types
Integers: C++ supports these integer types: char, short, int, long, long long (in C++11) in a non-decreasing
order of size. The actual size depends on the implementation. The integers (except char) are signed number (which
can hold zero, positive and negative numbers). You could use the keyword unsigned
[char|short|int|long|long long] to declare an unsigned integers (which can hold zero and positive numbers).
There are a total 10 types of integers - signed|unsigned combined with char|short|int|long|long long .
Characters: Characters (e.g., 'a', 'Z', '0', '9') are encoded in ASCII into integers, and kept in type char. For
example, character '0' is 48 (decimal) or 30H (hexadecimal); character 'A' is 65 (decimal) or 41H (hexadecimal);
character 'a' is 97 (decimal) or 61H (hexadecimal). Take note that the type char can be interpreted as character in
ASCII code, or an 8-bit integer. Unlike int or long, which is signed, char could be signed or unsigned, depending
on the implementation. You can use signed char or unsigned char to explicitly declare signed or unsigned
char.
Floating-point Numbers: There are 3 floating point types: float, double and long double, for single,
double and long double precision floating point numbers. float and double are represented as specified by IEEE
754 standard. A float can represent a number between ±1.40239846×10^-45 and ±3.40282347×10^38,
approximated. A double can represented a number between ±4.94065645841246544×10^-
324 and ±1.79769313486231570×10^308 , approximated. Take note that not all real numbers can be represented
by float and double, because there are infinite real numbers. Most of the values are approximated.
Boolean Numbers: A special type called bool (for boolean), which takes a value of either true or false.
The table below shows the typical size, minimum, maximum for the primitive types. Again, take note that the sizes
are implementation dependent.
Bytes Minimum Max
Category Type Description
(Typical) (Typical) (Ty
Integers int Signed integer (of at least 16 4 (2) - 21474
(or signed int) bits) 2147483648
unsigned int Unsigned integer (of at least 4 (2) 0 42949
16 bits)
char Character 1
(can be either signed or
unsigned depends on
implementation)
signed char Character or signed tiny 1 -128 127
integer
(guarantee to be signed)
unsigned char Character or unsigned tiny 1 0 255
integer
(guarantee to be unsigned)
Bytes Minimum Max
Category Type Description
(Typical) (Typical) (Ty
short Short signed integer (of at 2 -32768 32767
(or short int) least 16 bits)
(or signed
short)
(or signed
short int)
unsigned short Unsigned short integer (of at 2 0 65535
(or unsigned least 16 bits)
shot int)
long Long signed integer (of at least 4 (8) - 21474
(or long int) 32 bits) 2147483648
(or signed
long)
(or signed long
int)
unsigned long Unsigned long integer (of at 4 (8) 0 same a
(or unsigned least 32 bits)
long int)
long long Very long signed integer (of at 8 -263 263-1
(or long long least 64 bits)
int)
(or signed long
long)
(or signed long
long int)
(C++11)
unsigned long Unsigned very long integer (of 8 0 264-1
long at least 64 bits)
(or unsigned
long long int)
(C++11)
Real float Floating-point number, ≈7 4 3.4e38 3.4e-
Numbers digits
(IEEE 754 single-precision
floating point format)
double Double precision floating- 8 1.7e308 1.7e-
point number, ≈15 digits
(IEEE 754 double-precision
floating point format)
long double Long double precision 12 (8)
floating-point number, ≈19
digits
(IEEE 754 quadruple-precision
floating point format)
Bytes Minimum Max
Category Type Description
(Typical) (Typical) (Ty
Boolean bool Boolean value of 1 false (0) true
Numbers either true or false non-z
Wide wchar_t Wide (double-byte) character 2 (4)
Characters char16_t
(C++11)
char32_t
(C++11)
In addition, many C++ library functions use a type called size_t, which is equivalent (typedef) to a unsigned int,
meant for counting, size or length, with 0 and positive integers.
*The sizeof Operator
C/C++ provides an unary sizeof operator to get the size of the operand (in bytes). The following program
uses sizeof operator to print the size of the fundamental types.
1/*
2 * Print Size of Fundamental Types (SizeofTypes.cpp).
3 */
4#include <iostream>
5using namespace std;
6
7int main() {
8 cout << "sizeof(char) is " << sizeof(char) << " bytes " << endl;
9 cout << "sizeof(short) is " << sizeof(short) << " bytes " << endl;
10 cout << "sizeof(int) is " << sizeof(int) << " bytes " << endl;
11 cout << "sizeof(long) is " << sizeof(long) << " bytes " << endl;
12 cout << "sizeof(long long) is " << sizeof(long long) << " bytes " << endl;
13 cout << "sizeof(float) is " << sizeof(float) << " bytes " << endl;
14 cout << "sizeof(double) is " << sizeof(double) << " bytes " << endl;
15 cout << "sizeof(long double) is " << sizeof(long double) << " bytes " << endl;
16 cout << "sizeof(bool) is " << sizeof(bool) << " bytes " << endl;
17 return 0;
18}
sizeof(char) is 1 bytes
sizeof(short) is 2 bytes
sizeof(int) is 4 bytes
sizeof(long) is 4 bytes
sizeof(long long) is 8 bytes
sizeof(float) is 4 bytes
sizeof(double) is 8 bytes
sizeof(long double) is 12 bytes
sizeof(bool) is 1 bytes
[TODO]
Choosing Types
As a programmer, you need to choose variables and decide on the type of the variables to be used in your
programs. Most of the times, the decision is intuitive. For example, use an integer type for counting and whole
number; a floating-point type for number with fractional part, char for a single character, and boolean for binary
outcome.
Rule of Thumb
Use int for integer and double for floating point numbers. Use byte, short, long and float only if you have
a good reason to choose that specific precision.
Use int (or unsigned int) for counting and indexing, NOT floating-point type (float or double). This is
because integer type are precise and more efficient in operations.
Use an integer type if possible. Use a floating-point type only if the number contains a fractional part.
Read my article on "Data Representation" if you wish to understand how the numbers and characters are
represented inside the computer memory. In brief, It is important to take note that char '1' is different from int
1, short 1, float 1.0, double 1.0, and String "1". They are represented differently in the computer memory,
with different precision and interpretation. For example, short 1 is "00000000 00000001", int 1 is "00000000
00000000 00000000 00000001", long long 1 is "00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000001", float 1.0 is "0 01111111 0000000 00000000 00000000" , double 1.0 is "0 01111111111
0000 00000000 00000000 00000000 00000000 00000000 00000000", char '1' is "00110001".
There is a subtle difference between int 0 and double 0.0.
Furthermore, you MUST know the type of a value before you can interpret a value. For example, this
value "00000000 00000000 00000000 00000001" cannot be interpreted unless you know the type.
*The typedef Statement
Typing "unsigned int" many time can get annoying. The typedef statement can be used to create a new name
for an existing type. For example, you can create a new type called "uint" for "unsigned int" as follow. You should
place the typedef immediately after #include. Use typedef with care because it makes the program hard to read
and understand.
Many C/C++ compilers define a type called size_t, which is a typedef of unsigned int.
Floating-point Literals
A number with a decimal point, such as 55.66 and -33.44, is treated as a double, by default. You can also express
them in scientific notation, e.g., 1.2e3, -5.5E-6, where e or E denotes the exponent in power of 10. You could
precede the fractional part or exponent with a plus (+) or minus (-) sign. Exponent shall be an integer. There should
be no space or other characters (e.g., space) in the number.
You MUST use a suffix of 'f' or 'F' for float literals, e.g., -1.2345F. For example,
float average = 55.66; // Error! RHS is a double. Need suffix 'f' for float.
float average = 55.66f;
Use suffix 'L' (or 'l') for long double.
Character Literals and Escape Sequences
A printable char literal is written by enclosing the character with a pair of single quotes, e.g., 'z', '$', and '9'. In
C++, characters are represented using 8-bit ASCII code, and can be treated as a 8-bit signed integers in arithmetic
operations. In other words, char and 8-bit signed integer are interchangeable. You can also assign an integer in
the range of [-128, 127] to a char variable; and [0, 255] to an unsigned char.
You can find the ASCII code table HERE.
For example,
Notes:
New-line (0AH) and carriage return (0dH), represented by \n, and \r respectively, are used as line
delimiter (or end-of-line, or EOL). However, take note that Unixes/Mac use \n as EOL, Windows use \r\n.
Horizontal Tab (09H) is represented as \t.
To resolve ambiguity, characters back-slash (\), single-quote (') and double-quote (") are represented using
escape sequences \\, \' and \", respectively. This is because a single back-slash begins an escape sequence,
while single-quotes and double-quotes are used to enclose character and string.
Other less commonly-used escape sequences are: \? or ?, \a for alert or bell, \b for backspace, \f for form-
feed, \v for vertical tab. These may not be supported in some consoles.
The <cctype> Header
The cctype header (ported from C's ctype.h) provides functions such
as isalpha(), isdigit(), isspace(), ispunct(), isalnum(), isupper(), islower() to determine the type of
character; and toupper(), tolower() for case conversion.
String Literals
A String literal is composed of zero of more characters surrounded by a pair of double quotes, e.g., "Hello,
world!", "The sum is ", "". For example,
TRY: Write a program to print the following picture. Take note that you need to use escape sequences to print
special characters.
'__'
(oo)
+========\/
/ || %%% ||
* ||-----||
"" ""
bool Literals
There are only two bool literals, i.e., true and false. For example,
Gender is m
Is married is 1 // true
Number of children is 8
Year of birth is 1945
Salary is 88000
Weight is 88.88
GPA is 3.88
4. Operations
4.1 Arithmetic Operators
C++ supports the following arithmetic operators for numbers: short, int, long, long long, char (treated as 8-bit
signed integer), unsigned short, unsigned int, unsigned long, unsigned long long, unsigned
char, float, double and long double.
Operator Description Usage Examples
* Multiplication expr1 * expr2 2 * 3 → 6; 3.3 * 1.0 → 3.3
/ Division expr1 / expr2 1 / 2 → 0; 1.0 / 2.0 → 0.5
% Remainder (Modulus) expr1 % expr2 5 % 2 → 1; -5 % 2 → -1
+ Addition expr1 + expr2 1 + 2 → 3; 1.1 + 2.2 → 3.3
- Subtraction expr1 - expr2 1 - 2 → -1; 1.1 - 2.2 → -1.1
All the above operators are binary operators, i.e., they take two operands. The multiplication, division and
remainder take precedence over addition and subtraction. Within the same precedence level (e.g., addition and
subtraction), the expression is evaluated from left to right. For example, 1+2+3-4 is evaluated as ((1+2)+3)-4.
It is important to take note that int/int produces an int, with the result truncated, e.g., 1/2 → 0 (instead of 0.5).
Take note that C/C++ does not have an exponent (power) operator ('^' is exclusive-or, not exponent).
4.2 Arithmetic Expressions
In programming, the following arithmetic expression:
must be written as (1+2*a)/3 + (4*(b+c)*(5-d-e))/f - 6*(7/g+h). You cannot omit the multiplication
symbol '*' (as in Mathematics).
Like Mathematics, the multiplication '*' and division '/' take precedence over addition '+' and subtraction '-'.
Parentheses () have higher precedence. The operators '+', '-', '*', and '/' are left-associative. That is, 1 + 2 +
3 + 4 is treated as (((1+2) + 3) + 4).
4.3 Mixed-Type Operations
If both the operands of an arithmetic operation belong to the same type, the operation is carried out in that type,
and the result belongs to that type. For example, int/int → int; double/double → double .
However, if the two operands belong to different types, the compiler promotes the value of the smaller type to
the larger type (known as implicit type-casting). The operation is then carried out in the larger type. For
example, int/double → double/double → double . Hence, 1/2 → 0, 1.0/2.0 → 0.5, 1.0/2 → 0.5, 1/2.0 →
0.5.
For example,
4.4 Overflow/UnderFlow
Study the output of the following program:
This feature is an legacy design, where processors were slow. Checking for overflow/underflow consumes
computation power and reduces performance.
To check for arithmetic overflow (known as secure coding) is tedious. Google for "INT32-C. Ensure that operations
on signed integers do not result in overflow" @ www.securecoding.cert.org.
4.5 Compound Assignment Operators
Besides the usual simple assignment operator '=' described earlier, C++ also provides the so-called compound
assignment operators as listed:
Operator Usage Description Example
= var = expr Assign the value of the LHS to the x = 5;
variable at the RHS
+= var += expr same as var = var + expr x += 5; same as
x = x + 5
Operator Usage Description Example
-= var -= expr same as var = var - expr x -= 5; same as
x = x - 5
*= var *= expr same as var = var * expr x *= 5; same as
x = x * 5
/= var /= expr same as var = var / expr x /= 5; same as
x = x / 5
%= var %= expr same as var = var % expr x %= 5; same as
x = x % 5
4.6 Increment/Decrement Operators
C++ supports these unary arithmetic operators: increment '++' and decrement '--'.
Operator Example Result
++ x++; ++x Increment by 1, same as x += 1
-- x--; --x Decrement by 1, same as x -= 1
For example,
The increment/decrement unary operator can be placed before the operand (prefix operator), or after the operands
(postfix operator). They takes on different meaning in operations.
Operator Description Example Result
++var Pre-Increment y = same as x=x+1; y=x;
Increment var, then use the new value ++x;
of var
var++ Post-Increment y = same as oldX=x;
Use the old value of var, then x++; x=x+1; y=oldX;
increment var
--var Pre-Decrement y = -- same as x=x-1; y=x;
x;
var-- Post-Decrement y = x-- same as oldX=x; x=x-
; 1; y=oldX;
If '++' or '--' involves another operation, then pre- or post-order is important to specify the order of the two
operations. For examples,
x = 5;
cout << x++ << endl; // Save x (5); Increment x (=6); Print old x (5).
x = 5;
cout << ++x << endl; // Increment x (=6); Print x (6).
// This is confusing! Try to avoid! What is i=++i? What is i=i++?
Prefix operator (e.g, ++i) could be more efficient than postfix operator (e.g., i++) in some situations.
4.7 Implicit Type-Conversion vs. Explicit Type-Casting
Converting a value from one type to another type is called type casting (or type conversion). There are two kinds of
type casting:
1. Implicit type-conversion performed by the compiler automatically, and
2. Explicit type-casting via an unary type-casting operator in the form of (new-type)operand or new-
type(operand).
Implicit (Automatic) Type Conversion
When you assign a value of a fundamental (built-in) type to a variable of another fundamental type, C++
automatically converts the value to the receiving type, if the two types are compatible. For examples,
If you assign an int value to a double variable, the compiler automatically casts the int value to
a double double (e.g., from 1 to 1.0) and assigns it to the double variable.
if you assign a double value of to an int variable, the compiler automatically casts the double value to
an int value (e.g., from 1.2 to 1) and assigns it to the int variable. The fractional part would be truncated and
lost. Some compilers issue a warning/error "possible loss in precision"; others do not.
1/*
2 * Test implicit type casting (TestImplicitTypeCast.cpp)
3 */
4#include <iostream>
5#include <iomanip>
6using namespace std;
7
8int main() {
9 int i;
10 double d;
11
12 // print floating point number in fixed format with 1 decimal place
13 cout << fixed << setprecision(1);
14
15 i = 3;
16 d = i; // Assign an int value to double
17 cout << "d = " << d << endl; // 3.0
18
19 d = 5.5;
20 i = d; // Assign a double value to int
21 cout << "i = " << i << endl; // 5 (truncated, no warning!)
22
23 i = 6.6; // Assign a double literal to int
24 cout << "i = " << i << endl; // 6 (truncated, no warning!)
25}
C++ will not perform automatic type conversion, if the two types are not compatible.
Explicit Type-Casting
You can explicitly perform type-casting via the so-called unary type-casting operator in the form of (new-
type)operand or new-type(operand). The type-casting operator takes one operand in the particular type, and
returns an equivalent value in the new type. Take note that it is an operation that yields a resultant value, similar
to an addition operation although addition involves two operands. For example,
// Print floating-point number in fixed format with 1 decimal point (need <iomanip>)
cout << fixed << setprecision(1);
Example: Suppose that you want to find the average (in double) of the integers between 1 and 100. Study the
following codes:
1/*
2 * Testing Explicit Type Cast (Average1to100.cpp).
3 */
4#include <iostream>
5#include <iomanip>
6using namespace std;
7
8int main() {
9 int sum = 0;
10 double average;
11 for (int number = 1; number <= 100; ++number) {
12 sum += number; // Final sum is int 5050
13 }
14 average = sum / 100; // Won't work (average = 50.0 instead of 50.5)
15 cout << fixed << setprecision(1);
16 cout << "Average is " << average << endl; // Average is 50.0
17 return 0;
18}
You don't get the fractional part although the average is a double. This is because both the sum and 100 are int.
The result of division is an int, which is then implicitly casted to double and assign to the double variable average.
To get the correct answer, you can do either:
average = (double)sum / 100; // Cast sum from int to double before division
average = sum / (double)100; // Cast 100 from int to double before division
average = sum / 100.0;
average = (double)(sum / 100); // Won't work. why?
Example :
1/* Test Type Casting (TestTypeCast.cpp) */
2#include <iostream>
3#include <iomanip>
4using namespace std;
5
6int main() {
7 // Print floating-point number in fixed format with 1 decimal place
8 cout << fixed << setprecision(1);
9
10 // Test explicit type casting
11 int i1 = 4, i2 = 8;
12 cout << i1 / i2 << endl; // 0
13 cout << (double)i1 / i2 << endl; // 0.5
14 cout << i1 / (double)i2 << endl; // 0.5
15 cout << (double)(i1 / i2) << endl; // 0.0
16
17 double d1 = 5.5, d2 = 6.6;
18 cout << (int)d1 / i2 << endl; // 0
19 cout << (int)(d1 / i2) << endl; // 0
20
21 // Test implict type casting
22 d1 = i1; // int implicitly casts to double
23 cout << d1 << endl; // 4.0
24 i2 = d2; // double truncates to int! (Warning?)
25 cout << i2 << endl; // 6
26}
Example:
1/*
2 * Converting between Celsius and Fahrenheit (ConvertTemperature.cpp)
3 * Celsius = (5/9)(Fahrenheit–32)
4 * Fahrenheit = (9/5)Celsius+32
5 */
6#include <iostream>
7#include <iomanip> // needed for formatting floating-point numbers
8using namespace std;
9
10int main() {
11 double celsius, fahrenheit;
12
13 // Format floating-points in fixed with 2 decimal places
14 cout << fixed << setprecision(2);
15
16 cout << "Enter the temperature in celsius: ";
17 cin >> celsius;
18 fahrenheit = celsius*9/5 + 32;
19 // 9/5*celsius + 32 gives wrong answer! Why?
20 cout << celsius << "C is " << fahrenheit << "F" << endl;
21
22 cout << "Enter the temperature in fahrenheit: ";
23 cin >> fahrenheit;
24 celsius = (fahrenheit - 32)*5/9;
25 // 5/9*(fahrenheit - 32) gives wrong answer! Why?
26 cout << fahrenheit << "F is " << celsius << "C" << endl;
27 return 0;
28}
*Operator static-cast<type>
C++ introduces a new operator called static_cast<type> to perform type conversion (because the regular cast
mentioned earlier is too lax and could produce expected results). static_cast signal an error if conversion fails.
For example,
double d = 5.5;
int i = static_cast<int>(d);
float f = static_cast<float>(i);
long l = static_cast<logn>(d);
Exercise: Given the year, month (1-12), and day (1-31), write a boolean expression which returns true for dates
before October 15, 1582 (Gregorian calendar cut over date).
Ans: (year < 1582) || (year == 1582 && month < 10) || (year == 1582 && month == 10 && day < 15 )
5. Flow Control
There are three basic flow control constructs - sequential, conditional (or decision), and loop (or iteration), as
illustrated below.
5.1 Sequential Flow Control
A program is a sequence of instructions. Sequential flow is the most common and straight-forward, where
programming statements are executed in the order that they are written - from top to bottom in a sequential
manner.
5.2 Conditional (Decision) Flow Control
There are a few types of conditionals, if-then, if-then-else, nested-if (if-elseif-elseif-...-else), switch-case,
and conditional expression.
Syntax Example
"switch-case" is an alternative to the "nested-if". In a switch-case statement, a break statement is needed for each
of the cases. If break is missing, execution will flow through the following case. You can use either
an int or char variable as the case-selector.
Conditional Operator: A conditional operator is a ternary (3-operand) operator, in the form
of booleanExpr ? trueExpr : falseExpr. Depending on the booleanExpr, it evaluates and returns the value
of trueExpr or falseExpr.
Syntax Example
booleanExpr ? trueExpr : falseExpr cout << (mark >= 50) ? "PASS" : "FAIL" << endl;
// return either "PASS" or "FAIL", and put to cout
max = (a > b) ? a : b; // RHS returns a or b
abs = (a > 0) ? a : -a; // RHS returns a or -a
Braces: You could omit the braces { }, if there is only one statement inside the block. For example,
if (mark >= 50)
cout << "PASS" << endl; // Only one statement, can omit { } but not recommended
else { // more than one statements, need { }
cout << "FAIL" << endl;
cout << "Try Harder!" << endl;
}
However, I recommend that you keep the braces, even though there is only one statement in the block, to improve
the readability of your program.
Exercises
[TODO]
The difference between while-do and do-while lies in the order of the body and condition. In while-do,
the condition is tested first. The body will be executed if the condition is true and the process repeats. In do-while,
the body is executed and then the condition is tested. Take note that the body of do-while will be executed at least
once (vs. possibly zero for while-do).
Suppose that your program prompts user for a number between 1 to 10, and checks for valid input, do-while with
a boolean flag could be more appropriate.
// Input with validity check
bool valid = false;
int number;
do {
// prompt user to enter an int between 1 and 10
......
// if the number entered is valid, set done to exit the loop
if (number >=1 && number <= 10) {
valid = true;
}
} while (!valid); // Need a semi-colon to terminate do-while
// Game loop
bool gameOver = false;
while (!gameOver) {
// play the game
......
// Update the game state
// Set gameOver to true if appropriate to exit the game loop
......
}
Example (Counter-Controlled Loop): Prompt user for an upperbound. Sum the integers from 1 to a
given upperbound and compute its average.
1/*
2 * Sum from 1 to a given upperbound and compute their average (SumNumbers.cpp)
3 */
4#include <iostream>
5using namespace std;
6
7int main() {
8 int sum = 0; // Store the accumulated sum
9 int upperbound;
10 cout << "Enter the upperbound: ";
11 cin >> upperbound;
12
13 // Sum from 1 to the upperbound
14 for (int number = 1; number <= upperbound; ++number) {
15 sum += number;
16 }
17 cout << "Sum is " << sum << endl;
18 cout << "Average is " << (double)sum / upperbound << endl;
19
20 // Sum only the odd numbers
21 int count = 0; // counts of odd numbers
22 sum = 0; // reset sum
23 for (int number=1; number <= upperbound; number=number+2) {
24 ++count;
25 sum += number;
26 }
27 cout << "Sum of odd numbers is " << sum << endl;
28 cout << "Average is " << (double)sum / count << endl;
29}
Example (Sentinel-Controlled Loop): Prompt user for positive integers, and display the count,
maximum, minimum and average. Terminate when user enters -1.
1/* Prompt user for positive integers and display the count, maximum,
2 minimum and average. Terminate the input with -1 (StatNumbers.cpp) */
3#include <iostream>
4#include <climits> // for INT_MAX
5#include <iomanip> // for setprecision(n)
6using namespace std;
7
8int main() {
9 int numberIn; // input number (positive integer)
10 int count = 0; // count of inputs, init to 0
11 int sum = 0; // sum of inputs, init to 0
12 int max = 0; // max of inputs, init to minimum
13 int min = INT_MAX; // min of inputs, init to maximum (need <climits>)
14 int sentinel = -1; // Input terminating value
15
16 // Read Inputs until sentinel encountered
17 cout << "Enter a positive integer or " << sentinel << " to exit: ";
18 while (cin >> numberIn && numberIn != sentinel) {
19 // Check input for positive integer
20 if (numberIn > 0) {
21 ++count;
22 sum += numberIn;
23 if (max < numberIn) max = numberIn;
24 if (min > numberIn) min = numberIn;
25 } else {
26 cout << "error: input must be positive! try again..." << endl;
27 }
28 cout << "Enter a positive integer or " << sentinel << " to exit: ";
29 }
30
31 // Print result
32 cout << endl;
33 cout << "Count is " << count << endl;
34 if (count > 0) {
35 cout << "Maximum is " << max << endl;
36 cout << "Minimum is " << min << endl;
37 cout << fixed << setprecision(2);
38 // print floating point to 2 decimal places (need <iomanip>)
39 cout << "Average is " << (double)sum / count << endl;
40 }
41}
Program Notes
In computing, a sentinel value is a special value that indicates the end of data (e.g., a negative value to end a
sequence of positive value, end-of-file, null character in the null-terminated string). In this example, we use -
1 as the sentinel value to indicate the end of inputs, which is a sequence of positive integers. Instead of
hardcoding the value of -1, we use a variable called sentinel for flexibility and ease-of-maintenance.
Take note of the while-loop pattern in reading the inputs. In this pattern, you need to repeat the prompting
statement.
To control the precision of floating point numbers, use:
where n is the number of decimal places (after the decimal point). You need to include <iomanip> header.
The setprecision() is sticky. That is, it will remain in effect until another value is set.
Exercises
[TODO]
Try out the following program, which prints a 8-by-8 checker box pattern using nested loops, as follows:
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
1/*
2 * Print square pattern (PrintSquarePattern.cpp).
3 */
4#include <iostream>
5using namespace std;
6
7int main() {
8 int size = 8;
9 for (int row = 1; row <= size; ++row) { // Outer loop to print all the rows
10 for (int col = 1; col <= size; ++col) { // Inner loop to print all the columns of each r
11 cout << "# ";
12 }
13 cout << endl; // A row ended, bring the cursor to the next line
14 }
15
16 return 0;
17}
This program contains two nested for-loops. The inner loop is used to print a row of eight "# ", which is followed
by printing a newline. The outer loop repeats the inner loop to print all the rows.
Suppose that you want to print this pattern instead (in program called PrintCheckerPattern.cpp):
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
You need to print an additional space for even-number rows. You could do so by adding the following statement
before Line 8.
Exercises
1. Print these patterns using nested loop (in a program called PrintPattern1x). Use a variable called size for
the size of the pattern and try out various sizes. You should use as few printing statements as possible.
2. # * # * # * # * # # # # # # # # # # # # # # # # 1 1
3. # * # * # * # * # # # # # # # # # # # # # # 2 1 1
2
4. # * # * # * # * # # # # # # # # # # # # 3 2 1 1 2
3
5. # * # * # * # * # # # # # # # # # # 4 3 2 1 1 2 3
4
6. # * # * # * # * # # # # # # # # 5 4 3 2 1 1 2 3 4
5
7. # * # * # * # * # # # # # # 6 5 4 3 2 1 1 2 3 4 5
6
8. # * # * # * # * # # # # 7 6 5 4 3 2 1 1 2 3 4 5 6
7
9. # * # * # * # * # # 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7
8
Hints:
The equations for major and opposite diagonals are row = col and row + col = size + 1. Decide on what to
print above and below the diagonal.
10. Print the timetable of 1 to 9, as follows, using nested loop. (Hints: you need to use an if-else statement to
check whether the product is single-digit or double-digit, and print an additional space if needed.)
11. 1 2 3 4 5 6 7 8 9
12. 2 4 6 8 10 12 14 16 18
......
14. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
15. # # # # # # # # # #
16. # # # # # # # # # #
17. # # # # # # # #
18. # # # # # # # # # #
19. # # # # # # # # # #
20. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if ( i == 0) {
if (j == 0) cout << "i and j are zero" << endl;
} else {
cout << "i is not zero" << endl; // non-ambiguous for outer-if
}
}
This kind of errors is very serious if it is not caught before production. Writing good programs helps in
minimizing and detecting these errors. A good testing strategy is needed to ascertain the correctness of the
program. Software testing is an advanced topics which is beyond our current scope.
Debugging Programs
Here are the common debugging techniques:
1. Stare at the screen! Unfortunately, errors usually won't pop-up even if you stare at it extremely hard.
2. Study the error messages! Do not close the console when error occurs and pretending that everything is
fine. This helps most of the times.
3. Insert print statements at appropriate locations to display the intermediate results. It works for simple toy
program, but it is neither effective nor efficient for complex program.
4. Use a graphic debugger. This is the most effective means. Trace program execution step-by-step and watch
the value of variables and outputs.
5. Advanced tools such as profiler (needed for checking memory leak and function usage).
6. Proper program testing to wipe out the logical errors.
Testing Your Program for Correctness
How to ensure that your program always produces correct result, 100% of the times? It is impossible to try out all
the possible outcomes, even for a simple program. Program testing usually involves a set of representative test
cases, which are designed to catch the major classes of errors. Program testing is beyond the scope of this writing.
7. Strings
C++ supports two types of strings:
1. the original C-style string: A string is a char array, terminated with a NULL character '\0' (Hex 0). It is also
called Character-String or C-style string. C-string will be discussed later.
2. the new string class introduced in C++98.
The "high-level" string class is recommended, because it is much easier to use and understood. However, many
legacy programs used C-strings; many programmers also use "low-level" C-strings for full control and efficiency;
furthermore, in some situation such as command-line arguments, only C-strings are supported. Hence, you may
have to understand both sets of strings. However, avoid C-string unless it is absolutely necessary.
We shall describe string class here, and C-string later.
7.1 String Declaration and Initialization
To use the string class, include the <string> header and "using namespace std".
You can declare and (a) initialize a string with a string literal, (b) initialize to an empty string, or (c) initialize with
another string object. For example,
#include <string>
using namespace std;
NOTES:
We need to "#include <string>" to use the string class, and "using namespace std" as string is defined
under std namespace.
"cin >> aStr" reads a word (delimited by space) from cin (keyboard), and assigns to string variable aStr.
getline(cin, aStr) reads the entire line (up to '\n') from cin, and assigns to aStr. The '\n' character is
discarded.
To flush cin, you could use ignore(numeric_limits<streamsize>::max(), '\n') function to discard all the
characters up to '\n'. numeric_limits is in the <limits> header.
7.3 String Operations
Checking the length of a string:
int length();
int size();
bool empty();
string str1("Hello,");
string str2(" world");
cout << str1 + str2 << endl; // "Hello, world"
cout << str1 << endl; // "Hello,"
cout << str2 << endl; // " world"
str1 += str2;
cout << str1 << endl; // "Hello, world"
cout << str2 << endl; // " world"
string str3 = str1 + str2;
cout << str3 << endl; // "Hello, world world"
str3 += "again";
cout << str3 << endl; // "Hello, world worldagain"
str[0] = 'h';
cout << str << endl; // "hallo, world"
Extracting sub-string:
#include <algorithm>
......
string str("Hello, world");
replace(str.begin(), str.end(), 'l', '_');
cout << str << endl; // "He__o, wor_d"
Many others.
Example 1:
1/* Example on C++ string function (TestStringOp.cpp) */
2#include <iostream>
3#include <string> // use string class
4using namespace std;
5
6int main() {
7 string msg = "hello, world!";
8 cout << msg << endl;
9 cout << msg.length() << endl; // length of string
10 cout << msg.at(1) << endl; // char at index 1
11 cout << msg[1] << endl; // same as above
12 cout << msg.empty() << endl; // test for empty string
13 cout << msg.substr(3, 3) << endl; // sub-string begins at
14 // pos 3 of size 3
15 cout << msg.replace(3, 3, "why") << endl; // replace sub-string
16 cout << msg.append("end") << endl; // append behind
17 cout << msg + "end" << endl; // same as above
18 cout << msg.insert(3, "insert") << endl; // insert after pos 3
19
20 string msg1;
21 msg1 = msg; // copy
22 cout << msg1 << endl;
23
24 cout << "Enter a line: ";
25 getline(cin, msg); // read a line of input
26 cout << msg << endl;
27}
Example 2:
[TODO]
7.4 Exercises
[TODO]
8. Formatting Input/Output using IO Manipulators
(Header <iomanip>)
The <iomanip> header provides so-called I/O manipulators for formatting input and output:
setw(int field-widht): set the field width for the next IO operation. setw() is non-sticky and must be issued
prior to each IO operation. The field width is reset to the default after each operation (with just enough width
to accommodate the field).
setfill(char fill-char): set the filled character for padding to the field width.
left|right|internal: set the alignment
fixed/scientific (for floating-point numbers): use fixed-point notation (e.g, 12.34) or scientific notation
(e.g., 1.23e+006).
setprecision(int numDecimalDigits) (for floating-point numbers): specify the number of digits after the
decimal point.
boolalpha/noboolalpha (for bool): display bool values as alphabetic string (true/false) or 1/0.
8.1 Output Formatting
Example
1/* Test Formatting Output (TestFormattedOutput.cpp) */
2#include <iostream>
3#include <iomanip> // Needed to do formatted I/O
4using namespace std;
5
6int main() {
7 // Floating point numbers
8 double pi = 3.14159265;
9 cout << fixed << setprecision(4); // fixed format with 4 decimal places
10 cout << pi << endl;
11 cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
12 // setw() is not sticky, only apply to the next operation.
13 cout << setfill('-');
14 cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
15 cout << scientific; // in scientific format with exponent
16 cout << pi << endl;
17
18 // booleans
19 bool done = false;
20 cout << done << endl; // print 0 (for false) or 1 (for true)
21 cout << boolalpha; // print true or false
22 cout << done << endl;
23 return 0;
24}
8.3 Exercises
[TODO]
9. Arrays
9.1 Array Declaration and Usage
Suppose that you want to find the average of the marks for a class of 30 students, you certainly do not want to
create 30 variables: mark1, mark2, ..., mark30. Instead, You could use a single variable, called an array, with 30
elements.
An array is a list of elements of the same type, identified by a pair of square brackets [ ]. To use an array, you need
to declare the array with 3 things: a name, a type and a dimension (or size, or length). The syntax is:
type arrayName[arraylength]; // arraylength can be a literal or a variable
I recommend using a plural name for array, e.g., marks, rows, numbers. For example,
int marks[5]; // Declare an int array called marks with 5 elements
double numbers[10]; // Declare an double array of 10 elements
const int SIZE = 9;
float temps[SIZE]; // Use const int as array length
Take note that, in C++, the value of the elements are undefined after declaration.
You can also initialize the array during declaration with a comma-separated list of values, as follows:
This is another pitfall of C/C++. Checking the index bound consumes computation power and depicts the
performance. However, it is better to be safe than fast. Newer programming languages such as Java/C# performs
array index bound check.
1/*
2 * Find the mean and standard deviation of numbers kept in an array (MeanStdArray.cpp).
3 */
4#include <iostream>
5#include <iomanip>
6#include <cmath>
7#define SIZE 7
8using namespace std;
9
10int main() {
11 int marks[] = {74, 43, 58, 60, 90, 64, 70};
12 int sum = 0;
13 int sumSq = 0;
14 double mean, stdDev;
15 for (int i = 0; i < SIZE; ++i) {
16 sum += marks[i];
17 sumSq += marks[i]*marks[i];
18 }
19 mean = (double)sum/SIZE;
20 cout << fixed << "Mean is " << setprecision(2) << mean << endl;
21
22 stdDev = sqrt((double)sumSq/SIZE - mean*mean);
23 cout << fixed << "Std dev is " << setprecision(2) << stdDev << endl;
24
25 return 0;
26}
Exercises
[TODO]
9.6 Exercises
[TODO]
10. Functions
10.1 Why Functions?
At times, a certain portion of codes has to be used many times. Instead of re-writing the codes many times, it is
better to put them into a "subroutine", and "call" this "subroutine" many time - for ease of maintenance and
understanding. Subroutine is called method (in Java) or function (in C/C++).
area 1 is 3.63
area 2 is 14.52
area 3 is 32.67
In the above example, a reusable function called getArea() is defined, which receives a parameter (in double)
from the caller, performs the calculation, and return a piece of result (in double) to the caller. In the main(), we
invoke getArea() functions thrice, each time with a different parameter.
In C++, you need to declare a function prototype (before the function is used), and provide a function definition,
with a body containing the programmed operations.
Function Definition
The syntax for function definition is as follows:
A function prototype tells the compiler the function's interface, i.e., the return-type, function name, and the
parameter type list (the number and type of parameters). The function can now be defined anywhere in the file.
For example,
You could optionally include the parameter names in the function prototype. The names will be ignored by the
compiler, but serve as documentation. For example,
// Function Prototype
double getArea(double radius); // parameter names are ignored, but serve as documentation
int max(int number1, int number2);
Function prototypes are usually grouped together and placed in a so-called header file. The header file can be
included in many programs. We will discuss header file later.
Another Example
We have a function called max(int, int), which takes two int and return their maximum. We invoke
the max() function from the main().
1/* Testing max function (TestMaxFunction.cpp) */
2#include <iostream>
3using namespace std;
4
5int maximum(int, int); // Function prototype (declaration)
6
7int main() {
8 cout << maximum(5, 8) << endl; // Call maximum() with literals
9
10 int a = 6, b = 9, c;
11 c = maximum(a, b); // Call maximum() with variables
12 cout << c << endl;
13
14 cout << maximum(c, 99) << endl; // Call maximum()
15}
16
17// Function definition
18// A function that returns the maximum of two given int
19int maximum(int num1, int num2) {
20 return (num1 > num2) ? num1 : num2;
21}
The "void" Return Type
Suppose that you need a function to perform certain actions (e.g., printing) without a need to return a value to the
caller, you can declare its return-value type as void. In the function's body, you could use a "return;" statement
without a return value to return control to the caller. In this case, the return statement is optional. If there is
no return statement, the entire body will be executed, and control returns to the caller at the end of the body.
Actual Parameters vs. Formal Parameters
Recall that a function receives arguments from its caller, performs the actions defined in the function's body, and
return a value (or nothing) to the caller.
In the above example, the variable (double radius) declared in the signature of getArea(double radius) is
known as formal parameter. Its scope is within the function's body. When the function is invoked by a caller, the
caller must supply so-called actual parameters (or arguments), whose value is then used for the actual computation.
For example, when the function is invoked via "area1 = getArea(radius1)", radius1 is the actual parameter,
with a value of 1.1.
Scope of Function's Local Variables and Parameters
All variables, including function's parameters, declared inside a function are available only to the function. They
are created when the function is called, and freed (destroyed) after the function returns. They are called local
variables because they are local to the function and not available outside the function. They are also
called automatic variables, because they are created and destroyed automatically - no programmer's explicit action
needed to allocate and deallocate them.
Boolean Functions
A boolean function returns a bool value (of either true or false) to the caller.
Suppose that we wish to write a function called isOdd() to check if a given number is odd.
1/*
2 * Test Boolean function (BooleanfunctionTest.cpp).
3 */
4#include <iostream>
5using namespace std;
6
7// Function Prototype
8bool isOdd(int);
9
10int main() {
11 cout << boolalpha; // print bool as true or false
12 cout << isOdd(5) << endl; // true
13 cout << isOdd(6) << endl; // false
14 cout << isOdd(-5) << endl; // false
15}
16
17bool isOdd(int number) {
18 if (number % 2 == 1) {
19 return true;
20 } else {
21 return false;
22 }
23}
This seemingly correct codes produces false for -5, because -5%2 is -1 instead of 1. You may rewrite the condition:
The above code produces the correct answer, but is poor. For boolean function, you should simply return the
resultant bool value of the comparison, instead of using a conditional statement, as follow:
int main() {
int number = -9;
if (isEven(number)) { // Don't write (isEven(number) == true)
cout << "Even" << endl;
}
}
You should specify the default arguments in the function prototype (declaration). They can only be defined once
(one-definition rule), and cannot be repeated in the function definition.
Default argument is not absolutely necessary. The codes could be hard to maintain.
For example,
Example: Computing the Sum of an Array and Print Array's Contents
1/* Function to compute the sum of an array (SumArray.cpp) */
2#include <iostream>
3using namespace std;
4
5// Function prototype
6int sum(int array[], int size); // Need to pass the array size too
7void print(int array[], int size);
8
9// Test Driver
10int main() {
11 int a1[] = {8, 4, 5, 3, 2};
12 print(a1, 5); // {8,4,5,3,2}
13 cout << "sum is " << sum(a1, 5) << endl; // sum is 22
14}
15
16// Function definition
17// Return the sum of the given array
18int sum(int array[], int size) {
19 int sum = 0;
20 for (int i = 0; i < size; ++i) {
21 sum += array[i];
22 }
23 return sum;
24}
25
26// Print the contents of the given array
27void print(int array[], int size) {
28 cout << "{";
29 for (int i = 0; i < size; ++i) {
30 cout << array[i];
31 if (i < size - 1) {
32 cout << ",";
33 }
34 }
35 cout << "}" << endl;
36}
Array is passed into function by reference. That is, the invoked function works on the same copy of the array as
the caller. Hence, changes of array inside the function is reflected outside the function (i.e., side effect).
Why Arrays are Pass-by-Reference?
Array is designed to be passed by reference, instead of by value using a cloned copy. This is because passing huge
array by value is inefficient - the huge array needs to be cloned.
1/* Search an array for the given key using Linear Search (LinearSearch.cpp) */
2#include <iostream>
3using namespace std;
4
5int linearSearch(const int a[], int size, int key);
6
7int main() {
8 const int SIZE = 8;
9 int a1[SIZE] = {8, 4, 5, 3, 2, 9, 4, 1};
10
11 cout << linearSearch(a1, SIZE, 8) << endl; // 0
12 cout << linearSearch(a1, SIZE, 4) << endl; // 1
13 cout << linearSearch(a1, SIZE, 99) << endl; // 8 (not found)
14}
15
16// Search the array for the given key
17// If found, return array index [0, size-1]; otherwise, return size
18int linearSearch(const int a[], int size, int key) {
19 for (int i = 0; i < size; ++i) {
20 if (a[i] == key) return i;
21 }
22 return size;
23}
Program Notes:
[TODO]
Example: Sorting an Array using Bubble Sort
Wiki "Bubble Sort" for the detailed algorithm and illustration. In brief, we pass thru the list, compare two adjacent
items and swap them if they are in the wrong order. Repeat the pass until no swaps are needed. For example,
{8,4,5,3,2,9,4,1}
PASS 1 ...
{8,4,5,3,2,9,4,1} => {4,8,5,3,2,9,4,1}
{4,8,5,3,2,9,4,1} => {4,5,8,3,2,9,4,1}
{4,5,8,3,2,9,4,1} => {4,5,3,8,2,9,4,1}
{4,5,3,8,2,9,4,1} => {4,5,3,2,8,9,4,1}
{4,5,3,2,8,9,4,1} => {4,5,3,2,8,4,9,1}
{4,5,3,2,8,4,9,1} => {4,5,3,2,8,4,1,9}
PASS 2 ...
{4,5,3,2,8,4,1,9} => {4,3,5,2,8,4,1,9}
{4,3,5,2,8,4,1,9} => {4,3,2,5,8,4,1,9}
{4,3,2,5,8,4,1,9} => {4,3,2,5,4,8,1,9}
{4,3,2,5,4,8,1,9} => {4,3,2,5,4,1,8,9}
PASS 3 ...
{4,3,2,5,4,1,8,9} => {3,4,2,5,4,1,8,9}
{3,4,2,5,4,1,8,9} => {3,2,4,5,4,1,8,9}
{3,2,4,5,4,1,8,9} => {3,2,4,4,5,1,8,9}
{3,2,4,4,5,1,8,9} => {3,2,4,4,1,5,8,9}
PASS 4 ...
{3,2,4,4,1,5,8,9} => {2,3,4,4,1,5,8,9}
{2,3,4,4,1,5,8,9} => {2,3,4,1,4,5,8,9}
PASS 5 ...
{2,3,4,1,4,5,8,9} => {2,3,1,4,4,5,8,9}
PASS 6 ...
{2,3,1,4,4,5,8,9} => {2,1,3,4,4,5,8,9}
PASS 7 ...
{2,1,3,4,4,5,8,9} => {1,2,3,4,4,5,8,9}
PASS 8 ...
{1,2,3,4,4,5,8,9}
Program Notes:
[TODO]
Example: Sorting an Array using Insertion Sort
Wiki "Insertion Sort" for the algorithm and illustration. In brief, pass thru the list. For each element, compare with
all previous elements and insert it at the correct position by shifting the other elements. For example,
{8,4,5,3,2,9,4,1}
{8} {4,5,3,2,9,4,1}
{4,8} {5,3,2,9,4,1}
{4,5,8} {3,2,9,4,1}
{3,4,5,8} {2,9,4,1}
{2,3,4,5,8} {9,4,1}
{2,3,4,5,8,9} {4,1}
{2,3,4,4,5,8,9} {1}
{1,2,3,4,4,5,8,9}
Program Notes:
[TODO]
Example: Sorting an Array using Selection Sort
Wiki "Selection Sort" for the algorithm and illustration. In brief, Pass thru the list. Select the smallest element and
swap with the head of the list. For example,
{8,4,5,3,2,9,4,1}
{} {8,4,5,3,2,9,4,1} => {} {1,4,5,3,2,9,4,8}
{1} {4,5,3,2,9,4,8} => {1} {2,5,3,4,9,4,8}
{1,2} {5,3,4,9,4,8} => {1,2} {3,5,4,9,4,8}
{1,2,3} {5,4,9,4,8} => {1,2,3} {4,5,9,4,8}
{1,2,3,4} {5,9,4,8} => {1,2,3,4} {4,9,5,8}
{1,2,3,4,4} {9,5,8} => {1,2,3,4,4} {5,9,8}
{1,2,3,4,4,5} {9,8} => {1,2,3,4,4,5} {8,9}
{1,2,3,4,4,5,8,9}
Program Notes:
[TODO]
"const" Fundamental-Type Function Parameters?
You could also use const for fundamental-type function parameters (such as int, double) to prevent the
parameters from being modified inside the function. However, as fundamental-type parameters are passed by
value (with a cloned copy), there will never be side effect on the caller. We typically do not use the const keyword
for fundamental types. In other words, const is used to indicate that there shall NOT be side-effect.
10.8 Pass-by-Reference via "Reference" Parameters
As mentioned, parameters of fundamental types (such as int, double) are passed-by-value. That is, a clone copy is
used inside the function. Change to the cloned copy inside the function has no side-effect to the caller's copy.
Nonetheless, you can pass a fundamental type parameter by reference via the so-called reference
parameter denoted by &. For example,
1/* Test Pass-by-reference for fundamental-type parameter
2 via reference declaration (TestPassByReference.cpp) */
3#include <iostream>
4using namespace std;
5
6int squareByValue (int number); // Pass-by-value
7void squareByReference (int & number); // Pass-by-reference
8
9int main() {
10 int n1 = 8;
11 cout << "Before call, value is " << n1 << endl; // 8
12 cout << squareByValue(n1) << endl; // no side-effect
13 cout << "After call, value is " << n1 << endl; // 8
14
15 int n2 = 9;
16 cout << "Before call, value is " << n2 << endl; // 9
17 squareByReference(n2); // side-effect
18 cout << "After call, value is " << n2 << endl; // 81
19}
20
21// Pass parameter by value - no side effect
22int squareByValue (int number) {
23 return number * number;
24}
25
26// Pass parameter by reference by declaring as reference (&)
27// - with side effect to the caller
28void squareByReference (int & number) {
29 number = number * number;
30}
In function squareByReference(), we declare the parameter number is passed by reference by declaring its type
as int & (reference of int). In this way, the caller's copy is used inside the function (instead of a cloned copy in
pass-by-value). Changes inside the function has side-effect.
Pass-by-reference is NOT commonly used for fundamental types (such as int, double) - the above example is
purely meant for academic illustration. But it is used extensively for compound types (such as arrays and objects)
to avoid cloning huge data for better performance. We shall revisit pass-by-reference in Object-Oriented
Programming (OOP) chapters.
10.9 Mathematical Functions (Header <cmath>)
C++ provides many common-used Mathematical functions in library <cmath> (ported over from C's "math.h"). The
signatures of some of these functions are:
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x):
Take argument-type and return-type of float, double, long double.
atan2(y, x):
Return arc-tan of y/x. Better than atan(x) for handling 90 degree.
ceil(x), floor(x):
returns the ceiling and floor integer of floating point number.
1: 333109 (16.66%)
2: 333113 (16.66%)
3: 333181 (16.66%)
4: 333562 (16.68%)
5: 333601 (16.68%)
6: 333434 (16.67%)
As seen from the output, rand() is fairly uniformly-distributed over [0, RAND_MAX].
10.11 Exercises
[TODO]
Program Notes:
Once the file is opened, you can use >> and << for input and output, similar to cin >> and cout <<. (Advanced
note: ifstream is a subclass of istream, where cin belongs. ofstream is a subclass of ostream,
where cout belongs.)
Similarly, IO manipulators, such as fixed, setprecision() and setw(), work on the file streams.
11.2 Exercises
[TODO]
12. Namespace
When you use different library modules, there is always a potential for name crashes, as different library may use
the same name for different purposes. This problem can be resolved via the use of namespace in C++.
A namespace is a collection for identifiers under the same naming scope. (It is known as package in UML and Java.)
The entity name under a namespace is qualified by the namespace name, followed by :: (known as scope
resolution operator), in the form of namespace::entityName.
To place an entity under a namespace, use keyword namespace as follow:
// create a namespace called myNamespace for the enclosed entities
namespace myNameSpace {
int foo; // variable
int f() { ...... }; // function
class Bar { ...... }; // compound type such as class and struct
}
A namespace can contain variables, functions, arrays, and compound types such as classes and structures.
Namespace Example
1#include <iostream>
2
3namespace a { // contains variables
4 int i1 = 8;
5 int i2 = 9;
6}
7
8namespace b { // contains function
9 int max(int n1, int n2) {
10 return (n1 > n2) ? n1 : n2;
11 }
12}
13
14int main() {
15 std::cout << a::i1 << std::endl; // 8
16 std::cout << b::max(a::i1, a::i2) << std::endl; // 9
17}
Namespaces are opened. In other words, you can add more names into an existing namespace using
additional namespace definition.
Using Namespace
For example, all the identifiers in the C++ standard libraries (such as cout, endl and string) are placed under the
namespace called std. To reference an identifier under a namespace, you have three options:
1. Use the fully qualified names, such as std::cout, std::endl, std::setw() and std::string. For example,
Missing the "std::" results in "error: 'xxx' was not declared in this scope".
3. Use a using declaration to declare the particular identifiers. For example,
4. using std::cout;
5. using std::endl;
6. ......
7. cout << std::setw(6) << 1234 << endl;
You can omit the "std::" for cout and endl, but you still have to use "std::" for setw.
8. Use a using namespace directive. For example,
The using namespace directive effectively brings all the identifiers from the specified namespace to the
global scope, as if they are available globally. You can reference them without the scope resolution operator.
Take note that the using namespace directive may result in name crashes with identifier in the global scope.
12. For long namespace name, you could define a shorthand (or alias) to the namespace, as follows:
#include <iostream>
using namespace std; // std namespace is available to ALL
int main() {
using namespace std; // std namespace is available to main() only
.......
}
Note: you could use the C-style header "iostream.h" which does not use namespace to replace the first two lines
in the first sample.
Global Namespace
In C++, an entity (variable, function, or class) belongs to the global namespace (identified by :: with no namespace
name), if it is not enclose within a namespace declaration. For example, main() can be identified as ::main().
Link to "C++ References and Resources"
Latest version tested: Cygwin/MInGW GCC g++ 4.6.2
Last modified: June, 2013
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan
(ehchua@ntu.edu.sg) | HOME