This function takes an integer and returns its square.In the example above, the parameter n in Square is called a formal parameter, and the value 3 in Square called in main is called an
Trang 1In the examples above, it is not strictly necessary to surround the output statements with brackets However, it would be necessary in the case of several statements
In this book, brackets are always used The brackets and the code in between is called
if (i = 1) // Always true.
{
//
}
One way to avoid the mistake is to swap the variable and the value As a value can
be compared but not assigned, the compiler will issue an error message if you by mistake enter one equals sign instead of two signs
default statement can be omitted, and we can only have one default alternative However, it must not be placed at the end of the switch statement, even though it is considered good practice to do so
Trang 3Iteration Statements
Iteration statements iterate one statement (or several statements inside a block)
as long as certain condition is true The simplest iteration statement is the while
statement It repeats the statement as long as the given expression is true The
example below writes the numbers � to �0
We can also use the for statement, which is a more compact variant of the while statement It takes three expressions, separated by semicolons In the code below, the first expression initializes the variable, the repetition continues as long as the second expression is true, and the third expression is executed at the end of each repetition
for (int i = 1; i <= 10; ++i)
Trang 4for (int i = 1; i <= 10; ++i)
Trang 5The goto statement is, however, considered to give rise to unstructured code,
so called "spaghetti code" I strongly recommend that you avoid the goto
statement altogether
Expression Statements
An expression can form a statement
a = b + 1; // Assignment operator.
cout << "Hello, World!"; // Stream operator.
WriteNumber(5); // Function call.
In the above examples, we are only interested in the side effects; that a is assigned a new value or that a text or a number is written We are allowed to write expression statements without side effects; even though it has no meaning and it will probably
be erased by the compiler
a + b * c;
Functions
A function can be compared to a black box We send in information (input) and we
receive information (output) In C++, the input values are called parameters and the output value is called a return value The parameters can hold every type, and the
return value can hold every type except the array
Trang 6To start with, let us try the function Square This function takes an integer and returns its square.
In the example above, the parameter n in Square is called a formal parameter, and the
value 3 in Square called in main is called an actual parameter.
Let us try a more complicated function, SquareRoot takes a value of double type and returns its square root The idea is that the function iterates and calculates increasingly better root values by taking the mean value of the original value divided with the current root value and the previous root value The process continues until the difference between two consecutive root values has reached an acceptable tolerance Just like main, a function can have local variables dRoot and dPrevRoot
hold the current and previous value of the root, respectively
#include <iostream>
using namespace std;
double SquareRoot(double dValue)
{
const double EPSILON = 1e-12;
double dRoot = dValue, dOldRoot = dValue;
while (true)
{
dRoot = ((dValue / dRoot) + dRoot) / 2;
cout << dRoot << endl;
if ((dOldRoot - dRoot) <= EPSILON)
Trang 7void PrintSign(int iValue)
There is no problem if the execution of a void function reaches the end of the code,
it just jumps back to the calling function However, a non-void function shall always return a value before reaching the end of the code The compiler will give a warning
if it is possible to reach the end of a non-void function
Local and Global Variables
There are four kinds of variables Two of them are local and global variables, which
we consider in this section The other two kinds of variables are class fields and exceptions, which will be dealt with in the class and exception sections of the
next chapter
Trang 8A global variable is defined outside a function and a local variable is defined inside
cout << "Global variable: " << iGlobal // 1
<< ", Local variable: " << iLocal // 2
<< endl;
}
A global and a local variable can have the same name In that case, the name in the function refers to the local variable We can access the global variable by using two colons (::)
int iNumber = 1;
void main()
{
int iNumber = 2;
cout << "Global variable: " << ::iNumber // 1
<< ", Local variable: " << iNumber; // 2
cout << "Global variable: " << ::iNumber // 1
<< ", Local variable: " << iNumber; // 3
}
}
Trang 9Global variables are often preceded by g_ in order to distinguish them from local variables.
int g_iNumber = 1;
void main()
{
int iNumber = 2;
cout << "Global variable: " << g_iNumber // 1
<< ", Local variable: " << iNumber; // 3
}
Call-by-Value and Call-by-Reference
Say that we want to write a function for switching the values of two variables
int iNum1 = 1, iNum2 = 2;
cout << "Before: " << iNum1 << ", " << iNum2 << endl;
Swap(iNum1, iNum2);
cout << "After: " << iNum1 << ", " << iNum2 << endl;
}
Unfortunately, this will not work; the variables will keep their values The
explanation is that the values of iFirstNum and iSecondNum in main are copied into
iNum1 and iNum2 in Swap Then iNum1 and iNum2 exchange values with the help if
iTemp However, their values are not copied back into iFirstNum and iSecondNum
in main
Trang 10The problem can be solved with reference calls Instead of sending the values of the
actual parameters, we send their addresses by adding an ampersand (&) to the type
As you can see in the code, the Swap call in main is identical to the previous one without references However, the call will be different
int iFirstNum = 1, iSecondNum = 2;
cout << "Before: " << iFirstNum << ", " << iSecondNum
Trang 11In this case, we do not send the values of iFirstNum and iSecondNum, but rather their addresses Therefore, iNum1 and iNum2 in Swap does in fact contain the
addresses of iFirstNum and iSecondNum of main As in the reference section above,
we illustrate this with dashed arrows Therefore, when iNum1 and iNum2 exchange values, in fact the values of iFirstNum and iSecondNum are exchanged
A similar effect can be obtained with pointers instead of references In that
case, however, both the definition of the function as well as the call from main are different
int iFirstNum = 1, iSecondNum = 2;
cout << "Before: " << iFirstNum << ", " << iSecondNum
Trang 12In this case, pNum1 and pNum2 are pointers, and therefore drawn with continuous lines Apart from that, the effect is the same.
Default Parameters
A default parameter is a parameter that will be given a specific value if the call does not include its value In the example below, all three calls are legitimate In the first call, iNum2 and iNum3 will be given the values 9 and 99, respectively; in the second call, iNum3 will be given the value 99 Default values can only occur from the right
in the parameter list; when a parameter is given a default value, all the following parameters must also be given default values
cout << Add(1) << endl; // 1 + 9 + 99 = 109
cout << Add(1, 2) << endl; // 1 + 2 + 99 = 102
cout << Add(1, 2 ,3) << endl; // 1 + 2 + 3 = 6
}
Trang 13Several different functions may be overloaded, which means that they may have
the same name as long as they do not share exactly the same parameter list C++
supports context-free overloading, the parameter lists must differ, it is not enough
to let the return types differ The languages Ada and Lisp support context-dependent
overloading, two functions may have the same name and parameter list as long as they have different return types
cout << Add(1) << endl; // 1
cout << Add(1, 2) << endl; // 1 + 2 = 3
cout << Add(1, 2 ,3) << endl; // 1 + 2 + 3 = 6
}
Static Variables
In the function below, iCount is a static local variable, which means that it is initialized when the execution of the program starts It is not initialized when the function is called
Trang 14If iCount was a regular local variable (without the keyword static), the function would at every call write that the function has been called once as iCount would be initialized to zero at every call.
The keyword static can, however, also be used to define functions and global variables invisible to the linker and other object files.invisible to the linker and other object files.nvisible to the linker and other object files
Recursion
A function may call itself; it is called recursion In the following example, the
mathematical function factorial (n!) is implemented It can be defined in two ways
The first definition is rather straightforward The result of the function applied to a
positive integer n is the product of all positive integers up to and including n.
int Factorial(int iNumber)
An equivalent definition involves a recursive call that is easier to implement
int Factorial(int iNumber)
Trang 15Definition and Declaration
It's important to distinguish between the terms definition and declaration For a
function, its definition generates code while the declaration is merely an item of
information to the compiler A function declaration is also called a prototype.
When it comes to mutual recursion (two functions calling each other), at least the second of them must have a prototype to avoid compiler warnings I recommend that you put prototypes for all functions at the beginning of the file In the following example, we use two functions to decide whether a given non-negative integer is even or odd according to the following definitions
bool Even(int iNum);
bool Odd(int iNum);
bool Even(int iNum)
Trang 16If we use prototypes together with default parameters, we can only indicate the default value in the prototype, not in the definition.
Higher Order Functions
A function that takes another function as a parameter is called a higher order function
Technically, C++ does not take the function itself as a parameter, but rather a pointer
to the function However, the pointer mark (*) may be omitted The following example takes an array of the given size and applies the given function to each integer in the array
Trang 17// Doubles every value in the array.
ApplyArray(numberArray, iArraySize, Double);//2,4,6,8,10
PrintArray(numberArray, iArraySize);
// Squares every value in the array.
ApplyArray(numberArray, iArraySize, Square);//4,16,36,64,100
PrintArray(numberArray, iArraySize);
}
One extra point in the example above is the method of finding the size of an array;
we divide the size of the array with the size of its first value This method only works
on static arrays, not on dynamically allocated arrays or arrays given as parameters to functions A parameter array is in fact converted to a pointer to the type of the array The following two function definitions are by definition equivalent
void PrintArray(int intArray[], int iSize)
The main() Function
The main program is in fact a function; the only special thing about it is that it is the start point of the program execution Just like a regular function it can have
formal parameters and return a value However, the parameter list must have a
special format The first parameter iArgCount is an integer indicating the number of arguments given by the system The second parameter vpValues (vp stands for vector
of pointers) holds the arguments It is an array of pointers to characters, which can
be interpreted as an array of strings, holding the system arguments However, the first value of the array always holds the path name of the program In some tutorials, the traditional parameter names argc and argv are used instead iArgCount and
vpValues The program below writes its path name and its arguments
#include <iostream>
using namespace std;
int main(int iArgCount, char* vpValues[])
Trang 18cout << "Path name: " << vpValues[0] << endl;
The arguments can be input from the command prompt
The return value of the main function can (besides void) only be signed or unsigned int The return value is often used to return an error code to the operating system; usually, zero indicates ok and a negative value indicates an error The program below tries to allocate a large chunk of memory It returns zero if it turns out well, minus one otherwise
#include <cstdlib>
int main()
{
const int BLOCK_SIZE = 7FFFFFFF;
void* pBlock = new (nothrow) char[BLOCK_SIZE];
The preprocessor is a tool that precedes the compiler in interpreting the code The
#include directive is one of its parts It opens the file and includes its text So far,
we have only included system header files, whose names are surrounded by arrow brackets (< and >) Later on, we will include our own header files Then we will use parentheses instead of arrow brackets The difference is that the preprocessor looks for the system header files in a special system file directory while it looks for our
Trang 19Another part of the preprocessor is the macros There are two kinds: with or without
parameters A macro without parameters works like a constant
#define ARRAY_SIZE 256
int arr[ARRAY_SIZE];
The predefined macros DATE , TIME , FILE , and LINE holds today's date, the current time, the current line number, and the name of the
file, respectively
Macros with parameters act like functions with the difference being that they do not perform any type checking, they just replace the text A macro is introduced with the
#define directive and is often written with capitals
#define ADD(a, b) ((a) + (b))
cout << ADD(1 + 2, 3 * 4) << endl; // 15
One useful macro is assert, it is defined in the header file cassert It takes a
logical parameter and exits the program execution with an appropriate message
if the parameter is false exit is a standard function that aborts the execution of the program and returns an integer value to the operating system When a macro definition stretches over several lines, each line except the last one must end with
a backslash
#define assert(test) \
{ \
if (!(test)) \
{ \
cout << "Assertion: \"" << #test << "\" on line " \ << LINE << " in file " << FILE << "."; \ ::exit(-1); \
} \
}
In the error handling section of the next chapter, we will define an error checking macro displaying the error message in a message box
It is also possible to perform conditional programming by checking the value of
macros In the following example, we define a system integer according to the underlying operating system
#ifdef WINDOWS
#define SYSINT int
#endif
#ifdef LINUX
#define SYSINT unsigned int
#endif
Trang 21Let's revise the points quickly in brief as discussed in this chapter:
The text of a program is called its source code It is translated into target code by the compiler The target code is then linked to target code of other programs, finally resulting in executable code.
The basic types of C++ can be divided into the integral types char, short int, int, and long int, and the floating types float, double, and long double The integral types can also be signed or unsigned.
Values of a type can be organized into an array, which is indexed by an integer The first index is always zero An enum value is an enumeration of named values It is also possible to define new types with typedef, though that
feature should be used carefully
A pointer holds the memory address of another value There are operators to
obtain the value pointed at and to obtain the address of a value A reference
is a simpler version of a pointer A reference always holds the address of a specific value while a pointer may point at different values A pointer
can also be used to allocate memory dynamically; that is, during the
program execution
The operators can be divided into the arithmetic operators addition,
subraction, multiplication, division, and modulo; the relational operators equal to, not equal to, less than, less than or equal to, greater than, and greater than or equal to; the logical operators not, and, and or; the bitwise operators inverse, and, or, and xor; the assignment operators, and the condition operator There is also the operator sizeof, which gives the size in bytes of values of a certain type The statments of C++ can divided into the selection statements if and switch, the iteration statements while and for, and the jump statements break, continue, and goto, even thought goto should be avoided.
A function may take one or more formal parameters as input When it is called,
a matching list of actual parameters must be provided A function may also
return a value of arbitrary type, with the exception of array Two functions
may be overloaded, which means they have the same name, as long as they
differ in their parameter lists A function may call itself, directly or indirectly;
this is called recursion A function can also have default parameters, which
means that if the caller does not provide enough parameters, the missing parameters will be given the default values
A macro is a textual substitution performed by the preprocessor before the
compilation of the program Similar to functions, they may take parameters
We can also include the text of other files into our program Finally, we can
include and exclude certain parts of the code by conditional programming.