C++: A Comprehensive Introduction
Transcript of C++: A Comprehensive Introduction
C++ A Comprehensive Introduction
How to Use this User Guide
This handbook accompanies the taught sessions for the course Each section contains a brief overview of a topic for your reference and then one or more exercises
Exercises are arranged as follows
A title and usually a brief overview of the tasks to be carried out
A set of tasks together with a brief description of each
A set of steps that will achieve each task
Additionally there may be extra instructional notes for example some of the incomplete solutions contain notes in the form of code comments
PLUSPLUS As we get a broad mix of attendees on our courses we have occasionally added advanced or more technically in-depth asides labelled PLUSPLUS (all of which lie outside the scope of this introductory class) These are intended to challenge and inform just those students who already possess a more solid programming background
Exercises particularly those within the same section often assume that you have completed earlier exercises If you have any problems with the text or the exercises please ask the lecturer or one of the demonstrators (if any) for help
Note well
1 This course is mainly an introduction to the C++ that in the main attendees are most likely working with ie legacy or some might call it classic C++ With the introduction of C++11C++14C++17 modern up-to-date C++ can sometimes present itself as an almost new language (indeed this is extended further with the upcoming release of C++20) Therefore as this course is mainly aimed at those using existing C++ code we will only cover some of the changes made with the introduction of C++11 and later versions To find out more about C++11 and other versions eg C++17 please watch the relevant presentations found here channel9msdncomEventsGoingNative
2 The slides used by your lecturer do not necessary cover all the material required to complete the exercises ie there is extra information and sometimes a more detailed explanation in the notes or within the comments in code examples Also some slides may NOT be presented ndash in which case they are there for reference only
3 Additionally we do not expect attendees to complete very many of the large number of exercises provided during the course itself From their descriptions and subject matter select those that you feel able to complete Also you should feel free to work on your own project or problem if you would rather
Files and Folders
All of the files and folders you need to interact with should be located in the course folder on your machines desktop
Solutions to the exercises are located in folders named
(exercise solut ion) ProjectName
Where ProjectName will have previously been stated in the course notebook For example the folder called
(exercise solut ion) Sorts
contains the s ln file (Visual Studio solution file) which is the file you would open to see the solution to the Sorts exercise To open the solution you can either double-cl ick on the s ln file or open it via the File menu in Visual Studio NOTE if the file extension s ln is not visible just double-click on the file whose descr ipt ion reads Microsoft Visual
Studio Solut ion
The course folder also contains other C++ solutions in separate folders that again are usually referenced from the text In the main these are demonstrations andor contain code that might be useful to you after this course (but considered beyond the scope of this introduction to C++)
A quick note about Solutions and Projects in Visual Studio
In the real commercial world a full solution to a given problem may involve the creation of many constituent projects (possibly involving a variety of programming languages) A Visual Studio Solution (s ln file) mimics this approach and is really a container for separate constituent Visual Studio Projects files (vcxproj files)
All of our solutions contain single projects ndash and these may be opened in preference to opening the solution files For example in the (demonstrat ion) Ackermann
folder you will find a (demonstration) Ackermanns ln and a (demonstration) Ackermannvcxproj file you may open either file to work on the cpp code in the project
Copyright
This document is Copyright copy 2019 by Dr P Morris All rights are reserved No part of this publication may be reproduced transmitted transcribed stored in a retrieval system or translated into any language or computer language in any form or by any means without the prior written permission of the author
Version Date Author Comments
19 15 October 2019 Peet Morris
Please let us know if you find typos or errors in our course book and code
Contents
1 Introduction 1
11 What you should already know 1
12 What you will learn 1
13 Where can I get a copy of the softwaretools used 1
2 Things to understand 1
21 Compilers new and old 1
22 The C++ Standard Template Library (STL) 2
23 Visual Studio 2019 3
Creating your first program in Visual Studio 2019 6
Explanation 10
Your projects default code template 13
Arithmetic Operators 15
Characters 16
Header (include) Files 17
Strings 18
The LF (Line Feed) Problem and Reading Keys 20
Casts 22
Other Cast Types 24
3 Basic Control Flow 28
Selection - ifhellipelse statement 28
Selection - switch multiple selection statement 30
Repetition ndash while dohellipwhile and for loops 30
4 Logical and Bitwise Operators 35
41 Logical 35
42 Bitwise 37
Shifts 38
XOr 38
5 Introduction to Functions 39
Creating a function 41
52 Algorithms 49
Functions and Pass by Reference 51
Returning values from functions 53
Side effects 55
6 Classes and Objects 64
Creating your first class 65
Member functions and Passing parameters 67
Data Members 68
Constructors 70
Separating use from declaration and definition 72
Destructors 81
7 Arrays vectors lists and hash-tables 82
Declaring and using arrays 83
Searching Arrays with Linear Search 87
Sorting Arrays with Insertion Sort 90
Multidimensional Arrays 94
Declaring and using vectors 99
stdarray 105
Declaring and using lists 106
72 Hash Tables and Cached Calculations 107
Hash Tables 108
8 Pointers 112
Initialising pointers 113
Pointer Arithmetic and Arrays 115
9 APIs New Delete and Dynamic Memory 124
Using an API 124
Dynamic Memory Management 125
10 More on Functions 125
Multiple arguments overloading and default values 129
Passing Arrays to Functions 132
Passing Two-dimensional Arrays to Functions 135
11 Inheritance and (not presented) Polymorphism 135
111 Inheritance 135
Modelling a student - a first attempt 137
112 Polymorphism 143
12 Appendices 147
Arithmetical Operators 147
Assignment Operators 147
Assignment and Arithmetic examples 148
Relational and Equality Operators 148
Logical Operators 149
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
How to Use this User Guide
This handbook accompanies the taught sessions for the course Each section contains a brief overview of a topic for your reference and then one or more exercises
Exercises are arranged as follows
A title and usually a brief overview of the tasks to be carried out
A set of tasks together with a brief description of each
A set of steps that will achieve each task
Additionally there may be extra instructional notes for example some of the incomplete solutions contain notes in the form of code comments
PLUSPLUS As we get a broad mix of attendees on our courses we have occasionally added advanced or more technically in-depth asides labelled PLUSPLUS (all of which lie outside the scope of this introductory class) These are intended to challenge and inform just those students who already possess a more solid programming background
Exercises particularly those within the same section often assume that you have completed earlier exercises If you have any problems with the text or the exercises please ask the lecturer or one of the demonstrators (if any) for help
Note well
1 This course is mainly an introduction to the C++ that in the main attendees are most likely working with ie legacy or some might call it classic C++ With the introduction of C++11C++14C++17 modern up-to-date C++ can sometimes present itself as an almost new language (indeed this is extended further with the upcoming release of C++20) Therefore as this course is mainly aimed at those using existing C++ code we will only cover some of the changes made with the introduction of C++11 and later versions To find out more about C++11 and other versions eg C++17 please watch the relevant presentations found here channel9msdncomEventsGoingNative
2 The slides used by your lecturer do not necessary cover all the material required to complete the exercises ie there is extra information and sometimes a more detailed explanation in the notes or within the comments in code examples Also some slides may NOT be presented ndash in which case they are there for reference only
3 Additionally we do not expect attendees to complete very many of the large number of exercises provided during the course itself From their descriptions and subject matter select those that you feel able to complete Also you should feel free to work on your own project or problem if you would rather
Files and Folders
All of the files and folders you need to interact with should be located in the course folder on your machines desktop
Solutions to the exercises are located in folders named
(exercise solut ion) ProjectName
Where ProjectName will have previously been stated in the course notebook For example the folder called
(exercise solut ion) Sorts
contains the s ln file (Visual Studio solution file) which is the file you would open to see the solution to the Sorts exercise To open the solution you can either double-cl ick on the s ln file or open it via the File menu in Visual Studio NOTE if the file extension s ln is not visible just double-click on the file whose descr ipt ion reads Microsoft Visual
Studio Solut ion
The course folder also contains other C++ solutions in separate folders that again are usually referenced from the text In the main these are demonstrations andor contain code that might be useful to you after this course (but considered beyond the scope of this introduction to C++)
A quick note about Solutions and Projects in Visual Studio
In the real commercial world a full solution to a given problem may involve the creation of many constituent projects (possibly involving a variety of programming languages) A Visual Studio Solution (s ln file) mimics this approach and is really a container for separate constituent Visual Studio Projects files (vcxproj files)
All of our solutions contain single projects ndash and these may be opened in preference to opening the solution files For example in the (demonstrat ion) Ackermann
folder you will find a (demonstration) Ackermanns ln and a (demonstration) Ackermannvcxproj file you may open either file to work on the cpp code in the project
Copyright
This document is Copyright copy 2019 by Dr P Morris All rights are reserved No part of this publication may be reproduced transmitted transcribed stored in a retrieval system or translated into any language or computer language in any form or by any means without the prior written permission of the author
Version Date Author Comments
19 15 October 2019 Peet Morris
Please let us know if you find typos or errors in our course book and code
Contents
1 Introduction 1
11 What you should already know 1
12 What you will learn 1
13 Where can I get a copy of the softwaretools used 1
2 Things to understand 1
21 Compilers new and old 1
22 The C++ Standard Template Library (STL) 2
23 Visual Studio 2019 3
Creating your first program in Visual Studio 2019 6
Explanation 10
Your projects default code template 13
Arithmetic Operators 15
Characters 16
Header (include) Files 17
Strings 18
The LF (Line Feed) Problem and Reading Keys 20
Casts 22
Other Cast Types 24
3 Basic Control Flow 28
Selection - ifhellipelse statement 28
Selection - switch multiple selection statement 30
Repetition ndash while dohellipwhile and for loops 30
4 Logical and Bitwise Operators 35
41 Logical 35
42 Bitwise 37
Shifts 38
XOr 38
5 Introduction to Functions 39
Creating a function 41
52 Algorithms 49
Functions and Pass by Reference 51
Returning values from functions 53
Side effects 55
6 Classes and Objects 64
Creating your first class 65
Member functions and Passing parameters 67
Data Members 68
Constructors 70
Separating use from declaration and definition 72
Destructors 81
7 Arrays vectors lists and hash-tables 82
Declaring and using arrays 83
Searching Arrays with Linear Search 87
Sorting Arrays with Insertion Sort 90
Multidimensional Arrays 94
Declaring and using vectors 99
stdarray 105
Declaring and using lists 106
72 Hash Tables and Cached Calculations 107
Hash Tables 108
8 Pointers 112
Initialising pointers 113
Pointer Arithmetic and Arrays 115
9 APIs New Delete and Dynamic Memory 124
Using an API 124
Dynamic Memory Management 125
10 More on Functions 125
Multiple arguments overloading and default values 129
Passing Arrays to Functions 132
Passing Two-dimensional Arrays to Functions 135
11 Inheritance and (not presented) Polymorphism 135
111 Inheritance 135
Modelling a student - a first attempt 137
112 Polymorphism 143
12 Appendices 147
Arithmetical Operators 147
Assignment Operators 147
Assignment and Arithmetic examples 148
Relational and Equality Operators 148
Logical Operators 149
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Files and Folders
All of the files and folders you need to interact with should be located in the course folder on your machines desktop
Solutions to the exercises are located in folders named
(exercise solut ion) ProjectName
Where ProjectName will have previously been stated in the course notebook For example the folder called
(exercise solut ion) Sorts
contains the s ln file (Visual Studio solution file) which is the file you would open to see the solution to the Sorts exercise To open the solution you can either double-cl ick on the s ln file or open it via the File menu in Visual Studio NOTE if the file extension s ln is not visible just double-click on the file whose descr ipt ion reads Microsoft Visual
Studio Solut ion
The course folder also contains other C++ solutions in separate folders that again are usually referenced from the text In the main these are demonstrations andor contain code that might be useful to you after this course (but considered beyond the scope of this introduction to C++)
A quick note about Solutions and Projects in Visual Studio
In the real commercial world a full solution to a given problem may involve the creation of many constituent projects (possibly involving a variety of programming languages) A Visual Studio Solution (s ln file) mimics this approach and is really a container for separate constituent Visual Studio Projects files (vcxproj files)
All of our solutions contain single projects ndash and these may be opened in preference to opening the solution files For example in the (demonstrat ion) Ackermann
folder you will find a (demonstration) Ackermanns ln and a (demonstration) Ackermannvcxproj file you may open either file to work on the cpp code in the project
Copyright
This document is Copyright copy 2019 by Dr P Morris All rights are reserved No part of this publication may be reproduced transmitted transcribed stored in a retrieval system or translated into any language or computer language in any form or by any means without the prior written permission of the author
Version Date Author Comments
19 15 October 2019 Peet Morris
Please let us know if you find typos or errors in our course book and code
Contents
1 Introduction 1
11 What you should already know 1
12 What you will learn 1
13 Where can I get a copy of the softwaretools used 1
2 Things to understand 1
21 Compilers new and old 1
22 The C++ Standard Template Library (STL) 2
23 Visual Studio 2019 3
Creating your first program in Visual Studio 2019 6
Explanation 10
Your projects default code template 13
Arithmetic Operators 15
Characters 16
Header (include) Files 17
Strings 18
The LF (Line Feed) Problem and Reading Keys 20
Casts 22
Other Cast Types 24
3 Basic Control Flow 28
Selection - ifhellipelse statement 28
Selection - switch multiple selection statement 30
Repetition ndash while dohellipwhile and for loops 30
4 Logical and Bitwise Operators 35
41 Logical 35
42 Bitwise 37
Shifts 38
XOr 38
5 Introduction to Functions 39
Creating a function 41
52 Algorithms 49
Functions and Pass by Reference 51
Returning values from functions 53
Side effects 55
6 Classes and Objects 64
Creating your first class 65
Member functions and Passing parameters 67
Data Members 68
Constructors 70
Separating use from declaration and definition 72
Destructors 81
7 Arrays vectors lists and hash-tables 82
Declaring and using arrays 83
Searching Arrays with Linear Search 87
Sorting Arrays with Insertion Sort 90
Multidimensional Arrays 94
Declaring and using vectors 99
stdarray 105
Declaring and using lists 106
72 Hash Tables and Cached Calculations 107
Hash Tables 108
8 Pointers 112
Initialising pointers 113
Pointer Arithmetic and Arrays 115
9 APIs New Delete and Dynamic Memory 124
Using an API 124
Dynamic Memory Management 125
10 More on Functions 125
Multiple arguments overloading and default values 129
Passing Arrays to Functions 132
Passing Two-dimensional Arrays to Functions 135
11 Inheritance and (not presented) Polymorphism 135
111 Inheritance 135
Modelling a student - a first attempt 137
112 Polymorphism 143
12 Appendices 147
Arithmetical Operators 147
Assignment Operators 147
Assignment and Arithmetic examples 148
Relational and Equality Operators 148
Logical Operators 149
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Contents
1 Introduction 1
11 What you should already know 1
12 What you will learn 1
13 Where can I get a copy of the softwaretools used 1
2 Things to understand 1
21 Compilers new and old 1
22 The C++ Standard Template Library (STL) 2
23 Visual Studio 2019 3
Creating your first program in Visual Studio 2019 6
Explanation 10
Your projects default code template 13
Arithmetic Operators 15
Characters 16
Header (include) Files 17
Strings 18
The LF (Line Feed) Problem and Reading Keys 20
Casts 22
Other Cast Types 24
3 Basic Control Flow 28
Selection - ifhellipelse statement 28
Selection - switch multiple selection statement 30
Repetition ndash while dohellipwhile and for loops 30
4 Logical and Bitwise Operators 35
41 Logical 35
42 Bitwise 37
Shifts 38
XOr 38
5 Introduction to Functions 39
Creating a function 41
52 Algorithms 49
Functions and Pass by Reference 51
Returning values from functions 53
Side effects 55
6 Classes and Objects 64
Creating your first class 65
Member functions and Passing parameters 67
Data Members 68
Constructors 70
Separating use from declaration and definition 72
Destructors 81
7 Arrays vectors lists and hash-tables 82
Declaring and using arrays 83
Searching Arrays with Linear Search 87
Sorting Arrays with Insertion Sort 90
Multidimensional Arrays 94
Declaring and using vectors 99
stdarray 105
Declaring and using lists 106
72 Hash Tables and Cached Calculations 107
Hash Tables 108
8 Pointers 112
Initialising pointers 113
Pointer Arithmetic and Arrays 115
9 APIs New Delete and Dynamic Memory 124
Using an API 124
Dynamic Memory Management 125
10 More on Functions 125
Multiple arguments overloading and default values 129
Passing Arrays to Functions 132
Passing Two-dimensional Arrays to Functions 135
11 Inheritance and (not presented) Polymorphism 135
111 Inheritance 135
Modelling a student - a first attempt 137
112 Polymorphism 143
12 Appendices 147
Arithmetical Operators 147
Assignment Operators 147
Assignment and Arithmetic examples 148
Relational and Equality Operators 148
Logical Operators 149
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Creating your first class 65
Member functions and Passing parameters 67
Data Members 68
Constructors 70
Separating use from declaration and definition 72
Destructors 81
7 Arrays vectors lists and hash-tables 82
Declaring and using arrays 83
Searching Arrays with Linear Search 87
Sorting Arrays with Insertion Sort 90
Multidimensional Arrays 94
Declaring and using vectors 99
stdarray 105
Declaring and using lists 106
72 Hash Tables and Cached Calculations 107
Hash Tables 108
8 Pointers 112
Initialising pointers 113
Pointer Arithmetic and Arrays 115
9 APIs New Delete and Dynamic Memory 124
Using an API 124
Dynamic Memory Management 125
10 More on Functions 125
Multiple arguments overloading and default values 129
Passing Arrays to Functions 132
Passing Two-dimensional Arrays to Functions 135
11 Inheritance and (not presented) Polymorphism 135
111 Inheritance 135
Modelling a student - a first attempt 137
112 Polymorphism 143
12 Appendices 147
Arithmetical Operators 147
Assignment Operators 147
Assignment and Arithmetic examples 148
Relational and Equality Operators 148
Logical Operators 149
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Precedence and Associativity Table 150
Escape Sequences 151
Cast Operator 152
Formatted Output 152
Header Files 153
Matrix Libraries 153
Scope 154
Enumerating constants 154
Constants 154
Vector member functions 155
Global functions 155
list member functions 156
cmath functions 156
String class 158
ASCII Character set 161
Handy IDE Settings 169
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Exercises
Exercise 1 (Optional) Creating a first and default program 6
Exercise 2 CreatingModifying additional projects 26
Exercise 3 SearchString 29
Puzzled Programmers 29
The Collatz Conjecture 31
Mixing loops 33
PLUSPLUS Recursion 34
PLUSPLUS Base Two and Bits 37
Practising with Logical and Bitwise operators 38
Writing functions 42
Using a struct 43
PLUSPLUS When Things Go Wrong 44
The Monty Hall problem 46
More Functions 48
PLUSPLUS IsLeap in a line 49
Algorithms 49
Pass arguments by reference 52
Returning a value from a function 57
PLUSPLUS Arithmetic Bases 58
Searching for Sequences 61
PLUSPLUS Optimising Searching for Sequences 63
Evolving Searching for Sequences 64
Creating a class 65
Passing parameters 67
Using data members 69
More Objects 70
Using constructors 71
Separating declaration and definition 74
PLUSPLUS Using external libraries and third party header files 78
Creating an array to hold exam results 84
Linear Search 87
PLUSPLUS Debugging Linear Search 89
SortingSearching an array 90
PLUSPLUS Binary Search (Binary Chop) 93
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-
Creating a multidimensional array 95
Creating a vector to hold exam results 100
Using insert() and iterators 103
Computing Fibonacci Numbers 110
Using pointers 114
Pointers and Arrays 116
PLUSPLUS Pointers and Arrays 119
PLUSPLUS Function pointers 122
main() and command-line arguments 126
EncryptDecrypt a file 128
Passing Arrays to functions 132
Base classes 137
PLUSPLUS Polymorphism 144
The PowerPoint slides entitled Exercises show the inclusive fromto exercise numbers which cover the topics discussed in the previous section It is not at all necessary to attempt to work through the entire quoted range variety is the spice of life ndash just choose those that appeal
1
1 Introduction Welcome to C++ A Comprehensive Introduction
These notes accompany the course delivered by Oxfords IT Services IT Learning Programme
If at any time you are not clear about any aspect of the course please make sure you ask your lecturer or demonstrator for some help If you are away from the class you can get help by email from your lecturer or from helpitoxacuk
Please also note that the university subscribes to Lyndacom ndash please check there for other C++ resources
11 What you should already know
The prerequisite for this course says that Either experience in another programming language or attendance on one of the PHP JavaScript or Python Kick-Start courses Is required
The more programming knowledge you have the better That said the documentation and lectures are structured such that those with very little knowledge should still be able to work through the course at their own pace
12 What you will learn
We will cover the following topics
Working with Microsofts Visual Studio Fundamental data types
Control Flow amp Iteration Header Files
Strings Functions
Arrays and Vectors Classes and Objects
Constructors and Destructors Member functions
Pointers And much more
13 Where can I get a copy of the softwaretools used
wwwvisualstudiocom (Microsofts C++ Compiler IDE and tools)
wwwpeetmcomC++introcoursezip (latest course code notes slides etc)
2 Things to understand
21 Compilers new and old
Students on this course often have to work with enhance or bug-fix existing code This sub-section is primarily for their consideration (it assumes some prior C++ knowledge)
2
Not all C++ compilers comply with the latest official ISO C++ standard (C++17) which was finally approved in December 20171
What does this mean It means that the code you write compile and run on one machine may not compile on the next machine if you are using a different compiler (even if it is using the same operating system) In this course you will be using Microsofts C++ Compiler (part of Visual Studio 2019)
Some older header files you may see with inherited C++ code are
include ltiostreamhgt have a h extension The C++ standard for this header file is include ltiostreamgt Your program may run correctly by adding a h but simply adding a h suffix will not work for all included files
include ltstringhgt has been replaced with include ltstringgt The stringh header file does not include C++ strings it includes C strings
include ltmathhgt has been replaced with include ltmathgt
The lesson to be learnt here is that a lot of C++ code you come across will have been created using older compilers Some of the header file and other code will not be recognised and may cause compilation errors when compiled on a machine which is more compliant with the C++ standard
If you are using the Gnu Compiler Collection (gcc g++ etc) you can specify standards compliancy via the ndashstd option eg -std=c++17 (other options are C++98
C++11 C++14)
Visual Studio can also be configured to use LLVM and clang Please see the relevant online documentation of how to install and use these if you wish to use them httpsllvmorgdocsGettingStartedVShtml
22 The C++ Standard Template Library (STL)
enwikipediaorgwikiStandard_Template_Library
The C++ programs you write will consist of the classes and functions that you write or modify (we provide partial solutions to every exercise)
However we will also look at what is still commonly referred to as the STL (now just part of the C++ Standard Library ) which holds a collection of existing classes functions and algorithms that you can use in the programs you will be creating
Some of the classes and template classes we will be looking at are
The string class The vector container template
The sort algorithm The list container template
The find algorithm
In addition you should also look at and be aware of another powerful library called Boost (parts of the STL come directly from the Boost library) wwwboostorg
The Boost library is easy to install (on any platform) as most Boost libraries are what is called header-only ie they consist entirely of header files containing templates and inline
1 A draft of this is included with your course files (n4660pdf) Its worth mentioning that this draft is in effect the published C++17 standard
3
functions and require no separately-compiled library binaries or special treatment when linking
23 Visual Studio 2019
What is Visual Studio (VS) VS is Microsofts freely available integrated development environment (IDE) and comes complete with optional compilerstools for a variety of languages We have only installed the IDE and the C++ compi ler (clexe etc) for this course
So what is a compiler
A compiler is a computer program that allows us to write programs in some specially defined language (unfortunately not English yet) in our case C++ (a so called high- level
language ) As you heard earlier the tex t we write in C++ is called source-code it is just simple text that one could write in Notepadexe for example
Sadly source-code is not directly understood by operat ing systems such as Windows Linux and macOS etc and it is the compilers job to convert our source-code into the terse concise and highly optimised machine-code that computers understand directly
Machine-code is often called executable or object-code and the compiled version of the source code is really just a file that contains numbers ndash a series of 8-bit bytes each holding a value between 0 and 255 The numbers either encode l ow-level instruct ions (code) or data that working together define the program Because these numbers may not encode displayable characters (see the ASCII table in the appendices to see a mapping between the numbers and the displayable characters) opening such a file an exe file in something like Windows notepad application would result in something like this being displayed (just the beginning shown)
However if we open this same executable file in a program that simply displays the files content as numbers and not what characters if any are represented by those numbers as Notepad is doing) we see this (the numbers are shown in base-16 or hexadecimal format)
4
The first two numbers 4D and 5A can be displayed as the text M and Z2 (see the first two characters at the top left in the previous notepad view of this file) 4D in base 10 is 77 and 5A is 90 ie the ASCII values for M amp Z (you can look these up in the ASCII table in the back of your course book)
Also take note of the line sequence starting 55 8B EC Then read on
2 MZ (0x4D5A) at the beginning of a file is an example of whats known as a magic number these are often used to identify a file type ndash in this case an MS-DOS executable file Trivia MZ are the initials of Mark Zbikowski the designer of the MS-DOS executable file format
5
If we have Visual Studio we can open the same file to see how such numbers translate into instructions and data
55 8B EC is the real beginning of our program In the above we see the numbers on the left and on the right what they actually mean Eg the first number 55 means push ebp which is an Intel CPU instruction Likewise 8B and EC together mean mov ebp esp The next line 81 EC C0 00 00 00 combines instructions and data and translate into sub esp 0C0h (subtract from esp the value C0 or 192 in base-10)
This is the entire program really the extra data shown in the previous views are for housekeeping
What does this program actually do then
Well youre about to find out ndash youre optionally now going to recreate it in Exercise 1
6
Creating your first program in Visual Studio 2019
Exercise 1 (Optional) Creating a first and default program
IMPORTANT
This exercise starts with a walk-through of using Visual Studio to create a new solution which you then go on to modify You should have already seen the steps needed to create a new solution in class so if youd rather just get on with the modification part simply open the (exercise solut ion)
f i rs t folder (in the Course folder) and double click the f i rs t s ln file If you choose to do this you can skip over the next few pages to the Explanation section (232) or even jump further on to Task 1 on page 14
Note You will not need to create any completely new programs during the course so even if you didnt fully follow the steps you can still safely move on to the modification part However if you really want to walk it through for yourself
Start the Visual Studio 2019 Integrated Development Environment (IDE) and create a new C++ Console application project You should have a shortcut to Visual Studio on your desktop failing that look for it on the Start menu
If they appear follow the prompts as shown below (if youre asked about keyboard mappings or Develop options select the C++ option)
7
Click Create a new project
Select Console App and click Next
8
Well locate the first project in a folder called first in your C drives Temp folder If the folder doesnt exist it will be created for you Click Create
Something like the above should appear (if you dont see the Solution Explorer panel open it via the View menu)
9
Alter the code adding the lines in bold as show here
include ltiostreamgt using namespace std int main() stdcout ltlt Hello Worldn system(pause)
Build and run the project by pressing the green arrow or by pressing F5
10
Explanation
Disclaimer at this stage you do not need to fully follow all of this just now
include ltiostreamgt
iostream is a standard C++ library file Files of this type are called header files They are text files usually containing C++ declarations definitions and code
Including iostream allows us to use some pre-defined objects to output messages to a console window This file must be included for any program that outputs data to the screen - or inputs data from the keyboard for that matter
The C++ compiler operates in passes through our code In the first pass ndash called the pre-processing pass ndash include directives are processed which are really text-substitution directives To be precise what include ltiostreamgt says is ldquoGo and find the text file called iostream and replace the directive with the contents of that filerdquo
The file name following a include directive can be enclosed in double quotes or chevrons ie include iostream or include ltiostreamgt The meaning of each is defined by the implementation (Microsofts C++ compiler in our case)
However it is common practice that if file name is in quotes it will be looked for locally first - in the same folder as the cpp file containing it and before being sought elsewhere Conversely if it is in chevrons the compiler will usually look for the file in a central include folder that was installed with the compiler ndash this folder is usually reserved for include files that come with the compiler as opposed to those that you might write yourself eg standard includes (like iostream) We therefore usually use quotes when we want to include our own custom project specific include files and chevrons when wanting to use include files that come with the compiler
You may also see that the filename sometimes has a h file extension This typically means that the header file being used is a C language header file and not a C++ one There are other variations (you are welcome to use your own) for example you might also see the occasional hxx file extension or something else entirely
using namespace std
The using namespace std code above doesnt actually appear in the automatically generated code In our project and solution files we will add it just after any include directives
namespaces in summary are very simple Everything within a namespace has a unique name and so theyre often used to help divide larger projects into more manageable chunks and to avoid name clashes
Standard C++ places a lot of its routines and functionality within a namespace call std Wed like to use this functionality and so we say we want to use all of the std namespace In the real world this isnt terribly good practice
11
However by declaring that were using namespace std throughout we can access members of this namespace without having to say exactly where they are (in which namespace) or worry about name clashes - where two objects in different files have been given the same name
The members of std that we will be using throughout are
cin (Console In) and cout (Console Out) and we must use include ltiostreamgt in order to use them
endl - is a stream manipulator that writes a new line to output endl stands for end
of l ine and is pronounced end all
If we dont declare that we were using the std namespace (which is the case in the automatically generated code) we have to prefix any use of cin cout and endl with std eg stdcin stdcout stdendl If youve added the using namespace std directive you may now remove the std in front of the stdcout ltlt Hello Worldn line
int main()
This is the entry point to our program ndash every C++ program must have this same entry point defined main() is a function the body of a function is defined within the opening and closing braces that come after its name The int to the left of main() says that this function returns (or resolves to beevaluates to) an integer value Returning a value requires you to use a return statement However as it is normal practice to simply return the value zero if you omit the return statement a value of zero is returned for you (only where main is concerned) If you want to explicitly return the value yourself you could modify the code to read
int main() stdcout ltlt Hello Worldn system(pause) return 0
So why return a value anyway Our added line return 0 means in this case that our main doing whatever it does as part of its function eventually resolves to the value 0 The value is returned to whatever called our programs entry point in this case and as usually that is the operating system ndash which has been waiting for us to return a value at this point However the operating system will simply ignore whatever value we ultimately return Why do it then
12
Consider the case when one of your programs needs to run another program to perform a part of its entire function Your main program needs to start this other program and wait until it completes successfully before continuing See the description of the system(pause) code line below
stdcout ltlt Hello Worldn
cout is an object declared in iostream ndash think of its name meaning console out Anything sent to cout using the double chevron operator ltlt appears on the console the
The n in the text means that cout should also output a carriage-return linefeed sequence (terms taken from the days of typewriters and telex machines) basically it means start any new output on a newline underneath the current line An alternative to using n is to use endl eg stdcout ltlt Hello World ltlt endl endl does more or less the same thing as n
system(pause)
system() is a standard function that is used to run an external program (here thats a standard Windows program called pauseexe) The system() function waits for the pause program to complete before continuing Going back to the discussion on return 0 earlier this is an example of one program starting another ndash here thats our program starting the pause program The pause program returns a value as part of its completion and we can examine that if we want Programs usually return 0 for success or some other integer value that means something went wrong ndash the value returned indicates what went wrong Ie a returned value of say 42 might mean that we cant answer the ultimate question with this computer3
So what is pause pauseexe is a standard Windows program that simply outputs the message Press any key to continue and then waits for a key to be pressed before exiting We use that facility here so that our program doesnt simply shutdown and disappear as it falls off the end of main()s closing or encounters a return statement If we did allow it to exit we would hardly have time to examine our programs output before it disappeared off the screen Try that and see (comment out the line using a double-slash like this system(pause))
If you run any of the course code on Linux or a Mac youll need to change this line to something like cinget()
3 An unashamed reference to the Hitch Hikers Guide to the Galaxy and the Deep Thought computer
13
Your projects default code template
In the course exercises when it comes to you writing code we will always ask you to open and then modify a partially complete projectsolution so you wont have to fiddle with projects and boilerplate code like this again
Nevertheless should you wish to start from scratch or simply experiment with Visual Studio we recommend using the code below as a starting point
include ltiostreamgt using namespace std int main() Start coding after here system(pause) return 0
14
Task 1
Immediately above system(pause) Replace the stdcout ltlt Hello Worldn line with the code shown here
int anum = 0
cout ltlt Enter a number
cin gtgt anum
cout ltlt The number you entered is
ltlt anum
ltlt endl
Test your modified program Tip remember you may hit the F5 key to build and then run your program
Try entering some text instead of a number Did it work
Alter the spacing (use of spaces and tab characters) in your code ndash does the C++ compiler care about this so called whi tespace
The statement int anum = 0 defines a variable (a memory location) which we will refer to in our code as anum to store a number of type int to hold an in teger (ie 1 -4 27) The memory location is being initialised with a value of 0 here It is good practice to initialise variables when you define them In C++11 a new type of uniform initialisation syntax was introduced and also encouraged eg int anum 0
cout ltlt Enter a number cout is a name that belongs to the namespace std The ltlt is called the stream insert ion operator When the program executes the value to the right of the operator (Enter a number) is inserted in the output stream and ultimately output to console window
cin gtgt anum cin is the input stream object of the namespace std gtgt is called the stream extract ion operator and is used here to read a number from the keyboard
cout ltlt The number you entered is ltlt anum ltlt endl This statement concatenates the output by using multiple stream insertion operators ltlt endl is the stream manipulator that adds a new line
The next Exercise starts on page 26 The pages between here and page 26 contain
code that you may like to try out by further modifying this project if not just read through the textcode until you get to page 26
15
Arithmetic Operators
Most computer programs perform arithmetic calculations Table 1 summarises the standard C++ arithmetic operators When working with integer division where both the numerator and denominator are integer the expression 15 6 evaluates to 2 To get the remainder after integer division you would use the modulus operator Note the modulus operator can only be used with integer operands
To establish the complete result of the following integer division 156 requires two operations
15 6 = 2
15 6 = 3
The result being 2 remainder 3
C++ Operation C++
arithmetic operator
Algebraic expression C++ expression
Addition + y + 6 y + 6
Subtraction - a - b a - b
Multiplication c times d or cd c d
Division xy or y
x or yx x y
Modulus p mod q p q
Table 1 - C++ arithmetic operators
Other fundamental data types Table 2 shows how you would declare and initialise four other data types for use in programs (there are more data types available)
16
Data type Example
Float float aFloat = 1234
Double (the precision of a Float) double aDouble = 123456
Char char aChar = A
Bool bool aBoolean = true
Table 2 - C++ numerical types4
Characters
Characters are normally stored in variables of type char but can also be stored as in t(eger) data types Characters are represented as single byte integers in the computer so it is possible to output a character as an integer or as a character
All characters have a numerical representation in the computer and the ASCII (American Standard Code for Information Interchange) character set shows each character and its decimal equivalent (also note that a combination of characters may be used to form more complex Unicode characters) See appendix 111
Characters can be read in with the following statements
char aChar declares a variable (aChar) of type char
cin gtgt aChar this statement is used to read a character into the variable aChar
Note After entering a character the ltENTERgtkey must be pressed before the character is read by the program
The following four statements correctly declare a variable of type char output a user prompt then read a character and store it in the variable aChar
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar
4 See httpencppreferencecomwcpplanguagetypes for a complete list (or the official ISO standard of course)
17
Header (include) Files
So far weve seen that to use certain functionality we had to include ltiostreamgt We have to do similar to use other functionality which is not part of the code C++ language ie we will need to include anything that comes as part of the standard library
In its current form Visual Studio comes with the following include files (most of which are standard files)
h files (95 C language files)
agentsh agileh ammintrinh amph amprth amprt_exceptionsh amp_graphicsh amp_mathh amp_short_vectorsh armintrh arm_neonh cfguardh collectionh comdefh comdefsph comiph comutilh concrth concrtrmh ConcurrencySalh concurrent_priority_queueh concurrent_queueh concurrent_unordered_maph concurrent_unordered_seth concurrent_vectorh crtdefsh crtversionh delayimph dloadsuph dvech ehh emmintrinh excpth fvech gcrooth immintrinh internal_concurrent_hashh internal_split_ordered_listh intrinh intrin0h invkprxyh iso646h ivech limitsh mm3dnowh mmintrinh nmmintrinh omph pgobootrunh pmmintrinh pplh pplawaith pplcancellation_tokenh pplinterfaceh ppltasksh ppltaskschedulerh pplwinh rtcapih salh setjmph setjmpexh smmintrinh srvh stdargh stdboolh stdexcpth stdinth tmmintrinh typeinfoh use_ansih vadefsh varargsh vcclrh vccorlibh vcruntimeh vcruntime_exceptionh vcruntime_newh vcruntime_new_debugh vcruntime_startuph vcruntime_stringh vcruntime_typeinfoh wmmintrinh xatomich xatomic0h xkeycheckh xlocinfoh xmmintrinh xsmf_controlh xstring_inserth xtgmathh xxamph xxamp_inlh ymathh yvalsh zmmintrinh
115 C++ files
algorithm allocators any array atomic bitset cassert ccomplex cctype cerrno cfenv cfloat chrono cinttypes ciso646 cliext climits clocale cmath CodeAnalysis codecvt complex condition_variable csetjmp csignal cstdalign cstdarg cstdbool cstddef cstdint cstdio cstdlib cstring ctgmath ctime cuchar cvt cwchar cwctype deque exception experimental filesystem forward_list fstream functional future hash_map hash_set initializer_list iomanip ios iosfwd iostream istream iterator limits list locale Manifest
18
map memory msclr mutex new numeric optional ostream queue random ratio regex scoped_allocator set shared_mutex sstream stack stdexcept streambuf string string_view strstream system_error thr thread tuple typeindex typeinfo type_traits unordered_map unordered_set utility valarray variant vector xcomplex xfacet xfunctional xhash xiosbase xlocale xlocbuf xlocinfo xlocmes xlocmon xlocnum xloctime xmemory xmemory0 xstddef xstring xtr1common xtree xutility xxatomic
Strings
Next to numbers strings are the most commonly used data type in programming
A string is both a datatype (string) and also literal character data ie a sequence of characters such as Oxford or StAndrews In C++ string literals are enclosed in quotes The quotes are not part of the string they identify the data type as a string
Actually this isnt quite true the double quoted strings are a sequence of characters and are taken from the C programming language The things declared of the string type are C++ string objects ndash which may be initialised using the C language literal
C++ strings can be declared and initialised in this way
string institution = Oxford
string name = Peet
To use the string type in your programs add the header file include ltstringgt at the top of your program This allows the use of part of the C++ library of classes called the string class (and its member functionsmethods explanations will follow soon)
Of course strings are normally used when requesting an input Consider this code
string aName aDept Two string objects
cout ltlt Enter your full name
cin gtgt aName
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
19
If in answer to the first prompt we were to enter say Fred Brooks 5 the interaction and output of our program would immediately result in this
Enter your full name Fred Brooks
Enter your department Fred is associated with Brooks
Why When reading in a string with a space such as FredltspgtBrooks only the first part Fred is read into aName ndash and the input is said to be space delimited by cin ndash and consists of two separate inputs (so the Brooks parts is read into the aDept string variable)
We could use multiple prompts to read in a name of course but this is inconvenient
To handle this situation we can use the standard getline(cin aName) function to read in a name instead of using cin gtgt aName This reads all key-strokes into aName until the ltENTERgt key is pressed at which point it returns a string containing all of the characters from the input
cout ltlt Enter your full name
getline(cin aName)
cout ltlt Enter your department
cin gtgt aDept
cout ltlt aName ltlt is associated with ltlt aDept
The string class has many useful functions you can use to manipulate strings An example is the length() member functionmethod
string aName = Fred Brooks
cout ltlt The length of the string aName is ltlt aNamelength() ltlt endl
This statement will output - The length of the str ing aName is 11
See section 12119 for more information on the string class and its member functions
5 Fred Brooks is a real person and a legendary computer scientist httpenwikipediaorgwikiFred_Brooks
20
The LF (Line Feed) Problem and Reading Keys
Continuing on consider the following code
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
string aName
cout ltlt Enter your full name
getline(cin aName)
cout ltlt You entered ltlt aName ltlt endl
system(pause)
The intent here is to first ask for a character and then to use getline() to ask for a name
If only things were that simple
If we were to enter say a Z to satisfy the first prompt the program would immediately output
Enter a character Z
You entered Z
Enter your full name You entered
Press any key to continue
The problem here is that being a keyboard key theltENTERgt key is itself being seen as a valid input so when we enter Z followed by the ltENTERgt key were actually entering two keys ndash Z and the ltENTERgt key The first keys placed into aChar whilst the enter key is left in the keyboards buffer This is quite reasonable if you think about it you entered two keys (Z and ltENTERgt) but provided a home for just one of them in aChar
Ok so whats the problem Well the problem is that we really need to use something like getline() to read text that contains spaces and it just so happens that getline() given this scenario will see the residual ltENTERgt key left in the buffer and it will assume that you didnt enter anything you just hit the enter key
This problem - that of having a mischievous ltENTERgt key waiting to surprise us ndash will occur whenever you read a key from the keyboard using cin Luckily theres an easy fix as we can use another input function to read and then discard the waiting ltENTERgt key Its called cinget() Here is a modified version of the code above that fixes the problem
21
char aChar
cout ltlt Enter a character
cin gtgt aChar
cout ltlt You entered ltlt aChar ltlt endl
cinget() REMOVE THE ENTER KEY discarding the got character
string aName
cout ltlt Enter your full name
getline(cin aName)
Used like this cinget() reads and discards a character from the input stream You can do the same using cinignore() cinget extracts a single character from the stream and returns it cinignore() extracts any number of characters and discards them (the details are specified via passed parameters to the function) or a single character if no arguments to the function are provided
You can easily use cinignore() to ignore a number of characters or until a certain token (character) is met eg the following code reads in a users first and last names and then outputs their initials
22
char first last Two 8-bit characters
cout ltlt Please enter your first name followed by your surname
first = cinget() Get one character
The first parameter is the maximum number of characters to
extract (and ignore) The second parameter is a
delimiting character The function stops extracting characters
as soon as an extracted character matches this one
cinignore(2566 ) Ignore until a space is seen
last = cinget() Get one character
cout ltlt Your initials are ltlt first ltlt last ltlt endl
Casts
On occasions in your programs you may want to store a value in a variable of a different type (when there is a danger of a loss of information the compiler will issue a warning for example when storing a double in an int) If you store a double as an integer you lose information in two ways
any mantissa (fractional part) will be lost
the magnitude of the double being stored may be too large to fit into the integer
Eg it is not possible7 to store 6678 x 10000 as a 16-bit unsigned integer because 667800 is 10000010011011100 in binary (17-bits) and is therefore larger than the maximum storable value of 65535 (1111111111111111) However you can store 1230 as an integer8
When you need to represent a value as a different type you can use the static_cast notation as shown here to change a double to an integer
6 If this is exactly numeric_limitsltstreamsizegtmax() there is no limit As many characters are extracted as needed until delim (or the end-of-file) is found
7 Actually the result of attempting to store 66780 in a 16-bit unsigned integer will be 10011011100 or 1244 Do you see how this value comes about
8 Also see the (demonst rat ion) L imi ts project
23
int anInt
anInt = static_castltintgt(doResult) where dResult is a double
You may also use the following historic classic C-style9 notation to cast to different data types
anInt = (int)dResult
Eg to change an integer to a character
char aChar
aChar = static_castltchargt(bInt) where bInt is an integer
You may also combine this using the
object-constructionfunction-call syntax of C++ eg
double d = 314157
int n = (int)d Convert ds value to an integer
int j = int(d) Ditto
9 C-style casts are usually considered to be too powerful ndash in that they indiscriminately allow unsafe and downright dangerous conversions C++ casts were introduced to solve this problem
24
Other Cast Types
Although outside the scope of this introductory course for reference here is a summary of the cast types in C++ (feel free to skip this for now and come back to it at a later time)
static_castlttypegt(object)
The type parameter must be a data type for which there is a known method for converting object to whether this be a built-in or through a casting function (constructor) All types of conversions that are well-defined and allowed by the compiler are done using static_cast
The static_cast operator may be used for operations such as converting a pointer of a base class to a pointer of a derived class converting numeric data types such as enums to ints or ints to floats However static_cast conversions are not necessarily safe as no run-time type check is done which can cause casting between incompatible data types for example initialised pointers However this is checked at compile time to prevent casting obvious incompatibles Also be aware that a static_cast between pointer of base to pointer of derived may produce an erroneous result (where the actual object pointed to is of type base not derived)
dynamic_castlttypegt(object)
In the C++ programming language the dynamic_cast operator is a part of the run-time type information (RTTI) system that performs a typecast Unlike the static_cast the target of the dynamic_cast must be pointer or reference to class Unlike static_cast and C-style typecast (where a type check is made during compilation) a type safety check is performed at runtime If the types are not compatible an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers)
reinterpret_castlttypegt(object)
Allows any pointer to be converted into any other pointer type Also allows any integral type to be converted into any pointer type and vice versa
The reinterpret_cast operator produces a value of a new type that has the same bit pattern as its argument (unlike static_cast but like const_cast the reinterpret_cast expression does not compile to any CPU instructions It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type)
You cannot cast away a const or volatile qualification You can explicitly perform the following conversions
const_castlttypegt(object) A pointer to any object type or a pointer to a data member can be explicitly converted to a type that is
25
identical except for the const and volatile qualifiers For pointers and references the result will refer to the original object For pointers to data members the result will refer to the same member as the original (uncast) pointer to data member Depending on the type of the referenced object a write operation through the resulting pointer reference or pointer to data member may produce undefined behaviour
26
Exercise 2 CreatingModifying additional projects
Examine how comments look in a program
Examine the use of some fundamental data types
Using different data types
Using the cast operator
Using the string class
Task 1
Open the skeleton project called EvenI
The project folder is
EvenIEvenI s ln
Modify the projects code in to prompt for two numbers of type double and two numbers of type integer
The program should output the sum the product and the difference of the double numbers Also output the quotient and the fractional part of the two integers10
Youll need something along the lines of hellip
double aDouble double bDouble
etc
To read a number into aDouble you could use
cin gtgt aDouble
Task 2
Modify your EvenI program to read in two characters Enter the characters a and Z
Output the two characters with the character case changed ie a becomes A and Z becomes z
You will need to look online or at in 12120 to establish the ASCII integer values of each character hellip you can alter a characters case by treating it as an integer and
To convert integers (or the results of evaluating integer expressions) to say characters we need to use a cast Eg
int i = 65
cout ltlt static_castltchargt(i + 32)
10 Trivia quotient comes from the Latin quotiens for how many times For example when dividing twenty by three the quotient is six and two thirds You can use a modulus b to get the fractional part
27
then by addingsubtracting tofrom it
Task 3
Open the skeleton project called Address and modify it so that it can be used to collect some user data
Output this collected data to screen as shown in Figure 1
Note that youll have to have include ltstringgt in order to use getline()
Figure 1
Visual Studio builds projects in one of two different modes ndash Debug or Release we will always use the Debug mode (a Release build is normally only used when a product is being beta tested ie late in the cycle)
When using Visual Studio (or most other IDEs for that matter) we normally do not have to concern ourselves with the location of the executable that is built by the program ndash because we normally run it from within Visual Studio itself However and just for your information really the exe for a debug build will always be located in the Debug folder immediately below the projects root folder ie for this project Addressexe is located in the (exercise solut ion) Address Debug folder whilst a version built in Release mode would be in the (exercise solut ion) Address Release folder
Debug builds contain extra diagnostic code that is automatically inserted by the compiler
28
3 Basic Control Flow The programs you have created so far are limited in that they run through a sequence of instructions once and then stop Most computer programs will make decisions and carry out different actions determined by the user input
C++ has three kinds of control structures
Sequence statement - the computer executes the statements one after another All the programs you have written so far use sequence statements
Select ion statements - if ifelse switch
The if selection statement selects an action if a condition is true or skips the action if the condition is false
The ifelse selection statement selects an action if a condition is true or performs a different action if the condition is false
The switch multiple selection statement can be used to perform many different actions based on a character or integer value
Repeti t ion statements - while for do while
The while and for statements perform actions within their bodies zero or more times If the loop condition test is initially false no actions will occur
The dowhile statement will perform the actions in the body at least once (the test ndash as to whether to continue - is at the end)
Selection - ifhellipelse statement
The if selection structure is used to choose among alternative courses of action The structure of the statement is
if(mark gt= 50)
cout ltlt Passed
else
cout ltlt Failed
If the condition (mark gt= 50) is t rue the statement following it is executed cout ltlt Passed
If the condition is false the statement is ignored and control is passed to the else part of the selection and statement following else is then executed cout ltlt Failed
ifelse selection statements can also be nested within other ifelse selection statements
29
Exercise 3 SearchString
Task 4
Open the skeleton project called SearchStr ing
You will need to include ltstringgt at the top of the code to complete this exercise See page 158 for more on the string class functionality
Modify the program to display a string of text to the user
The user should then be prompted to select a word from the sentence and input a replacement word Your program should replace one with the other You will want to See section 12119 on string functionality
The prompting string should be shown both before and after the update
Tips
Given a string s initialised to
string s = C++ at the University of Oxford
string t
int i = sfind(U)
cout ltlt i ltlt endl 11
t = ssubstr(0 i) bit before U in t
t = t + ancient + + ssubstr(i) +
Outputs C++ at the ancient University of Oxford
cout ltlt t ltlt endl
Puzzled Programmers
Using if if else nested ifs switch and the conditional operator -
Task 1
Solving puzzles
Open the I fp project and WITHOUT compilingrunning it determine its output
You will need to consult the operator precedence table in section 1216
You shouldnt compile or run the program to start with ndash the idea here is for you to determine its output on paper11
Tip you might want to consider tidying up the codes layout before attempting to solve it
void out(int n) is a function We havent covered functions yet but it makes sense to use one here and so we have Suffice to say for now that using out(some value) will output the value to the console window
11 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
30
Functions will be explained fully soon
Compile and run the program ndash if your workings from Step 1 differ from the output you should determine where you went wrong
Selection - switch multiple selection statement
The switch multiple selection statement can be used to perform many different actions based only on a single integer value Note however the switch statement can only be applied in narrow circumstances The tests must be constants and be integers Lets compare the two statements
int num switch(num) case 1 cout ltlt num = one
double num switch(num) case 11 cout ltlt num = 11
OK ndash Test is 1 a constant and an integer NOT OK ndash Test is not constant integer
Repetition ndash while dohellipwhile and for loops
The while statement is commonly used to carry out repeated steps perhaps reading in values before doing a calculation on values read in The format of the code is
while(condition)
statement
This can be read as whi le the condition is t rue continue to do the statements until the condition is false
31
The Collatz Conjecture
Win a million dollars
Task 1
Open and complete the project called Col latz (use a while() loop)
Given any positive integer if the number is even divide it by two else treble it and then add one If the result is one stop else repeat the process
The Collatz conjecture says that given any starting value the process above will eventually hal t (goes to one and stops)
Eg setting n to 9 as a starting point successive values would be
28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
It is not known whether the Collatz conjecture is true Fame and fortune await anyone who can prove it httpenwikipediaorgwikiCollatz_conjecture
A Collatz tree as visualised by Edmund Harriss
32
This image is a sample from the colouring book Visions of the Universe by Alex Bellos and Edmund Harriss
Get your own hi-res version for colouring-in here and see here for an explanation
33
Task 2
Re-implement your code so as to use a for() loop (this will be a lot easier than you might first think)
Not essential for this task but as we mention for loops you might like to look at the for project to see how a for loop can be animated to show how the three sections of it work in order
Mixing loops
Task 1
Open and modify the skeleton project called Factor ial
Modify it to use different repetition statements to calculate and display the factorial of a value entered by the user (they should enter a value between 1 and 10 inclusive)
Example use a while loop to prompt for an input value (between 1 and 10) and a for loop to calculate the factorial result
The output should be like that shown in Figure 2 below
Factorials12
The factorial of 5 (usually written as 5) is
1 x 2 x 3 x 4 x 5 = 120
If factorials are new to you think of them as defining the number of ways to arrange n items
To avoid displaying results in scient i f ic notat ion use
cout ltlt setprecision(0) ltlt fixed
setprecision() requires include ltiomanipgt
12 0 Is defined to be 1
34
Figure 2
PLUSPLUS Recursion
Come back to this after weve covered functions
Note that our solution optionally also uses a function and recursion to find the same factorial If you open it you will see that just after where we perform the output above we have commented out an extra line of code (uncomment and rebuild to see it in action)
We havent covered recursion in this C++ course yet but its basically the process of solving a problem in terms of smaller versions of the same problem Since the problem gets smaller each time the process eventually terminates in a problem (the base case) that can be solved directly When defining a recursive function be sure of three things 1 The problem gets smaller each time 2 Include a solution for the base case And 3 Each case is handled correctly
The recursive function looks like this ndash add then test it in your own solution
Factorial function using recursion
long long int recur_factorial(long long int n)
return n lt 1 1 n recur_factorial(n - 1)
The question mark is the conditional operator and is used with the colon to form the functional equivalent of an if then else
35
If the expression before the is true then the expressionstatement to the left of the is evaluated otherwise the one after the is evaluated Eg these are equivalent
x boo() hoo()
if(x)
boo()
else
hoo()
4 Logical and Bitwise Operators
41 Logical
Quite often we will want to perform some action if two things are true and we can achieve this using nested if statements eg
if(onething == true)
if(secondthing == true)
do something
In C++ we can achieve the same result through the use of the l ogical And operator - ampamp
if(onething == true ampamp secondthing == true)
do something
ampamp is a binary operator ndash meaning that it takes two arguments (nothing to do with base 2) eg Op1 ampamp Op2 The expressions Op1 and Op2 must be capable of evaluating to t rue or false (false in C++ has the value 0 whilst any other value is considered true) and both Op1 and Op2 have to be true in order to have the conditional part execute eg if(x ampamp y) Z = 10 Here both x and y must have non-zero values in order for z to be assigned the value 10 Note again that this is equivalent to
36
if(x)
if(y)
z = 10
The truth table for logical And is as follows ndash note that both Op1 AND Op2 have to be true for the result to be true
Logical And
Op1 Op2 Result
True True True
True False False
False True False
False False False
We also have a Logical Or operator (||) in C++ and its truth table looks like this ndash note that its one OR the other that has to be true in order for the result to be true here
Logical Or
Op1 Op2 Result
True True True
True False True
False True True
False False False
The remaining logical operator we have is the unary Logical Not (the exclamation mark is used for this)
Logical Not
Op1 Result
True False
False True
Logical ampamp and Logical || short-circuit ie for ampamp if the expression on the left-hand side is found to be false then the expression on the right is never evaluated as the whole will evaluate to false (because to be true both sides have to be true and we know that the first one is false at this point)
37
The same is true for logical || in that the right-hand expression is not evaluated if the left is found to be true (the whole will evaluate to true because the left is true so there is no need to evaluate the right-hand expression)
42 Bitwise
PLUSPLUS Base Two and Bits
We also have bitwise versions of the logical operators ndash plus some extra ones Bitwise operators work on a variables individual binary bits ndash rather than the value of all the bits taken as a whole For bitwise And we do not use ampamp but use just a single amp The same is true for bitwise Or we just use a single | and not || Bitwise Not is a little different we use ~ (the tilde) for bitwise Not
The additional bitwise operators we have are for bitwise XOr ndash for which we use the ^ symbol and lastly for left and right bit shifting we use ltlt and gtgt
Bitwise operators work on binary bits (1s and 0s) whereas the logical operators work on values equating to either true or false
For example consider the following code
int w = 10 int x = 42
int y = w amp x
int z = w ampamp x
cout ltlt y ltlt endl
cout ltlt z ltlt endl
The base-2 binary representation of 10 is 001010 and for 42 it is 101010 So w amp x means
001010 101010 amp ------ 001010 ------
Remember And is one and the other
Now let us consider w ampamp x Here were not interested in ws or xs bits just whether when taken together they are zero or something else Here both are non-zero so both are considered to be t rue and if we refer to our truth table from earlier on we will see that the result will be t rue When we assign that to an integer like were doing here the value assigned will be 1
38
Shifts
The shift operators shift the binary bits left or right Bits that do not fit fall off the ends and bits are replaced with zeros when shifting left ie bits do not rotate and come back on the other end again When shifting right the sign-bit may be preserved depending upon whether youre using a signed or unsigned integer
Shifts are useful for all sorts of things but one of the obvious uses is to multiply and divide eg x = 2 x = x ltlt 1 shifts the bits in x one place to the left so given that xs value is 00000010 in binary x = x ltlt 1 turns x into 00000100 which is 4 So x = x ltlt 1 is like saying x = x 2 You can of course divide by right shifting
XOr
The rule for XOr is one or the other but not both ie 1 ^ 0 = 1 (just like 1 | 0) but whereas 1 | 1 = 1 with 1 ^ 1 the answer is 0
Note that we do not have a logical XOr operator in C++ as we can just use = (not equal to) ndash see the (demonstrat ion) Logical XOr project
Practising with Logical and Bitwise operators
You will need to use the Precedence and Associativity table in 1216 to complete these tasks
Task 1
Open the Logical project As earlier DO NOT compilerun this yet
You will need to consult the operator precedence table in section 1216
On paper determine the programs output13
Run the program ndash output as expected
Task 2
Open the Bitwise ndash
unsigned project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Unsigned The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
13 This puzzle is taken from The C Puzzle Book by Alan R Feuer ISBN-10 0201604612
39
PLUSPLUS Signs and bits
Task 1
This one is tough as you should really know something about Twos Complement arithmetic to complete this
Open the Bitwise ndash s igned
project Again DO NOT compilerun this yet
(exercise solut ion)
Bi twise-Signed The solution has a running commentary
On paper determine the programs output
Run the program ndash output as expected
5 Introduction to Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine (which will also be a function) Encapsulat ion is data information or detail hiding If youre mathematically minded you may think of a C++ function as being very similar to one in mathematics ie a mechanism for mapping one thing to another
Once a function is written the detail of how it works is not important It is only necessary to understand what if any inputs the function needs (its parameters) and what output is produced (the functions return value)
The use of functions provides several benefits but the main one is that it makes programs significantly easier to understand and maintain The main program function can consist of a series of function calls rather than hundreds of lines of code A second benefit is that well written functions can be reused across multiple programs
You have to tell the compiler about a function before you use it and this is normally done using a prototype early in the program A function prototype consists of the return type a funct ion name and a parameter l is t - indicating the data the function will receive ndash and is terminated using a semicolon Eg
int someFunc(int int)
This tells the compiler that there is a function (somewhere) called someFunc that takes two integers as its input and returns an integer value for its output
40
Using a prototype is a way of telling the compiler the data types of any return value and of any parameters being passed and enables error checking to be done
The function defini t ion consists of the modified prototype and a function body which is a block of code enclosed in parenthesis which does the work Eg
int someFunc(int a int b)
return a + b
Here we have named the two inputs a and b and we can see that the functions job is to add these two value and to return them As this function returns a value (the sum of a and b) it may be used to expressions like this
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
Arguments can be passed to functions in two ways pass-by-value the default is where a copy of the argument value in the main program is made and then passed to the function The copy in the function only exists in memory as long as the function is active When the code within function has been run to completion the memory is released and the value held there is lost Any changes made to the copy passed to the function do not affect the original variable in any way For example if we altered and used someFunc like this
int someFunc(int a int b)
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 20
41
Note that because we passed a copy of b to the function that the line b = b 2 alters the copy (which then isnt used) and not the original
Arguments can also be passed-by-reference When arguments are passed in this way any changes made to the arguments in the function are reflected by corresponding changes to that data variable in the calling part of the program Pass-by-reference is good for performance reasons because it can eliminate the pass-by-value overhead of copying large amounts of data (In later sections we will examine how pointers can be used to fake pass-by-reference) Eg this will alter b now
int someFunc(int a int amp b) Note the amp
int res = a + b
b = b 2
return res
int a = 10 b = 20 c = 30
cout ltlt c + someFunc(a b) outputs 60
cout ltlt b outputs 40
See section 521 for more on this subject
Creating a function
The format of a function prototype is
return_data_type FunctionName ( argument_l ist )
The function CtoF - void CtoF(int temp) - has no return data type (void) its name is CtoF and it accepts a single input argument called temp of type int (integer)
It is not strictly necessary to give the argument a name (temp) in a function prototype you saw this above in int someFunc(int int) However the argument type must be specified The statement void CtoF(int) is therefore an alternative prototype
The following exercise is an introduction to functions You will learn a lot more about functions in later exercises
42
Writing functions
Task 1
Open the project EvenI you created earlier and change the structure of the program to make use of functions
Solution in (exercise solut ion)
EvenI I
Read two integers in to main() and pass them to a function The prototype is void intCalcs(int int)
intCalcs() function should calculate and display the result of the division and modulus of the two variables passed see Figure 3
Read in two doubles to variables in main() Pass the two doubles and the value of one integer to the second function the prototype is int Calcs(double double int)
Within function Calcs() write statements to produce the output as shown in Figure 3 Most of the code already exists within main()
Return the result of the multiplication of one double and an integer cast this value as an integer
Display the returned value within main() as shown in Figure 3
Figure 3
43
Using a struct
Task 1
Open the project Person
Solution in (exercise solut ion)
Person
As you saw during the presentation we can keep related data together using the struct keyword For example say we define a thing as follows
struct thing
int x
string y
double z
Having done this we can now create as many thing objects as we wish ndash simply by declaring them as we would say an integer
thing a
thing b
Each thing object a and b contains its own x y and z member variables eg
ax = 10 thing as x member set to 10
bx = 20 thing bs x member set to 20
cout ltlt ax ltlt endl outputs 10
cout ltlt bx ltlt endl outputs 20
Complete the exercise by creating and populating a struct Person object Once populated amend the printPerson() function so as to output the persons details
44
PLUSPLUS When Things Go Wrong
Going back to Exercise 8 if you havent tried it already enter zero as your second number What happens
C++ contains mechanisms for catching errors in the form of a trycatch mechanism
cin gtgt y Enter zero
try
intResult = x y
catch(myException amp e)
cout ltlt ewhat() ltlt endl
catch()
cout ltlt Generic oops ltlt endl
Modify your code so as to catch the divide by zero
Hopefully try and catch are fairly self-evident try something and catch any error if something goes wrong
There are two catch blocks here One tries to catch a myException object (we cannot see the definition of this classstruct here) and the other tries to catch anything else that is missed by catch(myException amp e) The amp says that the myException object e is being passed to the catch handler by reference Well learn what this means a little later in section 521
So did you see the Generic oops message appear
Your C++ compiler doesnt have to catch the divide by zero error ndash doing such a thing results in undefined behaviour This is because an arithmetic exception is an OS or processor exception - which is not the same as a C++ exception - hence it cannot be caught by a in a try catch block
To catch errors like this we either need extra support from the compiler14 andor operating system or to write some extra code For example we could do this
14 See also C signal handling httpenwikipediaorgwikiC_signal_handling
45
cin gtgt y Enter zero
if(y gt 0)
intResult = x y
However first we have to realise that this is a possible source of a runtime error and secondly we have to write (correctly) the code to handle the condition
Windows has built-in exception handling ndash called Structured Exception Handl ing (SEH) and we can generate code that uses this in support of the try catch structure used earlier
To enable this we need to tell the compiler to generate code that links into the SEH mechanism
To do this open the Project | ltproject namegt Properties hellip dialog box and in the Code Generation section select Yes wi th SEH Exceptions ( EHa) in the Enable C++
Exceptions line See Figure 4
46
Figure 4
The Monty Hall problem
The Monty Hall problem is a probability puzzle loosely based on the American television game show Lets Make a Deal and named after the shows original host Monty Hall
It goes like this
You are on a game show where you are shown three closed doors You are told that behind one of them is a new car and that behind the other two are goats
Two pieces of essential information at this stage 1 your goal is to win the car 2 the game show host knows what is behind each door
Lets walk through a trial game
The game show hosts asks you to choose a door ndash lets say you choose door number 1 (your door remains closed) The host now opens one of the remaining doors to reveal a goat (as there are two goats they can of course always do this) lets say they open door number 3
47
The situation is now as follows you have chosen door number 1 Only door number 3 is open and it reveals a goat The host now asks you if you would like to switch your door to the only other closed door - door number 2 At this stage you must either stick with door number 1 or switch to door number 2 and at that point the host will open the door youve chosen to reveal your prize
The question is when youre offered the chance should you stick or should you swap - will swapping increase your chance of winning the car or is it just 5050 The claim made here is that by swapping doors you will double your chance of winning the car What does your completed project claim
Task 1
Open and complete the incomplete project MontyHal l
The goal of this project to provide a simulation of problem outlined above
The function
int getRandomDoor(int n = 3)
return rand() n + 1
is used to choose a door number between 1 and 3 (inclusive)
Note that it has a default argument ie if it is called without an argument like this int val = getRandomDoor() the argument n is set to 3 by default and val will be set to a value between 1 and 3 However if it is called like this int val = getRandomDoor(10) then n is set to 10 and val will receive a value in the range of 1 to 10
48
More Functions
Task 1
Open the incomplete project IsLeap
The program asks for a year and determines whether the year is or will be a leap year
You need to complete the function IsLeap(int y) to implement the necessary code
Although the program is incomplete the program contains pseudo code for the algorithm required to compute the answer The pseudo is also show opposite
if year modulo 4 is 0
then
if year modulo 100 is 0
then
if year modulo 400 is 0
then
is_leap_year
else
not_leap_year
else
is_leap_year
else
not_leap_year
Figure 5
49
PLUSPLUS IsLeap in a line
Task 1
Extra points for implementing the IsLeap() function in just a single line of code This could be done using ampamp and || or by using the operator (a short form of if then else)
If you completed this step how readable is your code when compared to the if else version on the right
52 Algorithms
Algorithms
An Aside Big-O notation and Algorithm Complexity feel free to jump over this to Task 1
As programmers we usually implement the various parts of any new program in the simplest and most straight-forward way possible Then later if we find parts of our program are slow (causing what are called hot-spots) we will look again at the code to see if there is a better way to do whatever it is that is taking up the time
As a general rule the most optimal algorithms run in the shortest possible constant t ime ndash such algorithms are often symbolised using O(1) whereas the worst run in quadratic cubic exponential or factorial time (you can think of the O [called Big-Oh] as meaning in the Order of for some input n)
Usually were often happy with those running in O(n) (in the order of n) time ie their running time scales linearly with the number of steps or operations they involve Loops invariably signal O(n) parts of any algorithm
This is best explained using an example
50
Task 1 Understanding Gauss algorithm
Q How would you sum the integers from 1 to n where n is say 100
The obvious way is to use a loop
int tot = 0
for(int i = 1 n = 100 i lt= n ++i)
tot += i
This is fine for small values of n but not so good for very large ones
Interestingly it is said that this self-same problem was once given to a class of children which included one Carl Friedrich Gauss (presumably the teacher wanted to keep his charges occupied for a time) While most of the children started working at the problem (using the loop approach above) Gauss thought about it for a moment and then wrote down the solution 5050
The algorithm Gauss used may be easily demonstrated using the values 1 ndash 10
Gauss realised that if he wrote out the values twice (whether on paper or just in his head) once forward and once in reverse that he could sum each column formed to 11
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
1+10 2+9 3+8 4+7 5+6 6+5 7+4 8+3 9+2 10+1
=11 =11 =11 =11 =11 =11 =11 =11 =11 =11
Then sum of 1 ndash 10 is then 11 10 (columns) = 110 2 = 55 (we divided by two because we used each value twice)
Coming back to algorithm runtimes you can see that when using a loop summing 1 ndash 1000 will take ten times longer than summing 1 ndash 100 which will take ten times longer than summing 1 - 10 However by using Gauss approach we can arrive at the answer for any range of values in the same time this is what we mean by a constant time algorithm
51
Task 2
Open the incomplete project SumIntSeries
Complete the project so as to implement Gauss algorithm for any continuous range of integers
The solution project is (exercise solut ion)
SumIntSer ies
The general formula required is
((119948 minus 119947) + 120783)(119947 + 119948)
120784
Or in a more code form
Sum = ((k - j) + 1) (j + k) 2
Where j and k are the starting and ending values in the range respectively (both inclusive)
Functions and Pass by Reference
In the previous section when working with functions all arguments passed to the functions were copies of variable values from main() The arguments were passed by their value
Pass by Value is the default argument passing mechanism for C++ (and the C language)
In pass by value when a function is passed an argument it receives a copy of the value from the calling function (main() in previous examples) This copy remains in scope until the called function has completed and returned at which time the copy is destroyed
Therefore a function that takes value-arguments cannot change a passed variables value because any changes only apply to copies and not to the actual callers variables
An alternate passing scheme is called Pass by Reference
Passing variables to functions by reference is very useful when we need to change or update variable(s) via a function (it is also a faster mechanism than pass by value as no copies have to be made)
Under the covers pass by reference involves passing a memory address and not a copy of the data to the function This is usually more efficient than passing by value because there is no requirement to copy memory However this argument passing mechanism enables a function to modify any argument even if its not supposed to To avoid this we usually declare all read-only parameters as const and pass them by reference
The format of a function prototype when using call by reference is
return-data-type funct ion-name (reference parameter) To indicate a reference parameter an ampersand (amp) is written in the function prototype and header after the parameter type name
The statement void squared(int amp) has no return data type (void) its name is squared and it accepts a reference parameter (amp) of type int (integer)
52
The function definition would be something like this
void squared(int amp inVal)
inVal = inVal inVal inVal
The function call to it would look like this
squared(aValue)
As mentioned above pass by reference is normally used for one of two reasons 1 Because we want to be able to change a passed variable inside a called function 2 Because we want the speed associated with a pass by reference
In 2 we will normally protect our argument by using const in the called function Eg say we want to pass the double argument x to a function f() and take the least possible time about doing it (and given that function f() shouldnt alter x) we would use the following code
void f(const double x)
Use x in some calculation Note that if
x appears on the left hand side of an assignment operator
that it will result in a compilation error
Pass arguments by reference
Task 1
Open the project (demonstrat ion) FunctionRef
Compile and run the program The output should be the same as shown in Figure 6
53
Figure 6
Examine the function prototype
void squared(int amp)
This shows the function squared accepts a reference
parameter of type int The reference parameter is ndash under the covers - the memory address of the argument passed to the function
The function uses this address to both get and set the value stored in variable a (value 21) in main() A reference to this address is passed to the function with the function call squared(a)
Examine the function void squared(int amp x)
Under the covers references to x refer to the address of the variable a in main (that holds the value 21) Ie x and a reference the same piece of memory (the word object was deliberately not used there) So we can think of x and a as two names for the same item
Returning values from functions
In previous programs we have most often produced output (using cout) from within the functions However to be of most use and general utility functions should return resultsinformation rather than output it
Functions may return results in one of two ways 1 via a return value or 2 via arguments ndash either passed as references or via pointer (address)
Non void Functions return a single value ndash if you will they evaluate to this value As such non-void functions may be used in expressions Eg
54
w = x sqrt(y) z
The function sqrt() is replaced with the value of whatever the square root of y happens to be For example if y has the value 4 then to evaluate x sqrt(y) z fully the sqrt() function has to be called ndash where it returns 2 This value is then substituted into the expression for further evaluation ie it becomes w = x 2 z
The second way for functions to return results is via its parameters ndash if they are references or passed via memory addresses Eg
void doubleIt(int amp n)
return n 2 Error The void means doesnt return a value
doubleIt() is a void function ndash so it cannot contain a return statement ndash so it cannot evaluate to anything ndash so it cannot be used in an expression
x = doubleIt(y) error
However the function is still able to return a result (modify something outside of itself is perhaps a better way of putting it)
void doubleIt(int amp n) using amp - a reference
n = n 2
55
doubleIt() cannot (still) be used in an expression but it can change things
int x = 10
doubleIt(x)
cout ltlt x Outputs 20
Why would you use references like this Well references are mainly used for speed (by passing an actual external entity a copy does not have to be made) but they are also useful when multiple values (entities) might best be updated via a single operation (function call)
int x y z
x = y = z = 10
doubleAll(x y z)
void doubleAll(int amp a int amp b int amp c)
a = a 2 b = b 2 c = c 2
Side effects
Going back to w = x sqrt(y) z
Lets replace sqrt() with our own function and cause some havoc
double havoc(double amp d)
++x
d = sqrt(d)
return d
x = 3
w = x havoc(y) z
56
Here the value of y has been changed (yet it is not clear that could happen from the functions call site ndash where it was called from) and so has x Also what value for x will be used in x havoc(y) z Will it be 3 or 4 These sorts of issues are called side-effects
This is one problem (or advantage) with reference arguments ndash and that is that they can cause a change in a variable outside of the function being called
One way to protect against this is to use const references eg
double havoc(const double amp d)
++x
d = sqrt(d) Compilation error here
return d
57
Returning a value from a function
Task 1
Open the TempConver t
project
Run the program The output should be the same as shown in Figure 7
Examine the function prototype
double convert(double temp int mode)
This function prototype has a return type of double When the function is called and calculations are completed a double value is returned to the caller
Examine the function definition The function definition matches the prototype indicating a double and an integer are being passed to the function and a double is being returned
Examine the function body The two statements below convert the temperature input The conversion type required is identified using the user input mode and a switch selection
The statement (temp - 32) 5 9 is used to calculate the temp in Centigrade
The statement 18 temp + 32 is used to calculate the temp in Fahrenheit
Figure 7
58
PLUSPLUS Arithmetic Bases
Task 2
Open compile and run the partially complete Bases project
Note that the project isnt complete
The program uses intrinsic functionality to output values in hexadecimal and octal ndash base 16 and base 8 Both these bases are useful in programming its all to do with binary and the size of a byte
Note that there isnt a bin equivalent to hex and oct and that we have instead written a function called bin1() to convert a value into its binary (base 2) representation
Understanding how bin1() works
bin1 uses the modulus operator () and the right shift operator (gtgt) to work eg 42 in binary is 101010
25 24 23 22 21 20
32 16 8 4 2 1
----------------------
1 0 1 0 1 0
----------------------
1 32 + 0 16 + 1 8 + 0 4 + 1 2 + 0 1 = 42
The function progresses like this
42 2 has remainder zero (false as evaluated in the if) If the if test is true we store a 1 else we store a 0 We then divide 42 by 2 by right shifting it one place ndash but just replace that with n = 42 2 if you prefer We then loop while we have a non-zero value in n to operate on hellip
42 2 = 210 42 2 = 0 if(42 2) = false string value = 0
21 2 = 105 21 2 = 1 if(21 2) = true string value = 1
10 2 = 50 10 2 = 0 if(10 2) = false string value = 0
5 2 = 25 5 2 = 1 if(5 2) = true string value = 1
2 2 = 10 2 2 = 0 if(2 2) = false string value = 0
1 2 = 05 1 2 = 1 if(1 2) = true string value = 1
59
Task 3
The project needs completing specifically it needs the function bin2() writing
We could write such a function as bin1 in a variety of ways and wed like you to write a new function called bin2() that produces the same output as bin1() here
Heres a step by step algorithm for implementing bin2()
Youll use either gtgt or and the bitwise And (amp) operator
Take the functions input (the number to convert) in as a parameter called n To keep it as simple as possible for now you could use plain int types rather than the unsigned long long type we used so the functions signature would look like string bin2(int n)
1 In the function create an integer called i and initialise it to 1
2 Realise that if you left shift the single bit in i (use ltlt or multiply it by 2) it will take on the values 2 4 8 16 32 hellip until it eventually goes to 0 ndash as you shift the bit off of the end
3 Recognise that you could compare your shifting bit with one in the same position in n using bitwise And Ie if((n amp i) == 1) then you know youll need a 1 in your output string for the bit position in n (2 4 8 ) given by is value at this point
4 Build up your result string as you proceed
Change your int n and int i to unsigned long long int and re-run
Try using other integer types ndash signed and unsigned
Lastly examine the solution project in (exercise
solut ion) Bases
60
Figure 8
61
Searching for Sequences
Task 1
Open and modify the incomplete project called called HeadsOrTai ls
When all completed the output should be similar to that shown in
Figure 9
This is the (exercise
solut ion) HeadsOrTai ls project
The programs purpose is to look for a sequence of simulated coin tosses ndash a series consisting of Hs and Ts
The program is complete (as in it runs) but it has some issues At first test it using quite short sequences
The timing information displayed by the application is included simply to demonstrate a timing mechanism that can be used to test the efficiency of the code
The first problem is that the user can currently enter characters other than H or T (h and t are ok as the input is converted to uppercase ndash note the string is passed by reference to toupper() which uses a pointer (which well cover later) to process the string
The second problem is that as it stands the algorithm isnt very optimal if we do not find our pattern we add the result of another coin toss to the current sequence and then re-check the sequence in its entirety
For example if were looking for HHTHH and the generated sequence is currently HTTHHHTTHTHHTTH we will fail to find HHTHH and then proceed to add another coin-toss result at the end ndash HTTHHHTTHTHHTTHH We will then scan this for HHTHH However as we know that we failed to find HHTHH before we added the extra coin-toss re-checking the previously checked sequence is pointless and very time consuming (think how this would (or wouldnt) scale) Your task here is to think of and implement another more optimal approach
62
Figure 9
Task 2
Open the HTTvsHTH project you will find that the project will compile correctly but displays an incorrect result
When completed the program can be used to check how many coin-tosses are required on average to see a particular sequence
Why should that be of interest Because sometimes its rather surprising For example test how many tosses are needed to see say HTH and then HTT
When the program is corrected the output should be as shown in Figure 10
63
Figure 10
PLUSPLUS Optimising Searching for Sequences
Task 1
As it stands the program (yours and ours) encodes a coin toss as a character ndasheither an H or a T Each character is encoded using at least 8-bits and so checking whether a generated sequence is the sequence were looking for means performing a string comparison which is costly in terms of clock-cycles Of course generating and storing the new coin toss also requires the use of these costly string operations
As we have just two tokens as an alternative to generating and storing characters and performing string operations we could encode a sequence as a series of bits For example the sequence HTH could be encoded as 101 in binary (5 in decimal) You can set the corresponding individual bits in an int using the bitwise Or operator | (a vertical bar) eg int n = 0 n = n | i which youd most likely do as a result of scanning the users entered search-sequence string a character at a time In this way you could encode the sequence HTHHTHHTHHTHHTHH in a single sixteen bit unsigned int
Additional operators needed to implement sequence checking and H or T bit manipulation are bitwise And (amp) and the left shift operator (ltlt)
You will find more information on some of these operators just a little below
64
Evolving Searching for Sequences
Task 1
Looking for sequences in stringssequences is an interesting and complex problem in computing and also in genetics where the string being searched could be a DNA sequence and pattern could represent a gene perhaps with a snip (a modificationmutation)
Modify your HeadsOrTai ls program (or our solution) so that instead of Hs and Ts it generates and searches for Gs As Ts and Cs instead
Randomly generate a GCTA sequence and a similar pattern to find within the sequence
How much more time and variation is required in this slightly more complex situation
Conduct a few experiments and using Excel graph your results (copy and paste some data highlight it and then select Excels line graph ndash Excel should then automatically plot your data)
Extrapolate The human genome is how long A gene might contain how many bases How difficult is the task of finding interesting sequences in the human genome How about checking for the odd mutation (insertion transposition deletion) ndash fuzzy matching
A solution for this problem can be found in the (demonstrat ion) GATTACA project
6 Classes and Objects In the previous section we have been working with simple programs that display messages to the user store data input as different data types manipulate the data in some way and output the results to screen
We will now start to look at C++ objects and classes
In the real world there are objects everywhere students staff cars birds houses and many more All objects have at tr ibutes these are similar to the variables created in previous tasks Some attributes of a student may be height weight race course of study etc All objects exhibit behaviours or operations cars accelerate and decelerate students matriculate enrol on courses and leave university
65
Now what is the relationship between a class and an object A good analogy would be from an architects blueprint for a house it would be possible to build many houses Similarly from a class in C++ it would be possible to build many objects
If we had a student class we could create many objects from the student class to represent the many students enrolling Each of these objects would be uniquely identified They would share common attributes and exhibit common behaviours If we wanted an object to perform some task we would call the appropriate member function allowing an operationaction to take place changing the behaviour of that object
Member functions are different from the functions you have created so far Member functions are always associated with objects and are usually called or invoked using a dot notation object member funct ionname() An example is student1getName() The object instance is student1 and the member function is getName()
Member functions contain the detail of how the technical aspects of some operation will be processed When member functions are invoked these technical issues are hidden from the end user When the member function is asked to do some operation a message is sent (a member-function call) telling the member function of that object to perform the operation detailed in the function
Functions are not completely new we have had a brief introduction and you have already created some of your own Note also that main() is a function that is called automatically when you run your program However it is not a member function as there is no object associated with it
Creating your first class
Creating a class
Task 1
Open the project called StudentUG
Compile and run the program It should look like Figure 11
66
Figure 11
Before you can create the object myName it is necessary to define the class from which the object will be created The class definition is shown below
class StudentUG Start of class definition
public
void displayName() Start of member function
cout ltlt My name is Michael Cain ltlt endl
Note a semicolon is required at the end of the class definition
Within main() the statement StudentUG myName creates the object myName of class StudentUG In effect StudentUG is a new type
The statement myNamedisplayName() is used to call the member function displayName() of object myName
As we have seen previously the function main() is called automatically when our programs are executed However member functions (displayname() is one we could have many) must be called in this way objectInstanceNamefunctionName() when dealing with an
67
object directly and like this objectInstanceName-gtfunctionName() if working through a pointer to an object (more on pointers later)
The member function displayName() is preceded by the word void All functions can return values this one does not The word void preceding the function name indicates nothing is being returned If this function returned an integer the definition would be int displayName()
When you use functions it is common to pass data (called parameters) to the function The function then manipulates the data before displaying an output andor returning a value
To pass a parameter to the function in the studentUG class the calling statement in main() would be
myNamedisplayName(name) where name is a string (a series of characters) that contains a value read in from the keyboard
In order for the function displayName() to recognise the parameter being passed the function declaration is changed to include the parameter (name) and type (string) as shown in below
void displayName(string name)
cout ltlt My name is ltlt name ltlt endl
Figure 12
Member functions and Passing parameters
Passing parameters
Task 1
Modify StudentUG to read in a student name The name should be passed to a member function The parameter should be output from within the function to welcome the user to C++ programming
68
Task 2
Modify the program in the above task to read in two more names Each name will be for a different student and you will need to create additional objects (instances) of the class
Data Members
In most of the programs written so far the variables have been declared inside the main() function Variables declared inside a function are local to that function and cannot be accessed from outside that function
You have created a student class and it would be reasonable to assume that a student would be following a particular course So courseName might be one of several attributes of a StudentUG object Attributes are represented as variables in a class defini t ion These variables are called data members and must be declared inside a class definition When you create an object of a StudentUG class each object has a unique memory location for its data members
Figure 13 shows data member name declared in the class definition The access specifier private means that only member functions of the class in which the attribute was declared can use this data member
private string name
Figure 13
When data members are declared as private the data is hidden This is called encapsulat ion and means the attributes of the object are hidden and can only be accessed via member functions
As there is no direct way to change a data member you will also need to create a member
funct ion to set the data member to a value and create a second member funct ion to output the value held there
Data members can also be declared public A data member that is declared public can be accessed from any (non-member) function
A protected data member can only be accessed by member functions of its own class and by member functions of classes derived from this class We will learn more about derived classes and inheritance later
69
Using data members
Task 1
Open the project called StudentCoursesln
Compile and run the program it should look like Figure 14
Figure 14
Task 2
Examine the member function getCourse() shown in Figure 15
string getCourse()
return course
Figure 15
Task 3
Modify the StudentCourse source file to enable the user to add a student name enrolment date and number of years of course Once entered this data should be output to screen You will need to create additional data members and member funct ions to achieve this
70
More Objects
Task 1
So far you have created one StudentCourse object It is about time we had a second student on the course Create a second object of the class StudentCourse You will need to add the second statement shown in Figure 16 to add the new object student2 Call the member functions passing parameters as necessary
Figure 16
Constructors
When you create objects from the StudentCourse class it is necessary to give initial values to all the data members If we were entering data for five people and they were all following the same course of study it would make sense to initialise the course data member (it is possible to initialise some or all of the data members) when each object is created
A constructor is a special kind of function that must have the same name as the class Constructors are normally defined to be publ ic and never have a return type They can be used to automatically initialise data members
In previous programs you have written a defaul t constructor has been provided by the compiler However it is not possible to pass parameters to a default constructor function so the data members in the programs created so far have not been automatically
71
initialised To initialise these data members you created member functions that assigned values to data members
Although a default constructor is provided at compilation time it is a good idea to create your own so that the data members can be initialised
It is worth noting here that functions (constructors are functions) can be over loaded This means it is possible to have more than one function with the same name Note that overloaded functions (functions with the same name) must have different types of or number of arguments
Constructors (functions) can also be overloaded with more than one function with the same name but different types or number of parameters Fortunately for us the compiler automatically calls the correct function whose parameters match the arguments used in the function call
Using constructors
Task 1
Open the project called Constructorss ln
Compile and run the program it should look like Figure 17
Figure 17
72
Task 2
In the constructor shown in Figure 18 what is the purpose behind course = Note that as the string parameter name has the same name as the class variable that we use the hidden this pointer to access the class variable in the assignment If we didnt do this and simply used name = name instead then all we would be doing is assigning the value in the parameter back to the parameter
StudentCourse(string name)
this -gt name = name
course =
Figure 18
Task 3
Create a third constructor that will take an argument enrolment_date
Add a third object call it student3
Write code that will test this additional constructor
Solution in (exercise
solut ion) Constructors
If time allows add other useful properties (data members) access methods (functions) and constructors
Separating use from declaration and definition
C++ is all about objects and any decent project will usually make use of a number of application or domain specific classes
To keeps things maintainable and to promote code reuse C++ projects usually contain a number of cpp and h files where each h files will usually contain a declaration of a class (sometimes called an interface) Note though that the definition of the class (sometimes called the implementation) ndash the code that implements it ndash will be absent from the h file and will instead reside in an accompanying cpp file
Aside from allowing different teams to more easily work on separate parts of the program one of the main reasons for separating definition from declaration is to enforce abstraction which is a programming (and design) technique that relies on the separation of declaration and implementation For example lets say that your team needs a class that acts a bit like a stack (a last-in first-out or LIFO structure) and as this is required
73
urgently you decide to implement it using a simple array You would then only want to give your team what is absolutely necessary to use this class a single h file for your team members to include in their cpp files If they look in the h file they will only see information on how to use the class but how it does what it does is kept elsewhere in the cpp and that youve withheld Consumers shouldnt need to know how a thing works in order to use it
An obvious advantage to this is that there is no danger in you changing how it works Perhaps you later decide to use a vector instead of the array You go ahead and alter the implementation and your team members are none the wiser ndash after all the interface hasnt altered just the implementation
So how does the project get built Of course the implementation of this class will be required at compile time and you can either do that by including the cpp file directly (which will give away the implementation details of course) or by including it as object code ie compiled C++ code (binary machine code) This is how valuable commercial source code is kept in-house while the binary implementation complete with a h file is provided to customers (you will see an example of this just below in Using external
l ibrar ies and thi rd par ty header f i les )
Any discussion on separating use from declaration and definition should include something on namespaces You introduce a namespace by simply using the keyword and braces Anything entered inside these braces is inside the namespace eg
namespace securityModule class Encryptor using namespace std using namespace securityModule int main() Encryptor e Without the using we would have had to use securityModuleEncryptor e securityModuleEncryptor e2
See the (demonstrat ion) Namespaces project for more on this
74
Separating declaration and definition
Using a header and source file to separate class declaration from definition
Task 1
Open and modify the partially complete skeleton project called Precis ionTimers
Like HeadsOrTai ls this project makes use of the Windows operating system to very precisely measure elapsed time However unlike HeadsOrTai ls we have separated the stopWatch class interface from its implementation
As weve previously mentioned Gauss and algorithm efficiency we could test our theory that summing in a loop is O(n) ie that the time taken scales with n
Examine the project files hrTimercpp and hrTimerh noting that the h file contains just enough information for someone to use the declared class stopWatch whilst htTimercpp contains the implementation of the class
Now look in PrecisionTimerscpp You will see that an instance of the stopWatch class is declared Also note that we include hrTimerh but make no reference to hrTimercpp
As it stands the code calls two functions to calculate the sum of a range of integers sumGauss() and sumLoop() The program outputs the clock-ticks used and time taken in seconds
Note that sumLoop() is incomplete
Complete the sumLoop() function and then choosing suitable values for the ranges upper-bound carry out a few experiments to test if the loop is really O(n)
What is this used to do in hrTimerh15
ifndef HRTIMER
define HRTIMER
endif
15 You should also see pragma once as this is rapidly becoming the alternate way to do this ndash whatever this is of course
75
PLUSPLUS Providing object code only
Task 2
We have provided a separate demonstration project that takes the discussion on this one step further (demonstrat ion)
Separat ingThings
In its current form the project wont compile To compile the project in the Solution Explorer add the existing carcpp file to the source files list that just contains SeparatingThingscpp and recompile carcpp is in the same folder as SeparatingThingscpp
Once youve done that right-click on carcpp in the Solution Explorer and select Remove Very importantly when youre prompted for confirmation choose Remove do not choose Delete Now recompile once more youll see that the project fails to compile as the definition of car has been removed
76
But hold on we created carobj - the compiled object-code version of carcpp during our previous compilation so we could tell the linker about that and all should be well (this more or less duplicates the scene whereby you do not provide source code but provide only object code)
The carobj file will be located somewhere like
CUsersDesktopCourse(demonstration) Separating Things(demonstration) Separating Thingsbincarobj
To add this to your project go to Project | Properties | Configuration Properties | Linker | Input
77
In the right-hand window select Additional Dependencies drop down the list and select ltEdit gt
In the dialog that appears add the full path to carobj (see earlier in Step 2) and press Ok
Lastly recompile the code once more It should compile and run At this point you could if you wanted to delete carcpp altogether
One last thing
If you look in the comments in SeparatingThingscpp you will find a discussion that goes into the advanced topic of hiding things even further This includes a brief discussion of the the so called pimpl pattern (pronounced Pimple this stands for Pointer to Implementation16)
16 httpenwikipediaorgwikiOpaque_pointer
78
PLUSPLUS Using external libraries and third party
header files
Task 3
Open and modify the project called Lot to
Examine the projects comments to understand the programs function Run the program ndash does it work
It is supposed to compute the odds of winning the UKs lottery httpwwwnational-lotterycouk (try as we might we couldnt find the odds on their own website)
The program uses the recursive factorial function used earlier in the course (with bigint being typedef ed as unsigned long long int)
Factorial function using recursion
bigint recur_factorial(bigint n)
return n lt 1 1 n recur_factorial(n - 1)
There is a problem here however in that to compute the odds we must compute some significant factorials ie
49 = 608281864034267560872252163321295376887552831379210240000000000
and
6 (49 - 6) = 43498989405629161658895695089330078205230448640000000000
Sadly our bigint (unsigned long long) can hold a maximum value of 2^64 ndash 1 = 18446744073709551615 ie not hardly big enough
Fortunately in C++ we can define new types like an arbitrarily sized integer (outside of the scope of this course but see the (demonstrat ion) newINT project for a small taste) However this is object orientation ndash surely we can just use an existing already defined arbitrarily sized integer class
79
Task 4
The good news is that in this class you can You can use LEDA (The L ibrary of
Eff ic ient Data types and Algor i thms ) a professional class library of advanced numerical functionality
You will need to download the program called
LEDA-63 i386 msc 10 ( NET 2010) 32 bi t
or
LEDA-63 i386 msc 10 ( NET 2010) 64 bi t
Go to wwwalgorithmic-solutionsinfofreeindexphp Accept the licence terms and download the appropriate version (usually the 64 bit version)
The LEDA installation program will install additional numerical libraries and header files from the Algorithmic Solutions company
Once the setup is complete modify the Lotto program
In the Solut ion Explorer right-click on your project (Lot to ) and left-click on Proper t ies A dialog-box appears
Under the CC++ section
1 Click on General Choose Addi t ional include di rec tor ies and enter the directory CAlgor i thmic Solut ions LEDA-63- free-win-msc10-
s td incl
2 Click on Preprocessor and add LEDA_DLL to the end of Preprocessor
Defini t ions Note the semicolon is required
3 Click on Code Generat ion and check that Runtime Library is set to Mult i - threaded Debug DLL ( MDd)
Under the Linker section
4 Click on General
5 Choose Addi t ional l ibrary di rector ies and enter the directory CAlgor i thmic Solut ionsLEDA-63- free-win-msc10-s td
6 Click on Input and add l ibGeoW_mdd_dl l l ib leda_mddl ib to the end of Addi t ional Dependencies Again the semicolon is significant
You may now close Properties dialog-box
7 Modify your code Add the following under include ltiostreamgt
include ltLEDAnumbersintegerhgt using ledainteger using namespace std
80
Then modify the recur_factorial() function so that it accepts and returns a type called simply integer rather than bigint
Save the project and exit Visual Studio
In order to build and execute Lottoexe Windows needs to have l eda_mdddl l in its search path for DLLs Therefore we need to add the path to the folder containing leda_mdddll to the PATH environment variable
8 In Windows Explorer navigate to My Computer then right-click on it and select Propert ies
9 Click on the Advanced tab and then on the Environment Var iables button
10 In the bottom section (System var iables ) of the dialog box highlight Path and then click the Edi t button
At the end of the existing path add -
11 CAlgor i thmic Solut ions LEDA-63- free-win-msc10-s td
Once more note the leading semicolon is significant
81
12 Restart Visual Studio and re-open Lot to Build and run the application as normal
It might seem that this was a lot of work for such an apparently trivial result but the fact is that you now have access to (and have seen how to use) an advanced numerical library of functionality And anyway when all is said and done you must admit that at least you got a return here ndash which is more than you should reasonably expect from the lottery
Figure 19
Task 5
Explore the LEDA samples and documentation ndash if you installed it there should be a shortcut in your start menu to LEDA-63-free-win-msc10-s td
Task 6
Modify the Lotto program to see how the odds change when there are more balls andor when more balls need to be matched (you might also display more of the intermediate results of calculations ndash like 49)
Destructors
Both constructors and destructors are special class methods We have seen how a constructor is called whenever an object is defined
A destructor has the class name prefixed by a tilde ~ Like constructors destructors cannot return values and therefore they have no return type specified but unlike constructors destructors have no arguments and thus cannot be overloaded
An objects destructor is called whenever an object goes out of scope The purpose of the destructor is to clean up eg to free any dynamically allocated memory that the object was using and release other system resources such as files and database connections etc
In the examples used so far no destructor has been provided for any class created In these programs it has been unnecessary If the programmer does not explicitly provide a
82
destructor the compiler will create an empty destructor in the same way that an empty constructor is created if one is not explicitly created
When classes are created any objects instantiated from them that contain dynamically allocated memory will need destructor methods added to implicitly free any dynamically allocated memory when the object goes out of scope
In the class example shown below the destructor function is ~StudentCourse()
~StudentCourse()
cout ltlt Im being destroyed
7 Arrays vectors lists and hash-tables Arrays vectors and lists are all types of data structures Data structures are areas of memory where collections of the same data type are held The main difference between arrays vectors and lists is that arrays stay the same size throughout the program execution whereas vectors and lists can grow automatically
Arrays consist of a series of elements (variables) all of the same type placed consecutively in memory Each of the elements can be individually referenced by adding an index to the arrays name We saw this type of notation earlier when using arrays
Eg
int examMarks[10]
This declares an array of ten scores score 1 is accessed via an index of zero ndash examMarks[0] and score 10 is access through an index of nine ndash examMarks[9] Very important note that indexes start at zero
The advantage of using arrays compared to using discrete variables (the way we have stored values so far) is it is possible to store any number of values of the same type in an array using the same identifier
With arrays it is possible to store 100 student exam marks or 100 student names with using one unique identifier
Vectors and lists are container classes which were originally part of the Standard
Template Library (STL) The STL evolved into C++ Standard Library ndash which includes iostream etc This is the general-purpose C++ library of functions algorithms and data structures that we can use in our programs While some aspects of the library are very complex it can often be applied in a very straightforward way that allows reuse of sophisticated data structures and algorithms
There are many container classes in the library ndash note that C++ now also provides such a class for the more primitive array
ltarraygt
New in C++11 and TR1 (Technical Report One)
83
A container for a fixed sized array
ltbitsetgt
A bit array
ltdequegt
A double-ended queue
ltforward_listgt
New in C++11 and TR1 A singly linked list
ltlistgt
A doubly linked list
ltmapgt
Sorted associative array and multi-map
ltqueuegt
A single-ended queue
ltsetgt
Sorted associative containers or sets
ltstackgt
A stack
ltunordered_mapgt
New in C++11 and TR1 Hash tables
ltunordered_setgt
An unordered_set unordered_multiset
ltvectorgt
A dynamic array
As with an array vector and l is t can hold objects of various types However unlike arrays vectors and lists can resize shrink and grow as elements are added or removed
The standard library provides access via iterators or subscripting Iterators are classes that are abstractions of pointers (more on pointers later) They provide access to container classes using pointer-like syntax and have other useful methods as well
The use of vectors lists and iterators is preferred to arrays and pointers By using containers common problems involving accessing past the bounds of an array are avoided Additionally the C++ standard library includes generic algorithms (an algorithm is a set of instructions on how to perform a task) that can be applied to vectors lists and other container classes
Declaring and using arrays
Arrays are declared indicating the type and number of elements in the following way
type ar rayName[arraySize]
84
Examples are
int inNumbers[20] an array called i nNumbers of 20 in tegers
char inName [20] an array called i nName of 20 characters
float ExamMarks[5] = 0 an array called ExamMarks of 5 floats with all elements explicitly initialised to zero
const int size = 5 declaring a constant variable size
float ExamMarks[size] When the constant variable size is applied to the array declaration the number of elements is set to 5 This cannot be changed during runtime of the program However it is handy when the number of array elements needs to be changed Changing the constant value size changes the number of elements wherever the ExamMarks array is used in the program
int numArray [2][3] is a multidimensional array with 2 rows and 3 columns
Note Arrays have been used in C++ for many years and there will be code you work with that was written before vectors became available Vectors are are usually preferred to using arrays and pointers Common problems involving accessing past the bounds of an array are avoided when using vectors
Creating an array to hold exam results
Task 1
Open the project Array s ln
Compile and run the program
Run the program adding five exam results The output should be similar to Figure 20
Figure 20
85
Examine the following statements
double ExamMarks[5] = 0 This statement declares the array setting its size to 5 elements and explicitly initialising all elements to zero
cout ltlt Enter Exam Mark ltlt i + 1 ltlt This statement prompts the user to enter an Exam mark into the array at element i + 1
Using the notation i + 1 indicates to the user to enter Exam Mark 1 not exam mark 0 which would be less intuitive
Array elements are numbered from 0 to n - 1 So an array that holds 20 integers will be addressed from element 0 to 19
ExamMarks[0] -ExamMarks[19]
The first number will be entered into element [0 ] The last into element [19]
cin gtgt ExamMarks[i]
This statement reads in the user input and stores the values in the array elements of ExamMarks[i] i is incremented within the for loop and starts at 0
Task 2
As it stands the program could be generally improved ndash see the notes in the code and consider how you might make such improvements
Next modify the program to output the highest and lowest marks entered
Task 3
Modify the program so that the number of marks may be easily changed (at compile time)
86
Task 4
Modify the program so as to break out the part that calculates the average and put it into a separate function
Write another function that given an array of this sort returns the mode mean and median values ndash you will need to pass in references as the function will need to return three values
Lastly put your two new functions into a separate cpp (you will also have to create a h file for Arraycpp to use ndash this will contain the new functions prototypes)
87
Searching Arrays with Linear Search
Linear search allows the user to search the array and establish whether the array contains a value that matches a search criteria defined by the user
The search compares each element of the array with the user input The array is not sorted and this method of searching works well for small arrays For large arrays linear searching is inefficient and it is necessary to use other forms of array searching after the array has been sorted
Linear Search
Task 1
Open the project LinearSearch
Compile and run the program - choose a number between 1 and 100 The output should be similar to Figure 21
Figure 21
88
Examine the following statements
myArray[i] = (1 + rand() 100) This statement uses the rand function part of the ltstdlibhgt header file (included via iostream being included) 1 + rand() 100 produces integers in the range 0 to 99
The function l inearSearch takes three arguments The array name the size of the array the third argument is the search value
if(theArray[j] == value)
return j
This selection statement compares each element to the search value If the search value is in the array the element number is returned to main() otherwise -1 is returned
The if selection statement if(containingElement = -1) in main() is used select the output indicating a successful or unsuccessful search
Task 2
Currently the program searches for the first occurrence the search value only
Modify the program so that it outputs al l matching element locations
This function can be used for turning an int value into a string See also the comment below about C++11s to_string() functions
string convertInt(int number)
stringstream ss
ss ltlt number
return ssstr()
Youll need to include ltsstreamgt to use the stringstream class
89
Task 3
Modify the program so that repeated searches may be carried out
See Figure 22
If using C++11 or later you can also use the to_string() helper functions of the string class eg to_string(10) yields 10
Figure 22
PLUSPLUS Debugging Linear Search
Task 1
For debugging purposes modify the program so as to output the contents of the array
Open and run (exercise solution) LinearSearch to see what this might look like You might want to use the modulus operator () to work out when to neatly break a line
You may or may not like to have the program generate varying sets of random numbers To facilitate this youll need to seed the random number generator by inserting a line of code like this
srand((unsigned)time(NULL))
Note the use of the cast
To use srand() include timeh at the top of your program
90
Sorting Arrays with Insertion Sort
When working with large quantities of data in an array you will need to sort the data at some point This makes searching for information quicker and there are many algorithms available that can be used In the following exercise you will learn how to sort numbers stored in an array in ascending order
SortingSearching an array
Task 1
Open the project Sorts
Run the program and examine the code
The program currently uses a class (sorts) which is defined in sortsh to implement one popular sorting algorithm called Inser t ion Sor t
For details on this algorithm see
httpenwikipediaorgwikiInsertion_sort
91
Task 2
Add a new sort to the sorts class
The text file quicksor t txt (in the Sorts folder) contains the C++ code required to implement another popular sorting algorithm called Quicksor t17
For details on this algorithm see
httpenwikipediaorgwikiQuicksort
Add the quicksort code found in quicksor t tx t to the sorts class - considering what parts of it need to be publicprivate
quicksort tx t is in the same folder as the Sortss ln project file
Step 2
Test the quicksort implementation on a range of values
Alter the quicksort implementation so as to have it sort in descending order
Following on from Step 3 parameterise the quickSort() function so as to add an option to have the array sorted in either ascending or descending order
17 Invented by C A R Hoare ndash Sir Tony Hoare with Christopher Strachey the most distinguished computer scientists Oxfords ever produced
92
Figure 23
93
PLUSPLUS Binary Search (Binary Chop)
Task 1
Now that the array is sorted we can implement a very efficient searching algorithm usually called either binary search or binary chop search
See Figure 24
Modify your project to allow the sorted array to be searched for a value using the binary chop algorithm See opposite
The algorithm for binary chop is quite straight forward
1 Look at the value of the middle element of the array If the value = target then youre done
2 If the value is lt than target discard the lower half of the array treating the upper half as though it were the complete array
If the value found is gt than target you obviously want to look in the lower half
3 Repeat step 1 until the item is found or else the index value becomes invalid
Pseudo code for this algorithm is here
first integer = 0
mid integer = 0
last integer = NumberOfItems
while first ltgt last
begin
mid = first + last 2
if List[mid] = target
exit while Found item
If List[mid]gt target
last = mid In the first half
else
first = mid + 1 In the last half
end
found boolean = List[mid] = target
94
Figure 24
Multidimensional Arrays
Multidimensional arrays with two dimensions (arrays can have more than two dimensions) may be thought of as consisting of data arranged in rows and columns see Table 3
Each element in the array is identified by using two subscripts as shown in Table 3 The first subscript identifies the element row and the second identifies the element column a[0] [1] identifies a value in Row 0 Column 1
The array in Table 3 contains two rows and three columns and can be called a 2 by 3 array
Column 0 Column 1 Column 2
Row 0 a[0] [0] a[0] [1] a[0] [2]
Row 1 a[1] [0] a[1] [1] a[1] [2]
Table 3 ndash Array Layout
A multidimensional (2 by 3) array of doubles is shown in Table 4
Column 0 Column 1 Column 2
Row 0 2367 6792 8557
Row 1 1276 9132 2789
Table 4 ndash Array Values
95
Creating a multidimensional array
Task 1
Open the Mult iDimArray
project
Compile and run the program adding 2 exam results for each of the two students The output should be similar to Figure 25
Figure 25
96
Task 2
Examine the code used to write values to and read from a multidimensional array
Examine the following code segments
double ExamMarks[2][2] = 0 This statement creates a two-dimensional array having two rows and two columns and initialises the elements to 0
Every element in the array is identified by an element name in the form a[x] [y] where a is the name of the array and x and y are the subscripts that uniquely identify each element in a Notice that the names of the elements in row 0 all have a first subscript of 0 see Table 5 The names of the elements in column 1 all have a second subscript of 1
Note multidimensional arrays can have two or more dimensions (subscripts) Three-dimensional arrays are uncommon
Column 0 Column 1
Row 0
a[0] [0] a[0] [1]
Row 1
a[1] [0] a[1] [1]
Table 5 ndash Array Indexing
97
Examine the following code segment used to read values in to the array
for(int row = 0 row lt 2 ++row)
for(int col = 0 col lt 2 ++col)
cout ltlt Enter Exam Mark No
ltlt col + 1
ltlt for student No
ltlt row + 1 ltlt
cin gtgt ExamMarks[row][col]
cout ltlt endl
The two for loops work taking one row at a time (the outer for loop) and looping through the columns in that row (the inner for loop) When the marks have been entered for all the columns in row 0 row 1 is selected and values entered for each column cell in row 1
Table 6 shows how four results would be allocated in a 2 x 2 multidimensional array
Exam mark 1 Exam mark 2
Student 1 67 71
Student 2 61 58
Table 6 ndash Populated Array
98
Examine the following code segment used to calculate the total of each students marks
if(row == 0)
r1total += ExamMarks[row][col]
else
r2total += ExamMarks[row][col]
r1total is a variable to hold the sum of values in column 0 and 1 for row 0 (Stud1) r2total sums the values in the columns for row 1 (Stud 2)
Selection for each row is made with if(row == 0) this is Stud1 If row is not 0 then row must be 1 and the mark can be added to r2total If three exam marks were input per student the code for selecting the marks would need to change
Task 3
Modify the program to read in four exam marks for f ive students
Establish the highest and average mark for each student Output the results
One way to do this is to keep a separate array to record the students statistics An alternative would be to extend the existing arrays row so that it may hold the necessary student data
99
Declaring and using vectors
Vectors are declared indicating the type and number of elements in the following way
vectorlttypegtvectorName
vectorlttypegtvectorName(initialSize)
vectorlttypegtvectorName(initialSize elementValues)
Examples
A vector called i nNumbers with no initial size to hold doubles
vectorltdoublegt inNumbers
A vector called Name with an initial size 20 to hold characters
vectorltchargt Name(20)
A vector called ExamMarks holding integers with initial size of 4 elements each with the value 6
vectorltintgt ExamMarks(46)
Note In previous exercises you have created your own member functions In the following exercises you will use some of the vector class member functions Some of these are begin() end() erase() and size() See section 12115 for more detail
The standard library also includes a large collection of algor i thms that manipulate the data stored in containers (vectors are one of several types of container)
You can sort the order of elements in a vector (vec) for example by using the sort algorithm
sort(vecbegin() vecend()) C++11 sort(begin(vec) end(vec))
You can find a value (69) in a vector by using the find algorithm
ptr = find(vecbegin() vecend() 69) See C++ note above
100
ptr is an iterator to store the memory location of the element found
You can reverse the order of elements in a vector for example by using the reverse algorithm
reverse(vecbegin() vecend()) See C++ note above
There are two important points to notice about the call to reverse First it is a global
function (as are find and sort) not a member function Second it takes two arguments rather than one and operates on a range of elements rather than on the container (vector container in this case)
With the above examples the range is the entire container from begin() to end() (vecbegin() to vecend()) reverse like the other standard algorithms is decoupled from the libraries container classes The reverse algorithm can be used to reverse elements in vectors in lists (another container) and even elements in C arrays
int myArray[] = 1 6 20 4
reverse(myArray myArray + 4)
for(int i = 0 i lt 4 ++i) Lets see the reversed array
cout ltlt Array[ ltlt i ltlt ] = ltlt myArray[i]
In the above example the first argument to reverse is a pointer (pointers are covered in Section 8 but for now we can say the first argument points to the address in memory that is the start of the vector ) to the beginning of the range and the second argument points one element past the end of the range This range is denoted (myArray myArray + 4)
Arguments to reverse are i terators which are a generalization of pointers which is why it is possible to reverse the elements of a C array using the array address and pointer notation
Creating a vector to hold exam results
Task 1
Open the Vector project
Compile and run the program adding five exam results The output should be similar to Figure 26
101
Figure 26
Examine the following statements
include ltvectorgt This statement includes the header file vector enabling the program to use the class template vector (templates allow the use of generic functions that admit any data type as parameters and return a value more on this later)
vectorltdoublegt ExamMarks(5) This statement declares the vector to hold doubles and sets the initial size to 5 elements
Note Although vectors can grow to any size it is good practice and more efficient to specify the size when this is known When no size is given and the contiguous memory spaces have been exhausted the elements must be copied to a larger memory space to increase the size of the vector
cin gtgt ExamMarks[i] This statement reads in the user input and stores the values in the vector slot i of ExamMarks[i] i is incremented within the for loop Note that we the same indexingsubscripting syntax as we used previously with arrays ie[ ]
102
Task 2
Modify the code so as to accommodate the adding of an extra exam mark
Note this should not be done (simply) as part of the loop but as a separate action later and you should use the vectors push_back() method to facilitate this
push_back() is a member function of the vector class that adds an additional vector element at the end
After adding the extra mark you will need to generate a new set of statistics ie the average will have changed now To do this separate out the statistical code and place it in a separate function so that you may re-use later (after the new data has been entered)
size() is a member function (method) of the vector class It can be used to establish the size of a vector
The statement for(int i = 0 i lt ExamMarkssize() i++) uses the vector member function size() available to the vector ExamMarks to obtain the size (number of elements) in the vector The size of the vector is used to identify a terminating value that ends iteration of the for loop
Task 3
Open VectorSor t
You will see three TODO sections in the code which need completing
1 Populate a vector with 100 randomly generated numbers
2 Sort the vector
3 Reverse the vector
For sortingreversing you will can use the algorithms sort() and reverse()
Heres a useful link hellip
httpwwwcpluspluscomreferencealgorithm
103
Using insert() and iterators
Task 1
Open and modify the skeleton project called Inser t
Important areas of the program are explained in the steps opposite
Examine the code
vectorltintgtiterator it
This statement creates an iterator that is used to access members of the vector
Iterators are used to access members of the container classes (the container type vector in this case) and can be used in a similar manner to pointers
In the example iterator it is used with the insert() function to place the value (200) at the beginning of the vector nums
it = numsbegin()
This statement uses the vector member function begin() to initialise the iterator it with the address of the start of the vector
it = numsinsert(it 200)
This statement uses the member function insert() and iterator it to insert 200 at the beginning of the vector (it)
Note that an iterator is returned by the function insert() that points to the newly inserted element
104
numsinsert(it + 1 numsTwobegin()
numsTwoend())
This version of the insert() function takes 3 arguments and is used for copying in part or full another collection This may be a vector a plain C++ array or some other collection that is accessed using pointersiterators
This statement inserts a second vector (numsTwo) into nums The three parameters are (copy to nums+1 from star t of numsTwo to end of numsTwo)
it = numsinsert(it + 2 696 )
This version of the insert() function takes 2 arguments The iterator it + 2 points to element number three it points to the beginning of the vector and the 2 moves two elements in The value 696 is inserted at that element
void display(vectorltintgt amp vec)
cout ltlt Vector contains
for(
unsigned int i = 0
i lt vecsize()
++i
)
cout ltlt vecat(i) ltlt
Function display() is passed a reference to a vector and outputs the vector contents used throughout program
105
Task 2
Add the code shown in Figure 27 to the program and using the insert() member function add the array to the nums vector at position two (in the vector) Output the contents of the nums vector to screen
int myArray[] = 5 6 3 4
Figure 27
stdarray
C++11 Introduced a new template array type called stdarray
stdvector is a template class that encapsulates a dynamic array that is stored on the heap and that grows and shrinks automatically if elements are added or removed It provides all the hooks (begin() end() i terators etc) that make it work fine with the rest of the STL It also has several useful methods that let you perform operations that on a normal array would be cumbersome like inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes) Since it stores the elements in memory allocated on the heap it has some overhead in respect to static arrays
stdarray is a template class that encapsulates a static array that is stored inside the object itself which means that if you instantiate the class on the stack the static array will be on the stack Its size has to be known at compile time (it is passed as a template parameter) and it cannot grow or shrink
It is more limited than stdvector but it is often more efficient especially for small sizes because in practice it is mostly a lightweight wrapper around a C-style array However it is more secure since the implicit conversion to a pointer is disabled and it provides much of the STL-related functionality of stdvector and of the other containers so you can use it easily with STL algor i thms
Here is a small example demonstrating the template and some other C++11 extras such as auto and a ranged-based for loop
106
include ltstringgt include ltiteratorgt include ltiostreamgt include ltarraygt using namespace std template ltsize_t N class Tgt arrayltT Ngt make_array(const T amp v) arrayltT Ngt ret retfill(v) return ret int main() The char here can be inferred and so is optional auto a = make_arraylt10 chargt(1) for (const auto amp s a) stdcout ltlt s ltlt system(pause) return 0
1 1 1 1 1 1 1 1 1 1 Press any key to continue
Declaring and using lists
Lists are a kind of sequence container similar to vectors The elements of a list are ordered following a linear sequence with storage handled automatically by the class
List containers are implemented as doubly-linked lists and it is worth noting that elements may be in different and unrelated storage locations
Ordering of a list is kept by a relationship to each element of a link to the element preceding it and a link to the element following it
Because linking information is associated with each element (possibly to different and unrelated storage locations) extra memory may be used to keep the linking This may be important when using a large list
l is ts tend to perform better than vectors at inserting extracting and moving elements in any position within the container but lack direct access to the elements by their position and because of this have a slower access time than vectors Access to an element has to be via a known position (the beginning or the end) and there is a time cost in linking between the known position and the element to be accessed
107
lists are declared indicating the type and number of elements in the following way
listlttypegt listName
listlttypegt listName(initialSize)
listlttypegt listName(initialSize elementValues)
Examples
A list called inNumbers with no initial size to hold doubles
listltdoublegt inNumbers
A list called Name with an initial size 20 to hold characters
listltchargt Name(20)
A list called ExamMarks holding integers with initial size of 4 elements each with the value 6
listltintgt ExamMarks(46)
72 Hash Tables and Cached Calculations
This section has ultimately really been about introducing you to templates and algorithms and well mix both now in a final example
From the binary chop exercise earlier we have seen that sorted arrays provide a very efficient means of storing data for later look-up However we have to bear in mind the algorithmic cost of sorting the array in the first place ie if we have a million unsorted items in our list and we want to find a single item (only) is it better to sort the entire list first and then find the item or is it better to simply walk through the array from the beginning ndash after all we could safely assume that weve a 5050 chance of finding it in the first half of the array Of course as were sorting we could keep an eye open for our item ie we could combine a (partial) sort with look-up operation ndash over time if we repeat this procedure looking for other items we will ultimately sort our array as a side -effect of the look-up operations
But lets move on a little and just consider the fastest look-up method we know so far that carried out on a sorted array using binary chop and think about our programs overall performance when we need to insert additional items into the array When considering problems like this we always think of the worst case hellip despite their often being fans of
108
Monty Python Computer Scientists rarely look on the bright side of life The worst case here is that we need to insert an item into array position zero
Eg say we have this sorted array (look-up operations average O log2 N = fast)
15 24 25 31 78 250 255 262 277
We now have to insert the value 5 into this array Using normal array indexing methods how many operations will this take
5 15 24 25 31 78 250 255 262 277
Each item needs to be shuffled up one position to the right and if weve millions of items that is rather costly especially if the next thing were likely to do is to insert another item
So weve seen that accessing sorted data is very useful and weve also seen that sorting and especially inserting items can be costly The big question is then is there a way we can make both just as efficient - finding andor inserting an item in Olog2N or O(1) (constant time)
Hash Tables
A hash-table is a data structure designed to allow for both rapid insertion and look-up
Although any specific hash-table is implementation specific (there are very many different types of hash-table) well quickly go through the basics
The storage medium well use for our hash-table is an array of strings and we will say that this array has just 10 elements It looks like this
string myhash[10]
Well use this hash-table to store words and well determine the array index for any specific word using a hash- funct ion ndash something that will take a word as its input and return an array index as its output
109
unsigned hashfunc(string s)
unsigned result = 0
for(unsigned i = 0 i lt slength() ++i)
result = result + s[i]
return result 10
hashfunc() iterates through s keeping a running total of the sum of the ASCII codes for each of the characters eg hashfunc(hash-table) computes
h + a + s + h + - + t + a + b + l + e
where the characters ASCII values are
104 + 97 + 115 + 104 + 45 + 116 + 97 + 98 + 108 + 101
The total = 985 and 985 modulus 10 = 5
The final computed value will be used as an index into the array The modulus value used is the size of the hash-table and we use it so as to ensure that resultant computed index value cannot be greater than 9 (remember our arrays indexes are 0 ndash 9)
We can now store words in the myhash array like this
string myhash[10]
string s = hash-table
index = hashfunc(s)
if(myhash[index] = )
myhash[index] = s
else
The complex part is what to do if we have what is called a collision ndash when we find that myhash[index] is already occupied Youll probably have already thought of what value hashfunc(elbat-hsah) will have
One way to help avoid collisions to use a better hash-function and a larger array However in real life collisions are practically impossible to avoid and the only other option to deal with them is to allow more than one string to inhabit an array slot in some way ndash perhaps by having each of the original array slots contain an array ndash rather than an individual string Of course in this case we would also need some way to determine which of the n colliding entries is the one were interested in ndash is it elbat-hsah or hash-table
110
Well briefly leave our examination of hash-tables at this point and instead look at Fibonacci numbers Do not worry we will return to hash-tables very soon
Fibonacci numbers are the numbers in the following integer sequence
0 1 1 2 3 5 8 13 21 34 55 89
By definition the first two numbers in the Fibonacci sequence are 0 and 1 and each subsequent number is the sum of the previous two More formally that is
119865119899 ∶= 119865(119899) ∶=
0 119894119891 119899 = 0 1 119894119891 119899 = 1
119865(119899 minus 1) + 119865 (119899 minus 2) 119894119891 119899 gt 1
Computing Fibonacci Numbers
Task 1
Open Cached_fibonacci
Compile and run the program as is
Examine main() and the calcfib() functions
bigint calcfib(bigint n)
if(n == 1 || n == 0)
return n
else
return calcfib(n - 1) + calcfib(n - 2)
bigint is defined as a unsigned long long int and we have used typedef to save some typing
NOTE The method used to calculate Fibonacci numbers here has been selected because it is perhaps the most obvious way to turn the formal definition into code If you are interested please see the separate Fibonacci project for two other examples of how to calculate Fibonacci numbers
111
Modify the beginning of the calcfib() code
bigint calcfib(bigint n) cout ltlt calcfib was passed ltlt n ltlt endl
Modify main() to set max = 5 and re-run the program
calcfib was passed 0 Fibonacci number 0 is 0 calcfib was passed 1 Fibonacci number 1 is 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 2 is 1 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 Fibonacci number 3 is 2 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 Fibonacci number 4 is 3 calcfib was passed 5 calcfib was passed 4 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 3 calcfib was passed 2 calcfib was passed 1 calcfib was passed 0 calcfib was passed 1
Fibonacci number 5 is 5
112
Note that to calculate Fibonacci number 5 we calculate Fibonacci number 4 and Fibonacci number 3 - even though weve previously calculated Fibonacci number 3 in order to calculate Fibonacci number 4
To fully appreciate the growth of this process re-run the program adding 10 to max for each subsequent run You maymay not like to comment out the line you inserted in Step 2
Task 2
Getting back to Hash Tables Using a hash-table to store previously computed Fibonacci numbers
As it stands the incomplete solution declares a template hash-table called fibs of the type unordered_map
Read the comments in the function fibCache() and modify the code to as to use the fibs hash-table to store previously computed Fibonacci numbers
fibs[n] = f stores f the n-th Fibonacci number in the n-th slot of fibs (which as you can see you may treat as an array for indexing into)
8 Pointers In C++ programming data (variables) can be referenced via the memory address of the variable This is done using a pointer var iable
A pointer var iable contains the address (location in memory) of a data variable
There are also functional pointers ie those that point to code rather than data and these are briefly explored later
Pointers can be particularly useful when interacting with the operating system andor when working with arrays - as the elements in an array will always occupy consecutive memory places Incrementing the pointer variable by one addresses the next array element
Lastly pointers are also used to fake pass by reference
Declarat ions
int n This is a standard variable declaration n that contains a value as yet unknown of type int
int p This is a pointer p that can hold (point to) an address that contains a variable of type int The type of p is int
Each variable declared as a pointer must be preceded by an asterisk () This modifies the type of the object being declared from thing of type to pointer to thing of type Eg int n means n is an int whereas int n says that n is a pointer to an int
113
int age height age is a pointer to an int height is an int value
double far cent are both pointers to doubles
Pointers can be initialised when they are declared or set using an assignment It is common to initialise pointers to a memory address but they can also be initialised to the predefined constant NULL ndash meaning that they do not (as yet) hold (point to) a valid memory location NULL is defined in the standard library such a pointer is called a nul l pointer
When is used in a variable declaration it indicates the variable being declared is a pointer and not a value
But do beware as is used elsewhere with pointers when the appears before a previously declared pointer variable elsewhere in the program it is said to dereference the pointer and so is used to access data stored at the address which is stored in the pointer A dereferenced pointer is essentially the variable to which the pointer was originally set to point
To complicate matters further using the pointer name without the dereference operator references whatever is stored in the pointer variable itself ndash this is the address of the object it references in memory (which maybe NULL of course)
As we have seen using can mean two things that something is being declared as a pointer or that a previously declared pointer is being dereferenced Experienced programmers sometimes enter the two usages differently ndash a notation we would highly recommend ie
int n n is an object that can hold the address of an int
int k = 0 k is an int holding the value zero
n = ampk n is set to hold ks address amp is explained below
n = 1 k (yes k) is set to hold the value 1
Note the space used in the different usages - int n vs no space in n
Initialising pointers
Pointers can be initialised in two ways
int x = 16 y = 69 variable declaration and initialisation int x_ptr = ampx pointer declaration and initialisation x_ptr holds the address of x int y_ptr pointer declaration yptr is a pointer
y_ptr = ampy pointer assignment yptr holds the address of y
Once declared a pointer variable can be assigned the address of another variable using the amp the addressof operator
114
Note the variable name should not be prefixed by the in the assignment statement unless the pointer is initialised immediately in the variable declaration
We also use pointers when creating objects on the Heap for example we can create and initialise a string object like this string pstring = new string(Hi there) Such objects are not normally tidied away as are the objects created on the stack - objects simply declared in a functionmethod and so they should explicitly be tidied away using delete eg delete pstring For more on this subject see section 9
Using pointers
Task 1
Open the project Pointers
Compile and run the program The output should be as shown in Figure 28
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int x_ptr = ampx This is x_ptr pointer declaration and initialisation
int y_ptr Declaring another pointer y_ptr
y_ptr = ampy Initialising y_ptr
y_ptr = x_ptr Assigning x_ptr contents to y_ptr Both pointers are pointing to variable x (16)
y_ptr = ampy Assigning the address of y back to pointer y_ptr
y_ptr = 170 Assign 170 to the variable at memory location of y_ptr y_ptr points to variable y so 170 has been assigned to y
115
Figure 28
Pointer Arithmetic and Arrays
We have seen that once a pointer is initialised it has a memory address and this address can be reassigned another address It is also possible to change an address using standard arithmetic
The ++ and -- increment and decrement operators can be used to move the pointer along to the next or back to the previous memory address To jump more than one memory address you would have to use the assignment operators += and -=
When using arrays and pointers the array name is the address of the first element in the array
int intArray[] = 1 2 3 4 5
int int_ptr = intArray Same as int int_ptr = ampintArray[0]
The pointer has been declared and initialised with the statement int int_ptr =
intArray Note there is no need to use the address of operator amp when initialising arrays as the array name is the address of the beginning of the array
When working with arrays each element of the array will be the type and size at declaration When an array is declared to hold integers each element will usually be 4 bytes in size An array of doubles will have element sizes of 8 bytes Note ndash these sizes are actually down to the compiler being used and are usually in turn dependent upon the operating system being used
It is not important to know how many bytes make up each element Moving the pointer through the array with the assignment operator x_ptr += 2 will move two elements further through the memory allocated for the array or 16 bytes for an array of doubles
116
Pointers and Arrays
Task 1
Open the project PointerAr i thmetic
Compile and run the program The output should be the same as Figure 29
Examine the program carefully
You may not fully follow the program at first glance as it employees a few potentially new constructs (it depends how far weve got through the lectures)
One slightly truncated new construct is
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
A struct in C++ is just like a class except that the default public and private sections are reversed By default everything in a struct is public
typedef in C++ allows the definition of our own types based on other existing data types
typedef exist ing_type new_type_name
where exist ing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining For example
117
typedef unsigned int WORD
typedef char pChar
You may also remember initialiser lists from earlier eg
s_thing(int a) a(a) b(sqrt((double)a))
If we re-write this
typedef struct s_thing
const int a
const double b
s_thing(int a) a(a) b(sqrt((double)a))
thing
We quickly see that a(a) and b() are initialising the a and b struct members const int a and const double b
118
Remember that as these are const we cannot use assignment
typedef struct s_thing
const int a
const double b
s_thing(int a)
Error ndash a and b are const
this -gt a = a
this -gt b = sqrt(a)
thing
Lastly when dealing with pointers to compound types one may access the members of the type via dereferencing or via the so called crows foot operator
(t) dereferences t giving us a thing which was pointed to by t Then we use the dot operator to access the member (t)a
We have to parenthesiset otherwise the would bind to t first ie it would be as though we had done this (ta) which would be an error
The crows foot saves us the dereference t-gta is just like (t)a
119
Figure 29
PLUSPLUS Pointers and Arrays
Task 1
Open and modify the skeleton project called ReverseArray
In main() create an array of 10 integers Fill the array with random numbers between 0 ndash 100
Write a helper function called to output the contents of the array to the console A suitable prototype for this would be void dumpArray(int array[] int size)
Write a helper function to reverse the contents of the array Use a temporary variable as an aid A suitable prototype for this function would be void reverseArray(int array[] int size)
Reverse the values in the array using only pointers
120
Reverse the array without using a temporary variable You should use the XOR operator ^ to achieve this
Pseudo code for an XOR swap is
X = X XOR Y
Y = X XOR Y
X = X XOR Y
The completed program should look like Figure 30
Figure 30
Task 2
Reverse the array using a vector and the standard function template stdreverse()
We can also have pointers to functions in C++ (and C)
The name of a function resolves to be its address in memory (somewhat similar to the case where we use the name of an array) When we call a function we use this name to retrieve the functions address and then use the function invocation operator to execute it The function invocation operator is the set of brackets you use eg
Lets take an example
121
include ltiostreamgt
using namespace std
int lue() life the universe and everything
return 42
int main()
cout ltlt The address of the function lue is
ltlt lue
ltlt invoking it yields
ltlt lue()
ltlt endl
system(pause)
return 0
Typical output is shown in Figure 31
Figure 31
122
We can also store addresses of functions in variables (theyre just numbers) and the type system allows for us to describe and declare scalar variable types for function pointers eg this modified code fragment would produce the same output as that show above
fp is a pointer to a function taking
no arguments and returning an int
int (fp)()
fp = lue
cout ltlt The address of the function lue is
ltlt fp
ltlt invoking it yields
ltlt fp()
ltlt endl
fp is a funct ion pointer var iable so it may be used to point to any other function having the correct signature at runtime
PLUSPLUS Function pointers
Task 1
Open the project Calculator
Compile and run the program The output should be as shown in Figure 32
123
Examine the following statements Only the important parts of the program are explained the rest has been covered in previous exercises
int (fp)(int int) This is the function pointer declaration It may point to functions that take two integers and return an integer
Like all automatic storage class variables fp will currently be pointing at a random location What happens if you run the program without setting fp to point to an actual function Comment out the switch to find out
switch (Operator)
case 0 fp = Add break
case 1 fp = Subtract break
case 2 fp = Multiply break
The code could do with improving
Modify it to allow for multiple trials eg add the necessary logic to loop and perform multiple calculations ndash youll need to add some way to end the program too therefore
Modify it so that the operator may be inputted as an operator character eg + - etc Allow X x and for multiplication and add for division
All three pieces of information could be entered on a single line eg 6 x 7ltentergt Using cin to read that data just requires you to use three cin statements
cin gtgt X
cin gtgt Operator
cin gtgt Y
Lastly modify the program to that it uses floating point arithmetic
124
Figure 32
9 APIs New Delete and Dynamic Memory As has been stated earlier pointers are useful in a variety of situations However because they are easy to get wrong ndash and when they go wrong everything goes very wrong indeed ndash languages like C++ have tried to make their use the exception rather than the norm For example without reference arguments (eg void someFunc(int amp)) we would have to use pointers to achieve the same functionality and performance
On the whole the underlying philosophy when it comes to pointers is to try to avoid using them whenever possible You can get a real feel for this subject by Googling for smart pointers c++ and from Wikipedia httpenwikipediaorgwikiSmart_pointer
Two areas where we absolutely need pointers are when calling into an external API (Appl icat ion Programming Interface ) and when allocating memory for our own purposes ndash the latter case is also eased by advances in the library support in C++
Using an API
An Appl icat ion Programming Inter face is functionality provided by some third party The most obvious API whether it is Windows Linux or OSX is that exposed by an operating system
If your application needs to interact with the user in any non-portable way you will need to call into your OSs API For example if you want to display a dialog box you will need to access the OSs functionality to do so (perhaps indirectly through a framework like Nokias Qt - httpsenwikipediaorgwikiQt_(framework)) In summary if you ever want to go outside of the standard libraries andor writing consoleterminal applications you will need to call into your operating systems API
When it comes to calling into operating systems pointers are used extensively As an example 1 Google for Linux API 2 Find any website that lists the API functions and then 3 click-through to any function The odds are that the function prototype you see will contain asterisks (pointers)
125
Dynamic Memory Management
The second area where you simply must know something about pointers is when it comes to using the heap
The heap is an area of memory available to your programs You may allocate and use the heap as you wish
Why would you want to do this Normally its to create variable length arrays or to model and use an advanced data structure of some sort a self-balancing red black tree perhaps (httpenwikipediaorgwikiRedAndblack_tree) Of course the more esoteric the data structure and less likely it is that it will be incorporated into the C++ standard library (although the library does contain most of the generally useful and popular ones like doubly l inked l is ts )
To allocate memory from the heap in C++ you use the new keyword and to return it you use the delete eg
int nSize = 12
note nSize does not need to be constant
int pArray = new int[nSize]
pArray[4] = 7
delete [] pArray
10 More on Functions Functions are used to encapsulate a set of operations and return information to the main program or calling routine Encapsulation is data information or detail hiding
Once a function is written the detail of how it works is not important to the end user The user needs to understand what data to input and what output will be produced
One of the most important aspects of writing programs using functions is that the functions can be reused from one project to the next Think about the standard functions youve seen already eg the square root function sqrt() Libraries contain atomic generally useful functionality that is likely to be of use at some future time It is useful to bear this thought in mind whenever we build new programs ie we should be on the lookout for generally useful functionality (given our domain) that we should consider coding as functions for later reuse The same goes for classes of course
Probably the most important function in your program in main() ndash without it you do not have a program at all
main() is your programs entry point and as such it may be used in such a way as to inform the rest of your program as to the actions required
126
main() and command-line arguments
Task 1
Open a Command Prompt or PowerShell Prompt and enter the following
dirltreturngt
di r Odltreturngt
t ree ltreturngt
t ree altreturngt
dir and t ree etc are like mini-programs They have default functionality which may be altered by providing additional command-line arguments eg for the dir command dir L N 4 TC
Command-line arguments are passed to your programs by optional parameters eg
int main(int argc char argv[])
Where argc is a count of the number of arguments and argv is an array of pointers to arrays of character (C strings) for each argument being passed Note that argc is always at least 1 and so argv always contains at least one entry ndash this is the name of the program being run
Task 2
Open (demonstrat ion)
CommandLineArgs and Build and run the program
Examine the code
The programs configuration is Debug
In the projects Project | Debugging | Command
Arguments you will see where the programs default command-line arguments are set for debugging purposes
Using the command prompt you opened earlier navigate to your where CommandLineArgsexe is located
CommandLineArgs debug
Run the program by entering its name followed by a variety of arguments eg
gtCommandLineAgs one two threelte ntergt
127
Task 3
Open the project UserPrompter project
Run the program and then examine its code
We will modify this program to use a command-line argument However before doing that its worth pointing out that the primary purpose of this program is to demonstrate the separation of a class declarat ion with its implementat ion (the mechanismfunctionality of class prompter is defined in promptercpp but its capabilities are declared in prompter h )
Its also interesting to note that the optimal strategy is to use an algorithm called binary search or binary chop (we saw this earlier in the course) with each guess you reduce the number of possible solutions by a half This sort of algorithms Big Oh is Log n (where log is base-two logs)
httpenwikipediaorgwikiBig_O_notation
Task 4
Modify the program so that the upper range for the max value is given as a command-line argument
The UserPrompter cpp is the file youll need to modify
Test your program via the setting the projects Command Arguments as detailed above -or- by running the application standalone in a command prompt after building (also as detailed above)
See Figure 33
To convert a string into a number (weve seen one other way of doing this earlier) we can use
include ltcstdlibgt
and the function atoi() eg
atoi(argv[1])
128
Figure 33
EncryptDecrypt a file
Task 1
Open compile and run the EncodeDecode project
Complete the program so that it may be run outside of the IDE and process a file for encryptiondecryption
This is actually quite a simple task as youll only need to add a couple of lines of code However the project also demonstrates how to use the Debug and Release modes to influence the way a program runs ie that in its Debug configuration the program automatically runs through a test
Other things to note include using bitwise XOr to perform the encoding and the use of the C standard library functions putchar() and printf() to perform some of the output eg putchar() is used to output a CR to the console window (CR = char 13)
129
Figure 34
Multiple arguments overloading and default values
In C++ we can over load functions ndash meaning that we can provide different versions of the same function (the different versions must differ by the number andor type of the parameters they take) For example
130
void foo(double d) 1
cout ltlt In void foo(double d)nn
void foo(long int n) 2
cout ltlt In void foo(long int n)nn
void foo(int n) 3
cout ltlt In void foo(int n)nn
double dtest = 0
long int ltest = 0
int ntest = 0
foo(dtest) Calls 1
foo(ltest) Calls 2
foo(ntest) Calls 3
In the above the compiler works out which version of the foo() to call based upon the argument type it is given
We can also overload functions if the number of arguments differ eg
131
void bar(double d)
void bar(double d double t)
We would use a feature like this if sometimes we needed to use extra information ndash in the shape of passing in t in the above eg we would most likely implement void bar(double d) as
void bar(double d)
bar(d 25) Call bar(double d double t)
What were really saying above is that in most cases the implicit double second parameters value is normally 25 ndash perhaps its a standard discount percentage ndash and only occasionally we will need to change that value in which case wed call bar(double d double t) directly and not by going through bar(double d)
Lastly C++ has one extra feature that can make this simpler ndash defaul t arguments
Rewriting bar using this feature we get
void bar(double d double t = 25)
Note that we now only have one bar function now and that we may call it like this
bar(x)
Or like this
132
bar(x y)
In the case of bar(x) the second parameter is omitted and so will receive the default value of 25 in the second example t will receive ys value
Although outside the scope of this class for more on overloading see the (demonstrat ion) Operator Over loading project This shows how to overload the ++ pre and post increment operators overload and provide your own ltlt stream insertion operator (and one use of a friend function) and using an enum with a typedef
Passing Arrays to Functions
To pass an array to a function it is only necessary to pass the array name and the number of elements in the array
The array name is the position (address) in memory of the first element The number of elements is passed to enable the function to establish the array size
An array declared as double somearray[10] would require a function call somefunction(somearray 10)
Passing Arrays to functions
Task 1
Open and modify the skeleton project called the project called ArrayReturnValue
Pass an array to a function to read in five numbers
Pass the array to another function to calculate the average value in the array return this to main() and output to screen
Lastly at the end of the program output the values in the array from within main() The finished program should look something that that in Figure 35
Create two function prototypes
void enterMarks(double ExamMarks[] int num)
double calcAverage(double ExamMarks[] int num)
ExamMarks[] is the array to be passed As with passing variables it is not strictly necessary to give the argument a name in the prototype just its type This could have been written as calcAverage(double [] int) However it is sometimes useful to include this information as it might help explain the functions operation
It is also necessary to pass the size of the array num is the number of elements in the array its size
Within main() declare the array and initialise the elements to zero with the following statement double ExamMarks[5] = 0
This declaration explicitly initialises the first element to zero and implicitly initialises the remaining four to zero
133
Create both functions
enterMarks to read in the values and calcAverage to calculate the average (you will need a for loop in each function)
Return the average value from calcAverage to main() and output the value using cout
Call the functions from within main() with the following statements
enterMarks(ExamMarks 5)
average = calcAverage(ExamMarks 5)
You may output the average directly of course ie without first storing the value in average
At the end of main() add the statements
for(int i = 0 i lt 5 ++i)
cout ltlt Exam Mark Number
ltlt i + 1
ltlt is
ltlt ExamMarks[i]
ltlt endl
ltlt endl
134
Explain how it is possible at the end of the program to output from within main() all the values in the array entered within the function
Modify the program so that the number of exam marks (5) appears only once
In previous exercises when parameters (variables) were passed to functions the function received a value When a value is used in a function a copy is stored in a part of memory that only exists from the time the function is called to when it ends After this the memory and any value in it are lost
However the array in this exercise was initialised in main() with zeros and then passed to the function Data was then added to the array and calculations done At the end of main() the values in the array elements are output The array contains values input from within the function
The name of the array is the address of the first element of the array in the machines memory As the starting address is passed (the name of the array) the called function knows where the array is stored in memory
Because we are working with memory addresses (references ) any changes made to array elements in the function affect the memory location set up in main() for the array
C++ passes arrays to functions by reference (to the memory location of the first element) In previous exercises functions were passed values copies of the variables in main()
135
Figure 35
Passing Two-dimensional Arrays to Functions
It is common to want to store numbers in a two dimensional layout of rows and columns as shown in Table 7
187645 783473 298372
871223 629399 561201
Table 7
This arrangement is known as a two-dimensional array or matrix
C++ uses an array with two subscripts to store a two dimensional array
double Balance[2][3]
When we specify a one-dimensional array the number of elements must be given
When a two-dimensional array is specified it is necessary to specify the array elements in both dimensions We therefore specify the number of rows and columns
The Balance array in the statement above has two rows and three columns
11 Inheritance and (not presented) Polymorphism
111 Inheritance
In Object Oriented languages like C++ inheritance describes a relationship between classes of objects and which usually implies some sort of a sub-division of labour
For example lets say that we want to build an IT system that has something to do with the members of the university
136
In an OO world the first question usually is how would we categorise our significant entities and that always means naming things what names would we use to categorise university members When modelling (for that is what were going to be doing) real-world objects its sensible to use proper names So heres an attempt ndash to broadly categorise university membership
Members are members of the sets
Students
Staff
Other
What is other though
The Bodleian and the card-office issue Readers cards ndash so is a Reader a university members or are they something else And if they are something else does our system really want to concern itself them Or more broadly does our system really want to concern itself with holders of cards issued by the card-office
Are all students really the same
What sort of students do we have at Oxford (and do we want a system ndash either now or in the future ndash that might be interested in recording the differences) Lets see we have undergraduates and graduates We also have Rhodes scholars ndash but are these sorts of student that are distinct (or should be in our system) from our underpost-graduates categories And how about graduates would we want to have some sort of sub-groups Masters students MScMBAMPhil or Doctoral students DPhilDScDLitt etc Perhaps wed like to know something about how theyre being funded ndash and we might want that piece of functionality shared by our undergraduates
We can of course go through the same process when thinking about members of staff (university staff departmental staff members of congregation academic staff fulltimepart-time staff casual staff ndash and how about staff that are sometimes (or also) students) We can go on thinking about this sort of thing for a very long time and we should as its important and when its important it has a name ndash Object Oriented Design or OOD
One of the things wed hope to see appear as part of the OOD phase is the relationship between entities For example if we were to say that a common property of all university members is that they have a date-of-birth we wouldnt want to have our Student and Staff C++ objects contain this information directly by way of some datastate class member (which might seem a little odd at first) But think about it If we performed some validation on the members DoB (perhaps when its being set) we would need to include this in both Student and Staff classes Or as an alternative we would capture the validation in some external function ndash which we would call from the separate classes (if we remember) No its messy and it would be much better if we thought of things this way that all university members are people and that people all have dates of birth
To put it another way we would say that studentsstaffother are just specialisations of people ndash they are people but with a bit of extra something tagged on to them ndash like a bod card number
Now if we also had some way of capturing people stuff in say a basic Person class and could somehow use that automatically ndash perhaps by deriving a Member class from it and then doing the same from Member to both Staff and Student classes from Member One thing though ndash we wouldnt want someone to be able to instantiate a Member object
137
perhaps ie in our system Member is an abstract class Imagine a generic Car vs a Renault Clio ndash it makes no sense to create a Car object ndash there are no generic cars on the road they are all specific cars Similarly we wouldnt want a generic Member wandering around our system (if you remain unconvinced well see why later)
Modelling a student - a first attempt
Please note that in this Introduction to C++ we do not expect you to complete an exercise that requires coding from now on Please just look through the code and follow along with the discussion
Base classes
Task 1
Open the project UnivMember1
Examine the program carefully
The project contains three classes Person Member Student In main() we create a Student and then attempt to output the students name ndash which fails
name is in the protected section of Person ndash which means only Person methods or methods in derived-from-Person classes can access it
Add a public section to the Person class and relocate the name there
Eg
public
string name
Any better now
The problem now is that Student only by default inherits the private side of Person
Change class Student so that we also inherit the public members of Person hellip
class Student public Person
138
Before we tackle further problems with name lets bring in the Member class (left doing nothing until now)
We really want Student to inherit from Member and not Person Change the code to reflect this
People have dates-of-birth and Members have bod cards Add a string member dateOfBirth to Person and move the bodCardNumber member out of Student and into Member ndash make them both strings
Change the code in main() to set these extra pieces of data
If you havent done it already Persons dateOfBirth and Members bodCardNumber should be set via constructors
139
Task 2
Open and examine the project called UnivMember2
UnivMember2 is a copy of the (exercise solut ion)
UnivMember1 solution
One of the problems we have in UnivMember1 is that too much of it is public eg given Student object s we can change name to simply by using assignment eg sname =
We should protect data members at each level using the maximum level of protection we can ie private
However if we do that then cout ltlt sname will no longer work and so well need to provide access methods to the data members Eg heres a modified Member class showing the basic scheme
class Member public Person
public
Member(string bodCardNumber)
this-gtbodCardNumber = bodCardNumber
string getBodCardNumber() For access
return bodCardNumber
private
string bodCardNumber
140
Another problem is that wed really like to not use assignment at all Eg in the above ctor snippet
this -gt bodCardNumber = bodCardNumber
is using assignment
Change string bodCardNumber to const string bodCardNumber Youll see now that assignment wont now work (you have to initialise constants)
What wed really like (most likely) is to use in i t ial isat ion
We can do this via initialiser lists Ie we could change the above to the following
class Member public Person
public
Member(string bodCardNumber)
bodCardNumber(bodCardNumber)
const string getBodCardNumber()
return bodCardNumber
private
const string bodCardNumber
The initialiser list is read thus
bodCardNumber(bodCardNumber)
^^member^^ ^^parameter^^
Note that weve also modified getBodCardNumber() to show that it returns a const string
141
Modify all three classes to use initialiser lists private const data members and use access functions (getBlah() etc)
Task 3
Open and examine the project called UnivMember3
UnivMember3 is a copy of the (exercise solut ion)
UnivMember2 solution
We will now finish this project to the level of an introductory course
Things to note
The main problem with the solution as it stands is that one may create a Member object
Remember that this is analogous to being able to create a generic Car object ndash we should not be allowed to create one
Going right back to UnivMember1 you may remember a comment in there about a protected constructor
protected Protected ctor Person()
At that point in your project we were thinking two things 1) we wont want to create a generic person and 2) a protected constructor will facilitate this
And we were wrong to think both thoughts
1) A properly thought through Person class would be perfectly good to model generic people But although this is true one question here ndash would we ever want just a generic person
2) A protected constructor in a (more) base class doesnt prevent a derived class from creating a base object So what about the Member class ndash would it be ok to instantiate that
The proper means to prevent a Member being created would be to use what is called a pure v i r tual funct ion as part of its definition (such a function is one that must be overridden in a derived class) But what function
142
If you look at the classes derived from Member ndash you can take it from us that one might want to interrogate at runtime ndash to ask them what they are
So a suitable member function to declare in Member would be something like string getRole() A function that does return Student for a student and return Staff for a Staff object
If its pure virtual in in Member wed best define it in our derived classes
class Member public Person
public
virtual const string getRole() = 0
class Student public Member
public
const string getRole() return Student
143
1 Why did we want duplicate (named) functions in Member Student and Staff 2 And what does virtual really mean
We require both 1 and 2 so that we can provide specific responses when being asked the same question and all when being treated in a rather basic way
Being asked the same question means having a method invoked eg getRole() and in a rather basic way means treating us all Students and Staff (etc) as Persons and Members
112 Polymorphism
Polymorphism comes in a few forms
Ad-hoc Polymorphism via function overloading
Parametric Polymorphism or Compile-Time Polymorphism via templates
Subtype Polymorphism or Runtime Polymorphism via virtual functions and
Coercion Polymorphism via casting
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class (after all a derived from base must have or contain all that a base has) Polymorphism is the art of taking advantage of this simple but powerful and versatile feature
One way Subtype Polymorphism is applied is to use a base reference to access a collection of instances of different types that are derived from a common base ndash one way to paraphrase that is to say that related (derived from a common class) objects respond according to their type rather than according to the type of the reference one uses to access them (a base class pointer type) That is the dynamic type of the object is used instead of its static type
All of this is best demonstrated via an example of course
144
PLUSPLUS Polymorphism
Task 1
Open and examine the project called (exercise
solut ion) UnivMember3
Run the program the output should be the same as shown in Figure 36
The crucial code here is as follows
Member arr[6]
Student studs1()
Student studs2()
Staff staff1()
Student studs3()
Staff staff2()
Student studs4()
arr[0] = ampstuds1
arr[1] = ampstaff1
arr[2] = ampstuds2
arr[3] = ampstaff2
arr[4] = ampstuds3
arr[5] = ampstuds4
for(int i = 0 i lt ++i)
cout ltlt arr[i]
ltlt i ltlt s name is
ltlt arr[i]-gtgetName()
ltlt t Their role is
ltlt arr[i]-gtgetRole()
ltlt endl
Weve created an array of Members (it isnt important that weve used pointers) and note that we have set some of the members of this to be pointers to Student and Staff objects We are allowed to do this as both Student and Staff are derived from Member
However when and if we invoke member functions on these objects wed really like it if they responded as what they really are ndash Student and Staff objects
145
From the output below you can see that they indeed do respond accordingly
Figure 36
The mechanism behind allowing this is the virtualisation of the getRole() member function Remember that this was declared and made virtual in the Member class
Play about with the code eg change
Member arr[6] to Person arr[6] Everything still ok How about not using pointers here ndash easy to do
146
Lastly weve implemented (for no good reason but to show you how its done) some instance counting in all three classes Have a look for the static members and the inserted lines immediately below the class definitions that look like this int PersonCount = 0
The End Thank you for coming and we hope that you enjoyed the class
Oh and please Please PLEASE fill out the feedback form email when it arrives
147
12 Appendices
Arithmetical Operators
Operator Operation
+ Addition
- Subtraction
Multiplication
Division
Modulus
++ Increment
-- Decrement
Table 8 ndash Arithmetical Operators
Assignment Operators
Operator Example Equivalent
= a = b a = b
+= a += b a = a + b
-= a -= b a = a - b
= a = b a = a b
= a = b a = a b
= a = b a = a b
Table 9 ndash Assignment Operators
148
Assignment and Arithmetic examples
The assignment operator in C++ is =
The format is var iable = expression this can be read as assign to the var iable the value of the expression
An example to calculate the number of pence in a value in pounds would be
pence = pounds 100
Note it is easy to confuse the assignment operator = with the equals notation used in mathematics The equals notation in C++ is ==
Incrementing a var iable
month = month + 1 adds the value one to the variable month This can be written as
month++
Decrementing a var iable
month = month - 1 deducts the value one from the variable month This can be written as month--
Note that ++ and ndash can be used before or after the thing being modified eg ++x x++ --y y-- However there are some subtle differences which will be explained in the lectures
In C++ it is also possible to combine arithmetic and assignment operations
To add 2 to a variable total
total = total + 2 or total +=2
To subtract 2 from to tal
total = total - 2 or total -=2
To multiply total by 2
total = total 2 or total =2
Relational and Equality Operators
The equality operator is used to compare two operands (a == b) and returns 1 (t rue) if both are equal otherwise 0 (false ) is returned
The inequality operator (=) returns 1 (t rue) if both are NOT equal otherwise 0 (false) is returned
Both the above operators are commonly used to test the state of two variables to perform conditional branching
The relational operators also return either true or false (a gt= b) returns 1 (t rue ) if a is greater than or equal to b otherwise 0 (false ) is returned
149
Standard algebraic equality or relational
operator
C++ equality or relational operator
Sample C++ condition
Meaning of C++ condition
Relational operators
gt gt a gt b a is greater than b
lt lt a lt b a is less than b
gt= a gt= b a is greater than or equal to b
lt= a lt= b a is less than or equal to b
Equality operators
= == a == b a is equal to b
= a = b a is not equal to b
Table 10 ndash Relational Operators
Logical Operators
When using i f selection statements it is common to use the relational operators as part of the test if(num gt 5) if(size lt= 14) if(Char == A) These are fine for testing one condition
To test multiple conditions it is possible to nest i f statements but this can be a bit cumbersome
Logical Operators can be used to form more complex conditions by combining simple conditions
Logical AND (ampamp) Operator allows a test to see if two conditions are true
if(leaveBooked gt LeaveLeft ampamp staffCover == false)
cout ltlt Take your holidays sometime else
Logical OR (||) Operator allows a test to see if either or both of the conditions are true
if(Temperature lt 16 || windspeed gt 15)
cout ltlt Too cold or windy to sunbath today then
Logical Negation ( ) Operator reverses the meaning of a condition
if((windspeed == 20))
150
cout ltlt The wind speed is not 20 its ltlt windspeed
This could be written equally as well with the equality operator
if(windspeed = 20)
cout ltlt The wind speed is not 20 its ltlt windspeed
Precedence and Associativity Table
Precedence Operator Description Associativity
1 Scope resolution Left-to-right
2
++ -- Suffixpostfix increment and decrement
() Function call
[] Array subscripting
Element selection by reference
-gt Element selection through pointer
typeid() Run-time type information (see typeid)
const_cast Type cast (see const_cast)
dynamic_cast Type cast (see dynamic_cast)
reinterpret_cast Type cast (see reinterpret_cast)
static_cast Type cast (see static_cast)
3
++ -- Prefix increment and decrement Right-to-left
+ - Unary plus and minus
~ Logical NOT and bitwise NOT
(type) Type cast
Indirection (dereference)
amp Address-of
sizeof Size-of
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
151
4 -gt Pointer to member Left-to-right
5 Multiplication division and remainder
6 + - Addition and subtraction
7 ltlt gtgt Bitwise left shift and right shift
8 lt lt= For relational operators lt and le respectively
gt gt= For relational operators gt and ge respectively
9 == = For relational = and ne respectively
10 amp Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 ampamp Logical AND
14 || Logical OR
15 Ternary conditional Right-to-Left
16
= Direct assignment (provided by default for C++ classes)
+= -= Assignment by sum and difference
= = = Assignment by product quotient and remainder
ltlt= gtgt= Assignment by bitwise left shift and right shift
amp= ^= |= Assignment by bitwise AND XOR and OR
17 throw Throw operator (exceptions throwing)
18 Comma Left-to-right
Table 11 ndash Precedence and Associativity Table
Escape Sequences
Escape Sequence
Description
n Newline Position the screen cursor at the beginning of the next line
152
t Horizontal tab Move the cursor to the next tab stop
r Carriage return Position the cursor at the beginning of the current line
a Alert Sound the system bell
Backslash used to print a backslash
Single quote Use to print a single quote character
Double quote Used to print a double quote character
Table 12 ndash Escape Sequences
Cast Operator
Is where the programmer explicitly asks for a change in data type It may be that the result of a calculation is a double and the user wants it to be of type integer
A double can be cast to an integer in the following way
double aNum = 237
int anInt = 0
anInt = static_castltintgt(aNum)
A C style cast may also be used eg
anInt = (int)aNum OR anInt = int(aNum)
Formatted Output
When several numbers are displayed each is printed with the minimum number of digits needed to show the value This can yield some unexpected output
The width of an output field can be set using a stream manipulator To set the next number to be printed to a width of 5 digits use cout ltlt setw(5) This command does not produce any output it manipulates the stream to change the output format of the next value Note setw() must be specified for every item output
To use any stream manipulators you must include the header include ltiomanipgt
setprecision is another manipulator and is used to set the precision of the next floating point number Note setprecis ion only has to be set once as the stream remembers the formatting directive and does not affect integer fields The format is cout ltlt
setprecision(3)
To set precision for trailing zeros (0100 will appear as 01) it is necessary to use the fixed format The notation is cout ltlt fixed Note f ixed only has to be set once
The three manipulators can be combined to achieve the required precision and field width when used in this way
153
cout ltlt fixed ltlt setprecision(3) ltlt setw(5) ltlt myDouble
Alternatively as fixed and setprecision only have to be set once this statement could be written as
cout ltlt fixed ltlt setprecision(3)
cout ltlt setw(5) ltlt myDouble
Header Files
Every program that you create will have at least one header file If you use input or output you will have to include the iostream header
If you use mathematical functions you will need cmath It can be difficult to know which header files to use for each function Some of the common header files used together with some of the older ones you may find with inherited code are shown below It is a good idea to use the help if you are unsure which header files are associated with particular functions
Standard C++ header Old header
iostream iostreamh
iomanip iomaniph
fstream fstreamh
cmath mathh
cstdlib stdlibh
string No equivalent
vector vectorh
Table 13 ndash Header Files Old and New
Matrix Libraries
The STL does not contain a Matrix type and so we must look elsewhere for a suitable implementation that suits the individuals needs
The table below lists the third party libraries that we are aware of
Some Linear AlgebraMatrix Libraries
Armadillo Blitz++ Boost
CPPLapack CPPScaLapack CVM Class Library
Eigen Elemental FLENS
Gmm++ GNU Scientific Library (GSL) HSL
154
IML++ IT++ LA library
Lapack++ LinBox Matrix Template Library (MTL)
MV++ Newmat PETSc
RNM Seldon SimuNova
SL++ (Scientific Library)
SparseLib++ SuiteSparse
TCBI (Temporary Base Class Idiom)
Template Numerical Toolkit (TNT)
Trilinos
uBlas ViennaCL
Table 14 ndash Matrix Libraries
Scope
The portion of a program where an identifier can be used is known as its scope
An identifier declared outside any function or class has f i le scope This type of identifier is known by all functions Global variables and function prototypes all have file scope
Identifiers declared inside a block of code have block scope This type of scope begins at the identifiers declaration and ends at the termination right brace ( ) of the block in which the identifier is declared
Any block can contain local variable declarations If blocks are nested it is possible to declare variables with the same name in each nested block The variable in the outer block is hidden while the inner block is being executed
Enumerating constants
The enum keyword provides a handy way to create a sequence of integer constants An example of enumeration is shown below
enum Months JAN = 1 FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
Each of the constants will have a default value 1 greater than the constants that it follows in the list The first value in the enumeration above is explicitly set to 1 and the remaining values increment by 1 The values assigned from JAN to DEC will be 1 to 12
The statement cout ltlt DECEMBER is month number ltlt DEC ltlt endl would be output as DECEMBER is month number 12
Constants
Data that will not change during the execution of a program should be stored in a constant container rather than a variable If the program attempts to change the value stored in a constant the compiler will report an error and compilation will fail
Constant can be created for any data type by prefixing the declaration with const keyword followed by a space Note Constants must always be initialised at declaration
The following declaration declares a constant for the speed of sound at sea level ms
155
const double SpeedOfSound = 34029
Vector member functions
Some commonly used member functions of the vector class are
Vector member Functions Effect
at(element number) Gets the value contained in the specified element
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
push_back(value) Adds an element to the end of the vector containing the specified value
size() Gets the number of elements
Table 15 ndash Vector Member Functions
Global functions
Global functions are not member functions They take more than one argument and operate on a range of elements rather than on the vector container ie they can be used on other types of containers
Vector global Functions Effect
find()
ptr = find(vbegin() vend() 67)
Finds the element in the vector containing number 67 Needs iterator (ptr) to store location of element
reverse()
reverse(vbegin() vend()) Reverses the values in a vector (v)
sort()
sort(vbegin() vend()) Sorts the vector (v)
Table 16 ndash Vector Global Functions
156
list member functions
Some commonly used member functions of the list class are
List member Functions Effect
back() Gets the value in the final element
begin() Points to the first element in vector
clear() Erases the vector
empty() Returns true (1) if the vector is empty or false (0) otherwise
end() Points to the last element in vector
front() Gets the value in the first element
insert() Insert new elements before position
pop_back Removes the final element
pop_front Removes the first element
push_back(value) Adds an element to the end of the vector containing the specified value
sort() Sorts the elements in the container from lower to higher
size() Gets the number of elements
swap() Exchanges the content of the list
Table 17 ndash List class Member Functions
cmath functions
Function Argument Result Returned Value Example Result
ceil(x) double double Smallest integer ge x
ceil(21) 30
cos(x) double double Cosine of x radians cos(10) 054
fabs(x) double double Absolute value of x
fabs(-15) 15
floor(x) double double Largest integer le 29
floor(29) 20
157
pow(x y) double double x to the yth power pow(24) 160
sin(x) double double Sine of x radians sin(10) 084
sqrt(x) double double Square root of x sqrt(4) 20
tan(x) double double Tangent of x radians
tan(10) 156
Table 18 ndash cmath Functions
158
String class
The string class defines many member funct ions A few of the basic ones are described below
Initialisation - constructors form
A string expression string str2 = str1
A character string literal string Intro = Programming with C++
A substring of another string object
string Intro = Capetown
string Mytown = Boars
string MyTown(Intro 4 5)
starts at character 4 (t)
with a length of 5 (or the rest of the string if shorter)
cout ltlt myTown ltlt endl
will produce an output town
Member Functions
length()
string myName = Sebastion
myNamelength()
will produce an output of 9
insert ()
Inserts a string into the current string starting at the specified position
string myName = Sebastion
string nameAdd = rjio
myNameinsert (2nameAdd)
cout ltlt myName ltlt endl
will produce an output Serjiobastion
erase()
Delete a substring from the current string
string myName = Sebastion
myNameerase (02)
cout ltlt myName ltlt endl
will produce an output bastion
replace()
Delete a substring from the current string and replace it with another string
string myName = Sebastion
string aName = renna
159
Member Functions
myNamereplace(3 6 aName)
cout ltlt myName ltlt endl
will produce an output Sebrenna
find()
Search for the first occurrence of the substring in the current string If the word is found return the position of the first character If not return -1
string sName
string findWord
position = sNamefind(findWord)
substr()
Returns a substring of the current string
string myName = Sebastion
string aName = myNamesubstr(0 3)
cout ltlt aName ltlt endl
will produce an output Seb
Non-member functions
getline()
string name
getline(cin name)
Table 19 ndash String Class Member Functions
160
A number of C++ operators also work with str ing objects
Operator
=
string fString = Hello
string lString
lString = fString
Assign a character (char ) to a str ing object
string aStringC
aStringC = Z
+
Concatenate two str ing objects
string str1 = C++
string str2 = Programming
string str3 = str1 + str2
+
Concatenate a string object and a character string literal
string str = Hello
string str1 = str + there
The same concatenation can be done in this way
str += there
+
Concatenate a string object and a single character
string str = Bye Bye
string strBye = str +
161
ASCII Character set
Decimal Octal Hexadecimal Binary Value Meaning
0 0 0 0 NUL (Null char)
1 1 1 1 SOH (Start of Header)
2 2 2 10 STX (Start of Text)
3 3 3 11 ETX (End of Text)
4 4 4 100 EOT (End of Transmission)
5 5 5 101 ENQ (Enquiry)
6 6 6 110 ACK (Acknowledgment)
7 7 7 111 BEL (Bell)
8 10 8 1000 BS (Backspace)
9 11 9 1001 HT (Horizontal Tab)
10 12 00A 1010 LF (Line Feed)
11 13 00B 1011 VT (Vertical Tab)
12 14 00C 1100 FF (Form Feed)
13 15 00D 1101 CR (Carriage Return)
14 16 00E 1110 SO (Shift Out)
15 17 00F 1111 SI (Shift In)
16 20 10 10000 DLE (Data Link Escape)
162
Decimal Octal Hexadecimal Binary Value Meaning
17 21 11 10001 DC1 (X ON) (Device Control 1)
18 22 12 10010 DC2 (Device Control 2)
19 23 13 10011 DC3 (X OFF)(Device Control 3)
20 24 14 10100 DC4 (Device Control 4)
21 25 15 10101 NAK (Negative Acknowledgement)
22 26 16 10110 SYN (Synchronous Idle)
23 27 17 10111 ETB (End of Trans Block)
24 30 18 11000 CAN (Cancel)
25 31 19 11001 EM (End of Medium)
26 32 01A 11010 SUB (Substitute)
27 33 01B 11011 ESC (Escape)
28 34 01C 11100 FS (File Separator)
29 35 01D 11101 GS (Group Separator)
30 36 01E 11110 RS (Request to Send)(Record Separator)
31 37 01F 11111 US (Unit Separator)
32 40 20 100000 SP (Space)
33 41 21 100001 (exclamation mark)
34 42 22 100010 (double quote)
163
Decimal Octal Hexadecimal Binary Value Meaning
35 43 23 100011 (number sign)
36 44 24 100100 $ (dollar sign)
37 45 25 100101 (percent)
38 46 26 100110 amp (ampersand)
39 47 27 100111 (single quote)
40 50 28 101000 ( (leftopening parenthesis)
41 51 29 101001 ) (rightclosing parenthesis)
42 52 02A 101010 (asterisk)
43 53 02B 101011 + (plus)
44 54 02C 101100 (comma)
45 55 02D 101101 - (minus or dash)
46 56 02E 101110 (dot)
47 57 02F 101111 (forward slash)
48 60 30 110000 0
49 61 31 110001 1
50 62 32 110010 2
51 63 33 110011 3
52 64 34 110100 4
164
Decimal Octal Hexadecimal Binary Value Meaning
53 65 35 110101 5
54 66 36 110110 6
55 67 37 110111 7
56 70 38 111000 8
57 71 39 111001 9
58 72 03A 111010 (colon)
59 73 03B 111011 (semi-colon)
60 74 03C 111100 lt (less than)
61 75 03D 111101 = (equal sign)
62 76 03E 111110 gt (greater than)
63 77 03F 111111 (question mark)
64 100 40 1000000 (AT symbol)
65 101 41 1000001 A
66 102 42 1000010 B
67 103 43 1000011 C
68 104 44 1000100 D
69 105 45 1000101 E
70 106 46 1000110 F
165
Decimal Octal Hexadecimal Binary Value Meaning
71 107 47 1000111 G
72 110 48 1001000 H
73 111 49 1001001 I
74 112 04A 1001010 J
75 113 04B 1001011 K
76 114 04C 1001100 L
77 115 04D 1001101 M
78 116 04E 1001110 N
79 117 04F 1001111 O
80 120 50 1010000 P
81 121 51 1010001 Q
82 122 52 1010010 R
83 123 53 1010011 S
84 124 54 1010100 T
85 125 55 1010101 U
86 126 56 1010110 V
87 127 57 1010111 W
88 130 58 1011000 X
166
Decimal Octal Hexadecimal Binary Value Meaning
89 131 59 1011001 Y
90 132 05A 1011010 Z
91 133 05B 1011011 [ (leftopening bracket)
92 134 05C 1011100 (back slash)
93 135 05D 1011101 ] (rightclosing bracket)
94 136 05E 1011110 ^ (caretcirumflex)
95 137 05F 1011111 _ (underscore)
96 140 60 1100000 `
97 141 61 1100001 a
98 142 62 1100010 b
99 143 63 1100011 c
100 144 64 1100100 d
101 145 65 1100101 e
102 146 66 1100110 f
103 147 67 1100111 g
104 150 68 1101000 h
105 151 69 1101001 i
106 152 06A 1101010 j
167
Decimal Octal Hexadecimal Binary Value Meaning
107 153 06B 1101011 k
108 154 06C 1101100 l
109 155 06D 1101101 m
110 156 06E 1101110 n
111 157 06F 1101111 o
112 160 70 1110000 p
113 161 71 1110001 q
114 162 72 1110010 r
115 163 73 1110011 s
116 164 74 1110100 t
117 165 75 1110101 u
118 166 76 1110110 v
119 167 77 1110111 w
120 170 78 1111000 x
121 171 79 1111001 y
122 172 07A 1111010 z
123 173 07B 1111011 (leftopening brace)
124 174 07C 1111100 | (vertical bar)
168
Decimal Octal Hexadecimal Binary Value Meaning
125 175 07D 1111101 (rightclosing brace)
126 176 07E 1111110 ~ (tilde)
127 177 07F 1111111 DEL (delete)
Table 20 ndash Full ASCII Table
169
Handy IDE Settings
Line Numbers onoff Tools | Options | Text Editor | CC++ | Line Numbers
Auto closing the console Tools | Options | Debugging | Automatically close the console window when debugging stops
Saves having to use system(pause)
170
REMAINING PAGES LEFT BLANK FOR NOTE TAKING
171
172
173
Peet Morris
peetmorrisgmailcom
C++ A Comprehensive Introduction
Arrangements
bull We Startfinish at 915am 500pm
bull Format two lectures per day (ask questions) hands-on at all other times
bull You should have Course book (copy of the slides at the back)
bull The course software is pre-installed on the machines
And also separately available from
The compilerIDE wwwvisualstudiocom
Notesslidesexercise files wwwpeetmcomC++introcoursezip
Your safety is important
Where is the fire exit
Beware of hazards
Tripping over bags and coats
Please tell us if anything does not work
Let us know if you have any other concerns
Your comfort is important
The toilets are along the corridor just outside the teaching rooms
The rest area is where you registered it has vending machines and
a water cooler
The seats are adjustable
You can adjust the monitors for brightness
What we assumehellip
What we assume
Experience of using another programming
language
Comprehensive Lots to get through
C++ and OOP
bull Created in 1985 by Bjarne Stroustrup C++ is a highly efficient
multiplatform low level Object Oriented Programming language
bull Latest version is C++17
stroustrupcom
Standard C++ Library
bull Written in the core language it is a collection of classes
(object definitions) functions and algorithms
See wwwcpluspluscomreference
IDEs amp Compilers
Visual Studio 2017
First Program
First application
include ltiostreamgt
using namespace std
int main()
int aNum = 0 aNum(0) or aNum0
cout ltlt Enter a number-
cin gtgt aNum
cout ltlt You entered ltlt aNum
return 0
hellip hellip
First Program
bull include ltiostreamgt
Adds the contents of the iostream header file into the program (for cout and cin)
bull using namespace std
So we donrsquot have to write stdcout ltlt and stdcin gtgt all of the time
bull cin is the standard input stream object that allows input from the keyboard
bull cout is the standard output stream object that allows output to the screen
bull int main() The programs entry point
Mandatory main function in every C++ program ndash always returns an integer value
First Program
bull int aNum = 0
Variable to hold a value of type integer (piece of machine memory referred to via the name aNum)
bull ltlt stream insertion operator ndash outputs to console
cout ltlt Enter a number-
bull gtgt stream extraction operator ndash waits for keyboard input
cin gtgt aNum
Other Types
Microsoft data types summary httpsdocsmicrosoftcomen-gbcppcppfundamental-types-cpp
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststack
Lots
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
x 1
y 2
x 3
y 4
p1
p2
x
y
Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 copies the bit pattern from p1 to p2
x 1
y 2
x 1
y 2
p1
p2
Compound Types
Cannot define operators other than assignment
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
p2 = p1 p2 compilation error
x 1
y 2
x 3
y 4
p1
p2
Compound Types
We can arbitrarily further compound things
struct point
int xint y
struct rectangle
point tlpoint br
struct line
point startpoint end
startxy
endxy tlxy
brxy
Compound Types
We can also group things using struct to create compound
types
struct point
int xint y
struct rectangle
point tlpoint br
int main()
rectangle r
rtlx = 1rtly = 2
rbrx = 3rbry = 4
int diff_x = abs(rtopLeftx - rbottomRightx)int diff_y = abs(rtopLefty - rbottomRighty)
cout ltlt area ltlt diff_x diff_y ltlt endl
r
tl
br
x 1
y 2
x 3
y 4
Using a Library Type
include ltstringgt
string s
cout ltlt What is your name
getline(cin s)
cout ltlt s ltlt
ltlt is
ltlt slength() ltlt
ltlt characters long ltlt endl
s
Other Types
C++ types (native to the compiler)bool[signedunsigned] char[signedunsigned] int[signedunsigned] short int[signedunsigned] long int[signedunsigned] long long int
floatdoublelong doublepointers
include-ed types (defined in the library)
stringvectorarrayliststackcomplex
Lots
8 bit Binary signed unsigned
00000001 1 1
00000010 2 2
00000011 3 3
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111101 -3 253
11111110 -2 254
11111111 -1 255
00000000 0 0
00000001 1 1
00000010 2 2
signed vs unsigned ndash its all just 1s and 0s and adding
Adding rules
0 + 0 = 0
1 + 0 = 1
0 + 1 = 1
1 + 1 = 0 (carry 1)
1 + 1 + 1 = 1 (carry 1)
-126 + +3 =
10000010
00000011 +
10000101 = -123
-126 + -3
10000010
11111101 +
01111111 = 127 (why not -129)
Arithmetic Operators
+ Addition
- Subtraction and unary minus
Multiplication
Division
Remainder after division (moduloclock arithmetic)
int j k l = 10
j = l 3 js value will be three
k = l 3 ks value will be 1
Relational Operators
Evaluate to either true or false represented by integer values 1 and 0
== Equal to
= Not equal to
gt Greater than
lt Less than
gt= Greater than or equal to
lt= Less than or equal to
Increment and Decrement Operators
++ Increment
-- Decrement
Can be prefix or postfix
b = 3
a = b++ + 6 Add 6 to b then increment b a is 9 b is 4
b = 3
a = ++b + 6 Increment b then add 6 to b a is 10 b is 4
Assignment Operators
Symbol Operation Long Short
= Assign a = 2 a = 2
+= Assign with add a = a + 2 a += 2
-= Assign with subtract a = a ndash 2 a -= 2
= Assign with multiply a = a 2 a = 2
= Assign with divide a = a 2 a = 2
= Assign with remainder a = a 2 a = 2
Basic Control Flow - if
Sequence
What we have been doing already
Selection
if statement if this then that
if (boolean expression) if (score gt= 50)
statement cout ltlt Passed
Logical Operators
Boolean expressions may be combined using
ampamp And
|| Or
Not
Operands and result resolves being either true or false
if (x ampamp (y || z))
else
Precedence and Associativity table in course book
Logical Operators
a b =
true true true
true false false
false true false
false false false
a b =
true true true
true false true
false true true
false false false
a =
true false
false true
a ampamp b a || b a
Logical Operators
if (x ampamp (y || z))
else
The value 0 (zero) is evaluated to mean false any other value is true
x ampamp (y || z) result
false ampamp (false || false) falsefalse ampamp (false || true ) falsefalse ampamp (true || false) falsefalse ampamp (true || true ) falsetrue ampamp (false || true ) falsetrue ampamp (false || false) truetrue ampamp (true || false) truetrue ampamp (true || true ) true
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp (y | ~z))
else
Bitwise Operators
unsigned int x = 11
unsigned int y = 7
unsigned int z = 25
if (x amp (y | ~z))
else
11 (x) = 000010117 (y) = 0000011125 (z) = 00011001
~z = 11100110 (230 or -26)
y | ~z = 11100111 (231 or -25)
x amp (y | ~z) = 00000011 = 3
Operands and the result resolve to a values
Bitwise Operators
Bitwise expressions may be combined using
amp And
| Or
~ Not
^ XOr
gtgt Right shift
ltlt Left shift
if (x amp 1) x is odd
if (x gt y)
x = x ^ y
y = y ^ x XOr swap
x = x ^ y
Control Flow - if else
Selection
ifelse statements
if (boolean exp) if (score gt= 50)
statement cout ltlt Passed
else else
statement cout ltlt Failed
Control Flow -
Selection
Conditional (or Ternary) Operator
boolean exp true result false result
cout ltlt score gt= 50 Passed Failed
Control Flow
if (x gt= y)
if (y 2)
else
if (x gt= y)
if (y 2)
else
Control Flow ndash else if
if (exp)
else if (exp)
else if (exp)
else catch all remaining
if (aNum == 0)
else if (aNum == 1 || aNum == 2)
else if (aNum == 3)
else catch all remaining
aNum not 0123
Control Flow - switch
Selection
switch multiple selection statements
bull test must be an integral value 1 10 A x eg not 1056
bull case values must be constants
switch (aNum)
case 0
break
case 1 Fall through
case 2
break
default catch all
break
Repetition - while
while (exp)
statements
while (n lt k)
cout ltlt Enter mark
cin gtgt mark
t += mark
n++
Repetition - for
for (init exp inc)
statements
for (t = 0 n lt k n++)
cout ltlt Enter mark
cin gtgt mark
t += mark
Preferable to while if the range is known
Repetition - for
for (init exp inc)
statements
for () infinite loop
break causes loop to exit
Preferable to while if the range is known
Repetition - do
do
statements
while (exp)
do
cout ltlt Continue yn
cin gtgt yn
yn = tolower(yn)
while (yn = y ampamp yn = n)
There are a huge number of exercises and we donrsquot expect you to attempt
them all during this course
bull If yoursquore completely new to programming itrsquos probably best to tackle
them in sequence
bull If yoursquove some programming experience you should read through the
exercise summaries and then start wherever you feel comfortable
Exercises
Exercises
Topics covered in ex1 ndash ex6
Functions = mini programs
bull Used to combine data with operations and through functional
decomposition to promote code re-use
bull Simplifies coding
bull Functions for discrete tasks
bull Not hundreds of lines of code
bull Consumer only needs to know
bull What goes in and what comes out
Functions
Like everything else the compiler needs to have seen a prototype or a
definition of a function before we can use it
Prototypes lets the compiler generate the correct code
int min(int int)
int min(int int int)
void drawLine(point to point from = 00)
int square(int)
int main()
void beep()
string getNextPacket(void)
Return type Function name (Parameter list)
min
int min(int int) min prototypes (forward declarations)int min(int int int)
int main()
Having seen the prototypes the compilerc = min(x y) can generate the required code
int min (int a int b) min function definition 1
return a lt b a b
int min (int a int b int c) min function definition 2
return min(min(a b) c)
inline min
int main()
c = min(x y)
inline int min (int a int b)
return a lt b a b
int main()
c = x lt y x y
inline int min (int a int b)
return a lt b a b
Function Parameters
bull Pass by Value
bull A Copy of the parameter is passed to the called function
bull Pass by Reference
bull The actual parameter is passed to the called function
bull Pass by Memory Address (pointer)
bull Same effect as Pass by Reference (tomorrow)
Pass by value
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
return n_copy n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 10
n_copy 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp x)
x just another name for real_n
return x x
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
x 10
Pass by value (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int n_copy)
n_copy = n_copy n_copy
return n_copy
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x7121 100
n_copy 100
Pass by reference (parameter treated as variable)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(int amp real_n)
real_n = real_n real_n
return real_n
100
100
Mem Addr Contents
0x2786 100
real_n 100
Mem Addr Contents
0x2786 100
real_n 100
const Parameters
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Recursion
unsigned long long int fibonacci(int n)
switch(n)
case 0 Fall through - [[fallthrough]]
case 1
return n
break
default
return fibonacci(n - 1) + fibonacci(n - 2) Very inefficient
Arrays (Part 1)
Data structure containing same type of data (int double string char object)
bull Built in to C++
bull Series of elements each containing one item of data (contiguous memory locations)
Size (number of elements) set at compile time
Arrays (1)
int numbers[10] an array of 10 integers Each box sizeof(int) bytes wide
numbers
index values - 0 to 9
0 1 2 3 4 5 6 7 8 9
Arrays (1)
int numbers[10] an array of 10 integers
int n = 0
cout ltlt numbers ltlt endl address of the first element
cout ltlt numbers[n] ltlt endl contents of the nth element
cout ltlt ampnumbers[n] ltlt endl address of the nth element
cout ltlt numbers + n ltlt endl address of the nth element
0 1 2 3 4 5 6 7 8 9
42 hellip hellip hellip hellip hellip hellip hellip hellip hellip
0x1526
Arrays
char name[5] name - an array of five characters
thing t[5] t - an array of five things
examMarks ndash an array of three doubles initialised to 12 39 95double examMarks[] = 12 39 95 C++11 - double examMarks[] 12 39 95
header ndash an array of fifty unsigned chars (bytes) first three elements set to 0 1 255 and the rest to zerotypedef unsigned char bytebyte header[50] = 0 1 -1
Arrays
Accessing array data
define MARKS 5 or const int MARKS = 5
double examMarks[MARKS]
for(int i = 0 i lt MARKS i++)
cout ltlt Enter Exam Mark
ltlt i + 1 ltlt
cin gtgt examMarks[i]
for(i = 0 i lt MARKS i++)
cout ltlt examMarks[i]
Multidimensional Arrays
Two dimensional array Two subscripts First identifies row second identifies column
const int students = 6 const int marks = 3
double examMarks[students][marks] = 0 set to zero
for (int s = 0 s lt students ++s)
for (int m = 0 m lt marks ++m)
cout ltlt Enter mark ltlt m + 1 ltlt for student ltlt s + 1 ltlt endl
cin gtgt examMarks[s][m]
00 01 02
10 11 12
20 21 22
30 31 32
40 41 42
50 51 52
Memory laid out in row column order (more later)
00 01 02 10 11 12 20 21 22 30 31 32 40 41 42 50 51 52
Matrices
Provider Link
Armadillo armasourceforgenet
Blitz blitzsourceforgenet
Boost boostorg
Eigen eigentuxfamilyorg
Elemental libelementalorg
FLENS apfelmathematikuni-ulmde
HSL hslrlacuk
LEDA algorithmic-solutionscom
PETSc mcsanlgov
SimuNova simunovacom
SuiteSparse facultycsetamuedu
TNT mathnistgov
Trilinos trilinosorg
ViennaCL viennaclsourceforgenet
Exercises
Topics covered in ex7 ndash ex16
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people
C++ and OOP
Object Oriented Programming
A mechanism allowing us to model both real world and abstract entities by
extending the type system
strings lists cars houses people and dice
Recap Compound Types
We can also group things using struct to create compound types
struct point
int xint y
int main()
point p1point p2
p1x = 1p1y = 2
p2x = 3p2y = 4
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 1
struct dice
int sides
int diceThrow(dice d)
srand((unsigned)time(0))
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
1 61 61 61 61 6
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
Dice throwing 2
struct dice
int sides
int diceThrow(dice d)
return (rand() dsides) + 1
int main()
dice d1 d2
d1sides = 6 d2sides = 6
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt diceThrow(d1) ltlt ltlt diceThrow(d2) ltlt endl
return 0
3 11 24 56 12 3
C++ and OOP
Encapsulation Keeping related stuff together
Member functionsmethods
an objectrsquos capabilities functionality and performable actions
int Throw()
Member variablesproperties
an objectrsquos current state values its dumb data
int sides
Dice throwing 3
struct dice
int sides State
dice(int n) Constructor
sides = n
int Throw() Member function (method)
return (rand() sides) + 1
int main()
Could also use dice d1 = 6 or d16 syntaxdice d1(6) d2(6)
d1sides = 6 d2sides = 10 Allow this
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
struct diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 4
class diceprivate Access modifier
int sides
public Access modifier
dice(int n)
sides = n
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
d1sides = 6 d2sides = 6 illegal now
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing ndash professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
diceh my-appcpp
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
dicecpp
Compiler
diceobj my-appobj
Linker
my-appexe
other librarycode objectfiles
Dice throwing - professional layout amp IPR
class diceprivate
int sides
public
dice(int n)
int Throw()
include ltiostreamgtinclude ltctimegtinclude diceh
using namespace std
int main()
dice d1(6) d2(6)
srand((unsigned)time(0))
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Compiler
include ltrandomgtinclude diceh
dicedice(int n)
sides = n
int diceThrow()
return (rand() sides) + 1
diceobj my-appobj
diceh dicecpp my-appcpp
Linker
my-appexe
other librarycode objectfiles
Only items provided to the end-usercustomer
Classes and Objects
the includeltstringgt header file from the standard library
class string
your cpp source code files
include ltstringgt include information about class string
string Name a class string instance
string Address a class string instance
Classes and Objects
the include carh header file
class car
your cpp source code files
include carh include information about class car
car c a class car instance
Classes and Objects
the include househpp header file
class house
your cpp source code files
include househpp include information about class house
house no1 a class house instance
house no2 a class house instance
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do with it
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
class car
What properties and methods do we need Think how wed use a ltcargt and what wed want it to be able to do
include carh
int main()
car c
cwheels = 4
cengine = V8
cstart()
caccelerate()
cstart()
cenginestart() Or should cstart() internally use enginestart()
OOD
Time for a break
class student
What properties and methods do we need
class student
public
string name
string DoB
string college
string bodCardNumber
float age()
int main()
student s
sname =
sDoB =
How to guarantee an objectrsquos integrity
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s
sname = Compilation errors
sDoB =
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
m_name = name m_DoB = DoB
float age()
return calcAge(m_DoB)
int main()
student s( )
cout ltlt sage()
Class Constructor
class student
private
string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB )
if(namelength() || DoBlength())
throw(student initialisation failed)
else
m_name = name m_DoB = DoB Error ndash cant assign to a constant
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_name(name) m_DoB(DoB)
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Class Constructor
class student
private
const string m_name string m_DoB
public
student(string name string DoB ) m_namename m_DoBDoB
if(checkName(m_name) || checkDoB(m_DoB)) Check - post initialisation
throw(student initialisation failed)
initialisation
Exceptions
class student
int main()
try
student s( )
catch(const char msg)
cout ltlt msg ltlt endl
student initialisation failed
Exceptions
try
catch(const char msg)
cout ltlt msg ltlt endl
catch (const invalid_argument amp e)
cout ltlt ewhat() ltlt endl
catch (exception amp e)
cout ltlt ewhat() ltlt endl
catch ()
cout ltlt Something went wrong ltlt endl
student invalid arg 2
if using C++11 see stdcurrent_exception
Reuse and inheritance
Say we now want to add a new type to our system ndash class academic With what we have seen so far we would proceed something like this
class academic
private
string m_name string m_DoB
Duplicating everything we had in class student
class person (generalisation)
OOP is sometimes called Programming by Describing the differences
student and academic are all specialisations of a more generalised and abstract class ndash person
class student public personpublic
student(string name) person(name)
class academic public personpublic
academic(string name) person(name)
class personprotected
person(string name) m_name(name)
private
string m_name
public
base class derived class
derived class
Specialised State
class student public person
private
const string m_bodCard
public
student(string name string DoB string bc ) person(name DoB) m_bodCard(bc)
Multiple inheritance
class student public person public oxMember
public
student(string name int age string bc) person(name age) oxMember(bc)
class academic public person public oxMember
public
academic(string name int age string bc) person(name age) oxMember(bc)
Destructors
class foo
private
int m_x int m_y
public
foo() foo(0 0)
foo(int x) foo(x 0)
foo(int x int y) m_x(x) m_y(y) only ctor that accesses private state
~foo() any necessary tidy up code
Dice throwing 5
class diceprivate
int sides
public
dice(int n) sides(n)
int Throw()
return (rand() sides) + 1
int main()
dice d1(6) d2(6)
srand((unsigned)time(0)) Happy with this
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
Dice throwing 6
class diceprivate
int sides
public
dice(int n) sides(n)
classshared state static bool seeded = false
if (seeded)srand((unsigned)time(0))seeded = true
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
3 65 21 44 22 6
Dice throwing 7
class dice private
int sides
public
dice(int n) sides(n)
int Throw()
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
Dice throwing 7
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyesDouble 14 33 5
Dice throwing 8
class dice private
int sidesint lastThrow
public
dice(int n) sides(n)
int Throw()
return lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
friend ostream amp operator ltlt (ostream amp os dice const amp d)
return os ltlt dlastThrow
int main()
dice d1(6) d2(6) int t
for(int n = 0 n lt 5 ++n)
cout ltlt (t = d1Throw()) ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp t = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Dice throwing 9
class dice private
int sidesint _lastThrow
public
const int amp lastThrow read-only stateproperty
dice(int n) _lastThrow(-1) lastThrow(_lastThrow) sides(n)
int Throw()
return _lastThrow = (rand() sides) + 1
int operator + (dice d)
return lastThrow + dlastThrow
bool operator == (dice d)
return lastThrow == dlastThrow
int main()
dice d1(6) d2(6)
for(int n = 0 n lt 5 ++n)
cout ltlt d1Throw() ltlt ltlt d2Throw() ltlt endl
if (d1 + d2 == 2)
cout ltlt Snake eyes ltlt endl
if(d1 == d2 ampamp d1lastThrow = 1)
cout ltlt Double ltlt ltlt d1 ltlt endl
1 55 5Double 51 1Snake eyes4 33 5
Exercises
Topics covered in ex17 ndash ex22
Vectors
Like an array a data structure containing same type of data (int double object)
bull A container class part of the standard library a wrapper similar to arrays
Need to includeltvectorgt
bull Can resize grow shrink as elements are added or removed from the end
bull Algorithms to manipulate data
bull Iterators to cycle through all the elements
Vectors
vectorltchargt name(5) vector of five characters
vectorltthinggt t(5) vector of five things
vectorltdoublegt examMarks 12 39 95 initialised vector of three doubles
typedef unsigned char byte
a vector of fifty bytes first three elements set to 0 1 255 and the rest to zerobyte char b[50] = 0 1 255 fully populate array
calc itemCountint itemCount = sizeof(b) sizeof(b[0])
vectorltbytegt bytes (b ampb[0] + itemCount) then init with vector 50 items
Vectors (iteration 1)
include ltvectorgt
vectorltintgt vec(20) 20 ints
for(int i = 0 i lt vecsize() i++) input values into vec
cin gtgt vec[i]
for(i = 0 i lt vecsize() i++) output vec
cout ltlt vec[i] ltlt
Vectors (iteration 2) (C++11 and later)
for(type identifier container)
statements
vectorltintgt vec(20)
for (int amp i vec)
Vectors
Adding an extra element
cout ltlt Enter an Extra Value
cin gtgt aNum
vecpush_back(aNum)
for (int i = 0 i lt vecsize() i++)
cout ltlt vec[i] ltlt endl
cout ltlt vecat(i) ltlt endl same as above but range checked (ie slowsafe)
Vectors (most of the methods)
docsmicrosoftcomen-uscppstandard-libraryvector-classFull list
Method Purpose
assign Erases a vector and copies the specified elements to the empty vector
at Returns a reference to the element at a specified location in the vector
back Returns a reference to the last element of the vector
begin Returns a random-access iterator to the first element in the vector
capacity Returns the number of elements that the vector could contain without allocating more storage
clear Erases the elements of the vector
C++11 data Returns a pointer to the first element in the vector
C++11 emplace Inserts an element constructed in place into the vector at a specified position
C++11 emplace_back Adds an element constructed in place to the end of the vector
empty Tests if the vector container is empty
end Returns a random-access iterator that points to the end of the vector
erase Removes an element or a range of elements in a vector from specified positions
front Returns a reference to the first element in a vector
insert Inserts an element or a number of elements into the vector at a specified position
max_size Returns the maximum length of the vector
pop_back Deletes the element at the end of the vector
push_back Add an element to the end of the vector
rbegin Returns an iterator to the first element in a reversed vector
rend Returns an iterator to the end of a reversed vector
reserve Reserves a minimum length of storage for a vector object
resize Specifies a new size for a vector
C++11 shrink_to_fit Discards excess capacity
size Returns the number of elements in the vector
swap Exchanges the elements of two vectors
Vectors (iteration 3)
include ltalgorithmgt
vectorltintgt vec
for(int i = 1 i lt= 5 ++i)vecpush_back(i)
1 2 3 4 5
5 4 3 2 1
vectorltintgtiterator it
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Reverse the vectorreverse(vecbegin() vecend())
cout ltlt endl
for(it = vecbegin() it = vecend() ++it)cout ltlt ltlt it
Arrays (2) (C++11 and later)
arrayltint 5gt arr Thin veneer over an array ndash so requires fixed size
arrfill(0) int j = 0
for (int amp i arr)
supports latest iteration style
reverse(arrbegin() arrend()) and iterators for use with algorithms
C++11 - Uniform initialisers
C++98
complexltdoublegt c( 271828 314159 )
int a[] = 1 2 3 4
vectorltintgt v
for( int i = 1 i lt= 4 ++i )
vpush_back(i)
C++11
complexltdoublegt c 271828 314159
int a[] 1 2 3 4
vectorltintgt v 1 2 3 4
Pointers ndash What
A pointer is a scalar variable that is used to hold the memory-address of
another variable or function the stored address is said to point to the thing
it holds ndash thus the name
Pointers have a type ndash the type of the thing they point to
int n = 10I (p) am a pointer to an integer and I point to n over thereint p = ampn
Pointers ndash Why
In no particular order
bull Because external libraries and APIs (like the operating system (all of them)) are written using them
bull Create custom data structures like linked-lists trees graphs etc
bull Create tables of functions or single functions for handling events callback or signals
bull Access data on to the heap (allocate memory dynamically)
bull Writecall functions that change their input parameters
1 2
3
4 5 6 nilhead
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
amp and
Overloaded
amp
address of ampnumbers[n]
reference int amp square(int amp x)
bitwise AND if(n amp 1)
logical AND if(fu() ampamp bar())
rvalue reference obj ampamp process()
pointer declaration int p = nullptr
multiplication int k = n y
pointer dereference int j = p
Recap - Pass by reference (amp)
int main()
int real_n = 10
cout ltlt square(real_n)
cout ltlt real_n
return 0
int square(const int amp real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x2786 10
real_n 10
Pass by reference using Pointers
int main()
int real_n = 10
cout ltlt square(ampreal_n)
cout ltlt real_n
return 0
int square(const int real_n)
return real_n real_n
100
10
Mem Addr Contents
0x2786 10
real_n 10
Mem Addr Contents
0x5110 0x2786
real_n 0x2786
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
-8763948576
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p -532765818
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
10
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt p
cout ltlt pcout ltlt ampx
cout ltlt x
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
Pointers
int p
x = 10
p = ampx
p = 11
cout ltlt pcout ltlt pcout ltlt ampxcout ltlt xcout ltlt ampp
15438 x
Address
0
1
2
Machine Memory
11
int x
17216 p 15438
15438
11
15438
11
17216
Pointers
int main(int argc char argv)
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )(argv + n) ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv + 0 C
argv + 1
argv + 2
argv + 3
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
int main(int argc char argv[])
for(int n = 0 n lt argc ++n)
cout ltlt n ltlt
ltlt (char )argv[n] ltlt endl
Pointers to Pointers
Cfooexe one two three
argc = 4
argv = 0xhellip argv[0] C
argv[1]
argv[2]
argv[3]
f o o e x e
o n e
t w o
t h r e e
0
0
0
0
0 Cfooexe
1 one
2 two
3 three
Memory Stack vs Heap
Stack (last in first out - LIFO)
Space automatically allocated
The place where arguments of a function call are stored
The place where local function data is allocated (eg variables)
The place where a function leaves its result (if any)
Heap
Space must be explicitly allocated
A place for allocating memory that is not part of last-in first-out approach
ie dynamically allocated data structures that survive function calls
Stack vs Heap
int stackArray[100] Allocate 100 ints on the stack
stackArray[n] = 0 Do something with it
int heapArray = new int[100] 100 ints on the heap C++
int heapArray = malloc(100 sizeof(int)) 100 ints on the heap C
heapArray[n] = 0 Or (heapArray + n) = 0 Do something with it C++ and C
delete [] heapArray When youre done C++
free(heapArray) When youre done C
Exercises
Topics covered in ex22 onwards
If time allows look through the remaining
exercises and attempt those that fit best
with your requirements
- C++ Notes TPLO 12-11-2019 Blackbox
- C++ Slides TPLO 12-11-2019 - Copy
-