NETB201 Data Structures
Chapter 1: Basic C++ Programming
1.1 Basic C++ Programming
Elements
1.1.1 A Simple C++ Program
#include <stdlib>
#include <iostream>
int main()
{ int x, y;
std::cout << "Please enter two numbers: ";
std::cin >> x >> y; // input stream
int sum = x + y;
std::cout << "Their sum is " << sum << std::endl;
return EXIT_SUCCESS;
}
Highlighting the C++ Elements
- header files
- function body
- standard output stream std::cout
- standard input stream
std::cin
- standard error stream std::cerr
-
using namespace std;
-- operator - as an element of a programming language (+, =, ==)
-- operation - as an action or a state (addition,
assignment, equal)
1.1.2 Fundamental Types
bool
char
short
int
long
float
double
enum |
true, false
character - 'A'
short integer
integer
long integer
single-precision
floating-point number
double-precision
floating-point number
enumeration - a set of
discrete values
|
bool,
char,
int
and enum
are called integral types.
void
indicates the absence
of any type information (only for function type).
Characters
A char variable
holds a single character - usually 8 bits. A literal is a constant value
appearing in the program.
'a', 'Q', '+', '\n', '9' are literals.
Each character is associated with an integer code, usually ASCII
code.
cout << 'a' << int('a') << static_cast<int>('a');
Integers
2 bytes <= sizeof(short)
<= sizeof(int)
<= sizeof(long)
and
sizeof(long)
>= 4
bytes
-
long constant: 123456789L
-
octal (base 8)
integer constant (using digits 0,1,2,3,4,5,6,7): 0273
-
hexadecimal
(base
16) integer constant (using digits 0,..9, A, B, C, D, E, F): 0xA05
Enumerations
An enumeration is a user-defined type that can hold any of a set of
discrete values.
enum Color { RED, GREEN, BLUE }; // default values are 0, 1, 2
enum Week { MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
// values are 1, 2, 3, .., 7
enum Mood { HAPPY = 3, SAD = 1, ANXIOUS = 4, SLEEPY = 2 };
Color skyColor = BLUE;
Mood myMood = SLEEPY;
Week day = TUESDAY;
Floating Point
-- double constants: 1.5402,
1.2E8, -2.25e-3, 1e5 (12-14 decimal digits)
-- float constants: 1.23f,
6f,
1.234F, 23e-2F (6-8 decimal digits)
1.1.3 Pointers, Arrays, and
Structures
Pointers
Each variable is stored in the computer's memory at some location,
or
address. A pointer holds the
value of such an address.
The address-of operator,
&
returns the address of a variable.
Accessing the object addressed by a pointer is called dereferencing, and is done using
*
operator.
char ch = 'Q';
char* p = &ch; // p holds the address of ch
cout << *p; // outputs the character 'Q'
ch = 'Z'; // ch now holds 'Z'
cout << *p; // outputs the character 'Z'
Arrays
An array is a collection of
elements of the same type.
double f[3]; // array of 3 doubles f[0], f[1], f[2]
double* p[10]; // array of 10 double pointers p[0]..p[9]
f[2] = 2.5;
p[4] = &f[2]; // p[4] points to f[2]
cout << *p[4]; // outputs 2.5
int a[] = { 10, 11, 12, 13 }; // initialization
int b[20] = { 0 }; // initialize all elements with value 0
C++ provides no build-in
runtime checking for array subscripting out of bounds [common
programming error]!
Pointers and Arrays
The name of an array can be used as a pointer to the array's initial
element and vice versa.
char c[] = {'c', 'a', 't'};
char* p = c; // p points to c[0]
char* q = &c[0]; // q also points to c[0]
cout << c[2] << p[2] << q[2]; // outputs "ttt"
Given two arrays c and
d, the comparison c == d does not test whether the contents
of
the two arrays are equal.
Strings in C++
#include<string>;
using std::string;
//...
string s = "to be";
string t = "not " + s; // t := "not to be"
string u = s + " or " + t; // u := "to be or not to be"
if (s > t) cout u;
//...
s = "John";
int i = s.size(); // i = 4
char c = s[3]; // c = 'n'
s += " Smith"; // s = "John Smith"
char *p = s.c_str(); // p is a C-style string
C-Style Structures
A structure is useful for storing an aggregation of elements. The
elements (members or fields) may be of different
types.
enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN }; struct Passenger { string name; // "John Smith" MealType mealPref; // LOW_FAT bool isFreqFlyer; // true string freqFlyerNo; // "293145" };
|
This defines a new type called Passenger.
The individual member of the structure variable (object) are
accepted
using the member selection
(dot) operator, which has the form struct_variable.member.
Passenger pass = { "John Smith", LOW_FAT, true, "293145" }; pass.name = "Pocahontas"; // change name pass.mealPref = VEGETARIAN; // change meal preference
|
This is C-style structure. In general, structures and classes in C++
provide a much wider range of capabilities than what is possible in
C-style structures (member functions, access control, etc).
Pointers, Dynamic Memory, and
the new Operator
The C++ runtime system reserves a large block of memory called free memory (dynamic memory or heap memory).
The operator new
dynamically allocates the correct amount of storage for an object of
a
given type from the free storage and returns a pointer to this
object.
Passenger *p; //... p = new Passenger; // p points the new Passenger p->name = "Pocahontas"; // member selection(arrow) operator p->mealPref = VEGETARIAN; // change meal preference p->isFreqFlyer = false; p->freqFlyerNo = "NONE"; //... delete p;
|
This new passenger object continuous to exist in the free store
until
it is explicitly deleted.
Memory Leaks
If an object is allocated with
new,
it should be eventually be deallocated with delete.
char* buffer = new char[500];
//...
delete buffer; // ERROR: delete only the fist element buffer[0]
Having inaccessible objects in dynamic memory is called memory leak.
char* buffer = new char[500];
//...
delete [] buffer; // delete all elements
1.1.4 Scope and Namespaces
Constants and typedef
Good programmers commonly like to associate names with constant
quantities.
const double PI = 3.14159265;
const int CUT_OFF[] = {90, 80, 70, 60};
const int N_DAYS = 7;
const int N_HOURS = 24*N_DAYS;
int counter[N_HOURS];
It is often useful to associate a name with a type:
typedef char* BufferPtr; // type BufferPtr is a pointer to char
typedef double Coordinate; // type Coordinate is a double
//...
BufferPtr p; // p is a pointer to a char
Coordinate x, y; // x and y are of type double
Local and Global Scopes
The portion of a program, from which a given name is accessible are
called its scope.
const int cat = 1; // global cat
int main()
{
const int cat = 2; // local cat (to main)
cout << cat; // outputs 2
return 0;
}
int dog = cat; // dog = 1 (from global cat)
Namespaces
A namespace is a mechanism
that
allows a group of related names to be defined in one place.
namespace myglobals {
int cat;
string dog = "bow wow";
}
int d = myglobals::cat;
We can access an object x
in namespace group,
using
the notation group::x,
which is called fully qualified
name.
namespace.cpp
The Using Statement
using std::cout;
using myglobals::cat;
or
using namespace std;
using namespace myglobals;
1.2 Expressions
An expression combines variables and literals with operators to
create
new values.
Member Selection and Indexing
Let
-
class_name
denote the name of a structure or class;
-
member
denote a member (or field) of this structure or class;
-
pointer
denote a pointer to a structure or class;
-
array
denote an array or a pointer to the first element of an array;
-
exp
to denote an expression (rvalue),
an expression combines variables and literals with operators to
create
new values.
Operators (lvalue):
class_name.member |
class/structure member
selection
|
dot (member selection)
operator |
pointer->member
|
class/structure member
selection |
arrow operator
|
array[exp]
|
array subscripting
|
index (subscript) operator
|
Arithmetic Operators
Binary arithmetic operators (rvalue):
exp + exp
|
addition
|
exp - exp |
subtraction
|
exp * exp |
multiplication
|
exp / exp |
division
|
exp % exp |
modulo (remainder)
|
Unary operators: +x and -x
Increment and Decrement
Operators
-
var
to denote a variable or anything to which a value may be
assigned (lvalue);
var ++
|
post increment
|
var --
|
post decrement
|
++ var |
pre increment |
-- var |
pre decrement |
int a[] = { 0, 1, 2, 3 };
int i = 2;
int j = i++; // j = 2 and then i = 3
int k = --i; // i = 2 and then k = 2
cout << a[k++]; // a[2] (=2) is output; then k = 3
Relational and Logical
Operators
Comparison operators:
exp < exp
|
less than
|
exp > exp |
greater than
|
exp <= exp |
less than or equal to
|
exp >= exp |
greater than or equal to |
exp == exp |
equal to
|
exp != exp |
not equal to
|
These returns a boolean value - true
or false.
Logical operators:
! exp
|
logical not |
exp && exp |
logical and |
exp || exp |
logical or |
exp != exp |
not equal to
|
exp can be a logical or
arithmetic expression (0 means false,
nonzero means true)
Bitwise Operators
~ exp
|
bitwise complement, ex.
|
~100010
->
011101 |
exp & exp |
bitwise and (conjunction),
ex.
|
1001
&& 1100 -> 1000 |
exp ^ exp |
bitwise exclusive-or
|
1001
^
1100 -> 0101
|
exp | exp |
bitwise or (disjunction)
|
1001
|
1100 -> 1101
|
exp << exp |
shift left |
11001
<< 1 -> 10010
|
exp >> exp |
shift right
|
11001
>> 1 -> 01100
|
Assignment Operators
Arithmetic operators (+, -, *, /, % )
and
bitwise binary operators (&,
^,
|, <<, >>) combine with assignment.
int i = 10;
int j = 5;
int k = 1;
i -= 4; // i = i - 4; result 6
j *= -2; // j = j * (-2); result -10
k <<= 1; // k = k << 1; result 2
Other Operators
class_name :: member
|
class scope resolution
|
namespace_name ::
member |
namespace scope resolution |
exp ? exp : exp
|
conditional expression
|
stream >> var
|
input stream (overloaded)
|
stream << exp
|
output stream (overloaded)
|
Operator Precedence
Operators in C++ are
assigned a
precedence, which determines the
order in which operations are performed in the absence of
parentheses.
Operator |
Description |
Associativity |
:: |
scope |
Left |
() [ ] -> . sizeof |
|
Left |
++ -- |
increment, decrement |
Right |
~ |
bitwise complement
|
! (not)
|
unary NOT |
& * |
reference and dereference
|
..._cast, (type)
|
type casting |
+ - |
unary + and -
|
* / % |
arithmetic operators |
Left |
+ - |
addition, subtraction |
Left |
<< >> |
bitwise shifts
|
Left |
< <= > >= |
relational operators |
Left |
== != |
relational operators |
Left |
&
|
bitwise and
|
Left |
^ |
bitwise exclusive-or |
Left |
| |
bitwise or
|
Left |
&& (and)
|
logical operator and
|
Left |
|| (or)
|
logical operator or
|
Left |
?: |
conditional operator
|
Left |
= += -= *= /= %=
>>= <<= &= ^= |= |
assignment operators
|
Right |
, |
comma, separator |
Left |
int a = 10, b, c, d;
// right associativity
d = c = b = a; // is equivalent to d = (c = (b = a));
// left associativity
d - c + b - a; // is equivalent to ((d - c) + b) - a;
// precedence
d > c && -b <= a // is equivalent to (d > c) && ((-b) <= a)
1.2.1 Casting in Expressions
Casting is an operation that allows us to change the type of a
variable.
Traditional C-Style Casting
-
(T)exp - C-style
cast
-
exp(T) -
functional-style cast
int cat = 14;
double dog = (double)cat;
double pig = double(cat);
Explicit Cast Operators
Casting operations can vary from harmless to dangerous, depending on
how similar the two types are and whether the information is lost.
-
short to int - harmless
-
double to int - dangerous (the
fractional
part of the number is lost)
-
double* to char* - dangerous
(depends of
the compiler, OS, hardware)
The standard of C++ supports
4
casting versions (operators):
- static_cast
- dynamic_cast
- const_cast
- reinterpret_cast
using the notation: some_cast<T>(exp).
Static Casting
static_cast<T>(exp)
int cat = 14;
double dog = static_cast<double>(cat); // dog := 14.0
double lion = 155.99;
int pig = static_cast<int>(lion); // pig := 155
Implicit Casting
There are many instances where the programmer has not requested an
explicit case, but a change of types is required. In many of these
cases, C++ will perform an implicit cast. That is, the compiler will
automatically insert a cast into the machine-generated code - the
compiler automatically casts to the stronger type (without loss of
information).
char - short - int - long -?
float - double
1.3 Control Flow
if (<condition>)
<operator>;
if (<condition>)
<operator1>; else
<operator2>;
while(<condition>)
<opetator>;
do <operator>; while(<condition>);
for ([<initialization>];
[<condition>]; [<increment>]) <operator>;
for ([<expression1>];
[<expression2>]; [<expression3>]) <operator>;
return [<expression>];
1.4 Functions
1.4.1 Argument Passing
1.4.2 Overloading
Function Overloading
Function overloading occurs when two or more functions are defined
with
the same name but different
argument lists.
void print(int x)
{ cout << x; }
void print(const Passenger &pass) { cout << pass.name << " " << pass.mealPref; if (pass.isFreqFlyer) cout << pass.freqFlyerNo; }
|
Operator Overloading
The equality test for two Passenger
objects:
bool operator==(const Passenger &x, const Passenger &y) { return x.name == y.name && x.mealPref == y.mealPref && x.isFreqFlyer == y.isFreqFlyer && x.freqFlyerNo == y.freqFlyerNo; }
|
Using Overloading
ostream& operator<<(ostream &out, const Passenger &pass) { out << pass.name << " " << pass.mealPref; if (pass.isFreqFlyer) out << pass.freqFlyerNo; return out; } //... Passenger pass1 = // details omitted Passenger pass2 = // details omitted cout << pass1 << pass2 << endl;
|
1.5 Classes
1.5.1 Class Structure
A class consists of members. Members that are variable or constants
are
data members (member
variables)
and members that are functions are called member functions (methods).
Access Control
Members may be declared to be public,
which means that they are accessible form outside the class, or private, which means that they
are
accessible only from within
the class. The keywords public
and private
are access specifiers,
the default is private.
Member Functions
enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN }; class Passenger { private: string name; // "John Smith" MealType mealPref; // LOW_FAT bool isFreqFlyer; // true string freqFlyerNo; // "293145" public: Passenger(); // default constructor bool isFreqFlyer() const; // accessor function void makeFreqFlyer(const string &newFreqFlyerNo); // update (mutator) function }; // ... bool Passenger::isFreqFlyer() const { return isFreqFlyer; } void Passenger::makeFreqFlyer(const string &newFreqFlyerNo) { isFreqFlyer = true; freqFlyerNo = newFreqFlyerNo; } //... Passenger pass; //... if (!pass.isFreqFlyer()) // OK pass.makeFreqFlyer("999999"); // OK pass.name = "Joe Blow"; // ERROR: private member
|
In-Class Function Definition
enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN }; class Passenger { private: string name; // "John Smith" MealType mealPref; // LOW_FAT bool isFreqFlyer; // true string freqFlyerNo; // "293145" public: Passenger(); bool isFreqFlyer() const { return isFreqFlyer; } void makeFreqFlyer(const string &newFreqFlyerNo) { isFreqFlyer = true; freqFlyerNo = newFreqFlyerNo; } };
|
1.5.2
Constructors and
Destructors
1.5.3 Classes and Memory
Allocation
1.5.4 Class Friends and Class
Members
class Matrix; // Matrix definition comes later
class Vector { // a 3-element vector
private:
double coord[3];
public:
// ...
friend class Matrix; // allow Matrix access to coord
};
class Matrix { // a 3x3 array
private:
double a[3][3];
public:
// ...
Vector multiplyBy(const Vector& v) { // multiply (a * v)
Vector w(0, 0, 0);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
w.coord[i] += a[i][j] * v.coord[j]; // access private data
return w;
}
};
Nesting Classes and Types
within
Classes
Classes may contain member variables, member functions and types. We
can nest a class definition within another class.
class Complex {
private:
class Node {
// ...
};
//...
};
1.5.5 The Standard Template
Library
Templates and the STL Vector
Class
The Standard Template Library (STL) is a collection of useful
classes
for common data structures.
Standard containers:
stack
|
Container with last-in,
first-out access
|
queue
|
Container with first-in,
first-out access |
deque
|
Double-ended queue
|
vector
|
Resizeable array
|
list
|
Doubly linked list
|
priority_queue
|
Queue ordered by value
|
set,
multiset
|
Set
|
map,
multimap
|
Associative array
(dictionary)
|
Each STL-class object can store objects of any type.
vector<int> scores(100);
vector<char> buffer(500);
vector<Passenger> passList(20);
vector<int> newScores = scores;
vector.cpp