C++ Moocs
C++ Moocs
1
• Structure of a program
– See ~zxu2/Public/ACMS40212/C++_basics/basics.cpp
Compilation Stages
– To see how the code looks after pre-processing, type icc –A –E basics.cpp
2
• Aggregates
1. Variables of the same type can be put into arrays or multi-D arrays, e.g., char letters[50], values[50][30][60];
Remark: C has no subscript checking; if you go to the end of an array, C won't warn you.
2. Variables of different types can be grouped into a structure.
typedef struct {
int age; int height;
char surname[30];
} person;
…
person fred; fred.age = 20;
Remark: variables of structure type can not be compared. Do not do:
person fred, jane;
if(fred == jane)
} 3
Pointers
• A variable can be viewed as a specific block of memory in the computer memory which can be accessed by the identifier (the name of
the variable).
– int k; /* the compiler sets aside 4 bytes of memory (on a PC) to hold the value of the integer. It also sets up a symbol table. In that
table it adds the symbol k and the relative address in memory where those 4 bytes were set aside. */
– k = 8; /*at run time when this statement is executed, the value 8 will be placed in that memory location reserved for the storage
of the value of k. */
• With k, there are two associated values. One is the value of the integer, 8, stored. The other is the “value” or address of the memory
location.
• The variable for holding an address is a pointer variable.
int *ptr; /*we also give pointer a type which refers to the type of data stored at the address that we will store in the pointer. “*”
means pointer to */
4
ptr = &k; /* & operator retrieves the address of k */
*ptr = 7; /* dereferencing operator “*” copies 7 to the address pointed to by ptr */
{
printf(“*ptr_a is %d\n”, *ptr_a);
ptr_a++; /*or ptr_a += 1; */ // ptr_a is incremented by the length of an int
// and points to the next integer, a[1], a[2] etc.
}
5
• Using a pointer avoids copies of big structures.
typedef struct {
int age; int
height;
char surname[30];
} person;
int sum_of_ages(person *person1, person *person2)
{
int sum; // a variable local to this function
/* Dereference the pointers, then use the `.' operator to get the fields */ sum = (*person1).age + (*person2).age;
/* or use the notation “->”:
sum = person1->age + person2->age; */
return sum;
}
int main()
{
person fred, jane; int sum;
…
sum = sum_of_ages(&fred, &jane);
}
6
Dynamic Memory Allocation in C/C++
Motivation
/* a[100] vs. *b or *c */
Func(int array_size)
{
double k, a[100], *b, *c;
b = (double *) malloc(array_size * sizeof(double)); /* allocation in C*/
c = new double[array_size]; /* allocation in C++ */
…
}
• The size of the problem often can not be determined at “compile time”.
• Dynamic memory allocation is to allocate memory at “run time”.
• Dynamically allocated memory must be referred to by pointers.
Remark: use debug option to compile code ~zxu2/Public/dyn_mem_alloc.cpp and use debugger to step through the code.
icc –g dyn_mem_alloc.cpp
7
Stack vs Heap
segment
• The size of the text and data segments are known as soon as compilation is completed.
The stack and heap segments grow and shrink during program execution.
8
Memory Allocation/Free Functions in C/C++
C:
• void *malloc(size_t number_of_bytes)
C++:
• “new” operator
-- delete pointer;
-- delete [] pointer; 9
References
• Like a pointer, a reference is an alias for an object (or variable), is usually implemented to hold a machine address of an object (or
variable), and does not impose performance overhead compared to pointers.
1. A reference can be accessed with exactly the same syntax as the name of an object.
3. There is no “null reference”, and we may assume that a reference refers to an object.
10
oid f() // check the code ~zxu2/Public/reference.cpp
int var = 1;
int& r{var}; // r and var now refer to the same int int x = r;// x becomes 1
r = 2;// var becomes 2
oid f1()
int var = 1;
int& r{var}; // r and var now refer to the same int int& r2; // error: initialization
missing
Remark:
11
Example 1
0x3D3B38 2.5
0x3D3B39
12
Example 2
0x3D3B38 0.0
0x3D3B39 -1.0
13
Example 3
• Static array of dynamically allocated vectors Func() /* allocate a contiguous memory which we can use for 20 ×30 matrix */
{
double *matrix[20]; int i, j;
for(i = 0; i < 20; i++)
matrix[i][j] = (double)rand()/RAND_MAX;
14
Example 4
• Dynamic array of dynamically allocated vectors Func() /* allocate a contiguous memory which we can use for 20 ×30 matrix
*/
{
double **matrix; int i, j;
matrix[i][j] = (double)rand()/RAND_MAX;
15
Example 5
Func() /* allocate a contiguous memory which we can use for 20 ×30 matrix */
{
double **matrix; int
i, j;
16
Release Dynamic Memory
Func()
{
int *ptr, *p;
ptr = new int[100]; p = new int; delete[] ptr;
delete p;
17
Functions and passing arguments
1. Pass by value //see ~zxu2/Public/Func_arguments
1. #include<iostream>
2. void foo(int);
When foo() is called, variable y is created, and the value of 5, 6 or 7 is copied into y. Variable
y is then destroyed when foo() ends.
Remark: Use debug option to compile the code and use debugger to step through the code.
icc -g pass_by_val.cpp 18
2. Pass by address (or pointer)
1. #include<iostream>
2. void foo2(int*);
3. using namespace std;
Since a reference to a variable is treated exactly the same as the variable itself,
any changes made to the reference are passed through to the argument . 20
1. #include <iostream>
2. int nFive = 5;
3. int nSix = 6;
4. void SetToSix(int *pTempPtr);
5. using namespace std; 6.
7. int main()
8. {
9. int *pPtr = &nFive;
10. cout << *pPtr;
11.
12. SetToSix(pPtr);
13. cout << *pPtr;
14. return 0;
15. }
16.
17. // pTempPtr copies the value of pPtr! I.e., pTempPtr stores the content of pPtr
18. void SetToSix(int *pTempPtr)
19. {
20. pTempPtr = &nSix;
21.
22. cout << *pTempPtr;
23. }
21
• A string reverser program //~zxu2/Public/wrong_string_reverse.c
#include <stdio.h>
/* WRONG! */
char* make_reverse(char *str)
{
int i, j;
unsigned int len; char
newstr[100]; len =
strlen(str) - 1; j=0;
for (i=len; i>=0; i--)
{ newstr[j] = str[i];
j++;
}
return newstr; /* now return a pointer to this new string */
}
23
Implementing Doubly-Linked Lists
A list element contains the data plus pointers to the next and previous list items.
struct node* next; // that points to the next node in the list
struct node* prev; // that points to the previous node in the list.
};
1. newNode->prev = location->prev;
2. newNode->next = location;
3. location->prev->next=newNode;
4. location->prev = newNode;
25
• Deleting “location” node from a Doubly Linked List
node* temp;
1. temp = location->prev;
2. temp->next =location->next;
3. (temp->next)->prev = temp;
4. free(location);
26
• Special trailer and header nodes and initiating doubly linked list
1. To simplify programming, two special nodes have been added at both ends of the doubly-linked list.
2. Head and tail are dummy nodes, and do not store any data elements.
header
trailer
Initialization:
1. header.next = &trailer;
2. trailer.prev = &header;
27
• Insertion into a Doubly-Linked List from the End
AddLast algorithm – to add a new node as the last of list: addLast( node *T, node *trailer)
trailer->prev->next = trailer;
28
Hash Table
29
C++ Class
• A class is a user-defined type provided to represent a concept in the code of a program. It contains data and function members.
30
// Vector.cpp, here we define interfaces to the data #include “Vector.h”
Vector.::Vector(int s):elem{new double[s]}, sz{s} // constructor: acquire resources
{
for(int I = 0; I < s; I++) elem[I] = 0;
}
double& Vector::operator[](int i)
{
return elem[i];
}
31
// main.cpp. To compile icpc main.cpp Vector.cpp
#include “Vector.h”
#include <iostream>
int main()
{
Vector v(10);
v[4] = 2.0;
std::cout<<“size of vector = ”<<v.size() <<std::endl;
}
Example. Consider to do multiplication of a Matrix by a Vector. However, the multiplication routine cannot be a member of both. Also
we do not want to provide low-level access functions to allow user to both read and write the complete representation of both Matrix and
Vector. To avoid this, we declare the operator* a friend of both. 33
class Matrix;
35
Operator Overloading
Overloadable operators
+ - * / % ^
& | ~ ! , =
+= -= /= %= ^= &=
|= *= <<= >>= [] ()
36
// complex.h //see ~zxu2/Public/complex_class class complex{
private:
double real, image; public:
complex operator+(const complex&); complex&
operator+=(complex); complex& operator=(const
complex&);
complex(double a, double b) { real = a; image = b; };
};
Remark:
A binary operator (e.g. a+b, a-b, a*b) can be defined by either a non-static member function taking one argument or a nonmember
function taking two arguments. For any binary operators @, aa@bb is aa.operator@(bb), or operator@(aa,bb).
A unary operator can be defined by either a non-static member function taking no arguments or a nonmember function taking one
argument. For any prefix unary operator (e.g. –x, &(y)) @, @aa can be interpreted as either aa.operator@() or operator@(aa). For any
post unary operator (e.g. a--) @, aa@ can be interpreted as either aa.operator@(int) or operator@(aa,int).
A non-static member function is a function that is declared in a member specification of a class without a static or friend specifier.
37
• Operators [], (), ->, ++, --, new, delete are special operators.
struct Assoc{
vector<pair<string,int>> vec; // vector of (name, value) pairs int& operator[]
(const string&);
};
int main()
{
Assoc values; string
buf;
while(cin>>buf) ++values[buf];
for(auto x: values.vec) cout<<‘{‘ <<x.first <<‘,’<<x.second <<“}\n”;
}
38
C++ Template
• C++ templates (or parameterized types) enable users to define a family of functions or classes that can operate on different types of
information. See also http://www.cplusplus.com/doc/oldtutorial/templates/
• Templates provides direct support for generic programming.
39
Class template
// declare template
template<typename C> class String{ private:
static const int short_max = 15; int sz;
char *ptr; union{
int space;
C ch[short_max+1];
};
public:
String ();
C& operator [](int n) {return ptr[n]}; String& operator +=(C c);
};
40
// define template
Template<typename C>
:sz{0},ptr{ch}
ch[0]={};
Template<typename C>
String<C>& String<C>::operator+=(C c)
{
// … add c to the end of this string return *this;
42
Stacks
• A stack is a container of objects that are inserted and removed according to the
last- in first-out (LIFO) principle. In the pushdown stacks only two operations
are allowed: push the item into the stack, and pop the item out of the stack.
Remark:
template <class T>
The template <class T> prefix
class stack {
specifies that a template is being
T* v;
declared and that an argument T
T* p;
of type type will be used in the
int sz;
declaration. After its introduction,
T is used exactly like other type
public: names. The scope of T extends to
stack (int s) {v = p = new T[sz = s];} the end of the declaration that
~stack() {delete[] v;}
template <class T> prefixes.
void push (T a) { *p = a; p++;}
T pop() {return *--p;}
int size() const {return p-v;} 43
};
public:
44
C++ STL
• STL consists of the iterator, container, algorithm and function object parts of the standard library.
– Sequence container:
vector<T,A> // a contiguously allocated sequence of Ts list<T,A> //a doubly-linked list of T
forward_list<T,A> // singly-linked list of T
Remark: A template argument is the allocator that the container uses to acquire and release memory
– Associative container:
map<K,V,C,A> // an ordered map from K to V. Implemented as binary tree unordered_map<K,V,H,E,A> // an unordered map from K to V
// implemented as hash tables with linked overflow
Container adaptor:
queue<T,C> //Queue of Ts with push() and pop() stack<T,C> //Stack of Ts with
push() and pop()
– Almost container:
array<T,N> // a fixed-size array N contiguous Ts. string
45
#include <iostream> #include
<vector> using namespace std;
int main()
{ // create a vector to store int
vector<int> vec; int i;
// display the original size of vec
cout << "vector size = " << vec.size() << endl;
// push 5 values into the vector
for(i = 0; i < 5; i++){
vec.push_back(i);
}
// display extended size of vec
cout << "extended vector size = " << vec.size() << endl;
// access 5 values from the vector for(i = 0; i < 5; i++)
{
cout << "value of vec [" << i << "] = " << vec[i] << endl;
}
// use iterator to access the values vector<int>::iterator v
= vec.begin(); while( v != vec.end()) {
cout << "value of v = " << *v << endl; v++;
}
vec.erase(vec.begin()+2); // delete the 3rd element in the vec. return 0;
} // 46
http://www.tutorialspoint.com/cplusplus/cpp_stl_tutorial.htm
STL Iterators
//An iterator is akin to a pointer in that it provides operations for indirect access and for moving to point to a new element. A sequence is
defined by a pair of iterators defining a half-open range [begin:end), i.e., never read from or write to *end.
47
• Operators
– Operator == and != returns whether two iterators represent the same position
• begin() returns an iterator that represents the beginning of the element in the container
• end() returns an iterator that represents the position behind the last element.
• container::iterator{first} of (unordered) maps and multimaps yields the second part of key/value pair.
48
Public/ACMS40212/C++_basics/map_by_hash.cpp. Use intel icc ver14 to compile
include <unordered_map> #include
<iostream> #include <string>
sing namespace std; int main ()
std::unordered_map<std::string,double> mymap = {
{"mom",5.4}, {"dad",6.1}, {"bro",5.9} };
} 49
//Public/ACMS40212/C++_basics/map_by_tree.cpp #include <iostream>
#include <map> #include
<string> using namespace
std;
int main()
{
map<string, string> mascots;
mascots["Illinois"] = "Fighting Illini"; mascots["Indiana"] = "Hoosiers"; mascots["Iowa"]
= "Hawkeyes"; mascots["Michigan"] = "Wolverines";
mascots["Michigan State"] = "Spartans"; mascots["Minnesota"] = "Golden Gophers";
mascots["Northwestern"] = "Wildcats"; mascots["Ohio State"] = "Buckeyes"; mascots["Penn
State"] = "Nittany Lions"; mascots["Purdue"] = "Boilermakers";
mascots["Wisconsin"] = "Badgers";
for (;;)
{
cout << "\nTo look up a Big-10 mascot, enter the name " << "\n of a Big-10 school ('q' to quit): "; string university;
getline(cin, university);
if (university == "q") break;
map<string, string>::iterator it = mascots.find(university);
if (it != mascots.end()) cout << "--> " << mascots[university] << endl; else
cout << university << " is not a Big-10 school " << "(or is misspelled, not capitalized, etc?)" << endl;
}
} 50
• Using template to implement Matrix.
51
Modularity
• One way to design and implement the structured program is to put relevant data type together to form aggregates.
• Clearly define interactions among parts of the program such as functions, user-defined types and class hierarchies.
– See ~zxu2/Public/C++_sample_vec
• Error handling
– Use Exceptions
• ~zxu2/Public/C++_sample_vec
52
Use of Headers
• Use “include guards” to avoid multiple inclusion of same header
#ifndef _CALC_ERROR_H #define
_CALC_ERROR_H
… #endif
• Things to be found in headers
– Include directives and compilation directives
#include <iostream> #ifdef
cplusplus
– Type definitions
struct Point {double x, y;}; class
my_class{};
– Template declarations and definitions
template template <typename T> class QSMatrix {};
– Function declarations
extern int my_mem_alloc(double**,int);
– Macro, Constant definitions
#define VERSION 10
• We need to:
54
References:
55