C++ Review COMPSCI 355 Fall 2016
C++ Review basic I/O command-line arguments dynamic memory allocation pointers and memory leaks random number generation
Balls and Bins How many people must be in a group before it is likely that at least two of them have the same birthday? Many problems in mathematics and computer science can be modeled as Balls and Bins problems. Hashing Load balancing How to distribute k processes among n CPUs. How to assign k visiting students to n professors.
Balls and Bins /* * Estimates probability that if k balls are randomly thrown * into n bins, at least one bin will receive multiple balls. * * Author: Drue Coles */ #include <cstdlib> #include <iostream> #include <ctime> using namespace std; // Simulates tossing k balls into n bins. Returns true if at // least one bin receives multiple balls. bool toss(int k, int n); int main(int argc, char** argv) { bool toss(int k, int n) {
Balls and Bins int main(int argc, char** argv) { if (argc!= 3) { cout << "Usage: " << argv[0] << " [balls] [bins]\n"; return 0; int balls = atoi(argv[1]); int bins = atoi(argv[2]); // Perform the simulation many times const int TRIALS = 1000000; srand(time(0)); int success = 0; for (int i = 0; i < TRIALS; i++) { if (toss(balls, bins)) success++; // Estimate probability as fraction of successful trials. double prob = static_cast<double>(success) / TRIALS; cout << "Probability of a bin with at least 2 balls: " << prob << endl; return 0;
Balls and Bins bool toss(int k, int n) { // bins[i] = true if the i-th bin contains a ball bool* bins = new bool[n]; for (int i = 0; i < n; i++) { Is this necessary? bins[i] = false; // Throw each ball into a random bin. for (int i = 0; i < k; i++) { int j = rand() % n; if (bins[j]) { // j-th bin already contains a ball return true; bins[j] = true; return false; What is the problem here?
Balls and Bins bool toss(int k, int n) { // bins[i] = true if the i-th bin contains a ball bool* bins = new bool[n]; for (int i = 0; i < n; i++) { Is this necessary? bins[i] = false; // Throw each ball into a random bin. for (int i = 0; i < k; i++) { int j = rand() % n; if (bins[j]) { // j-th bin already contains a ball delete bins; return true; bins[j] = true; delete bins; return false; Now what is the problem?
C++ Review arguments vs parameters argument passing value semantics reference semantics
Swapper #include <iostream> using namespace std; void swap(int, int); int main (int argc, char* const argv[]) { int a = 3, b = 5; swap(a, b); cout << a << b << endl; What will happen? return 0; void swap(int x, int y) { int temp = x; x = y; y = temp;
Swapper #include <iostream> using namespace std; void swap(int*, int*); int main (int argc, char* const argv[]) { int a = 3, b = 5; swap(&a, &b); cout << a << b << endl; return 0; void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp;
Swapper #include <iostream> using namespace std; void swap(int&, int&); int main (int argc, char* const argv[]) { int a = 3, b = 5; swap(a, b); cout << a << b << endl; return 0; void swap(int& x, int& y) { int temp = x; x = y; y = temp;
Exercise void f(int, int&); int main() { int x = 3, y = 5; f(x, y); cout << x << " " << y << endl; // Also try: f(y, x), f(x+y, y), f(x, x + y). return 0; void f(int x, int& y) { x *= 2; y += x;
Fibonacci Numbers // Outputs the first 20 fibonacci numbers. // Author: Drue Coles #include <iostream> using namespace std; int main() { const int N = 25; int a[n] = {0, 1; for (int i = 2; i < n; i++) { a[i] = a[i - 1] + a[i - 2]; return 0;
Fibonacci Numbers // Outputs the first 20 fibonacci numbers. // Author: Drue Coles #include <iostream> using namespace std; void set_fib_numbers(int[], int n); void print(const int[], int n); int main() { const int N = 25; int a[n]; set_fib_numbers(a, N); print(a, N); return 0;
Fibonacci Numbers void set_fib_numbers(int a[], int n) { a[0] = 0; a[1] = 1; for (int i = 2; i < n; i++) { a[i] = a[i - 1] + a[i - 2]; void print(const int a[], int n) { for (int i = 0; i < n - 1; i++) { cout << a[i] << endl;
C++ Review implementing classes assert macro destructors const methods prefix vs. postfix increment
String Reverse with Stack /* * Prompts user for a string of alphabetic characters * and then prints it backwards. Non-alphabetic chars * are ignored, and each input character is converted * to uppercase. * * Author: Drue Coles */ #include <iostream> #include <cassert> #include <cctype> using namespace std; // A bounded stack of characters. class Stack {... int main() {...
String Reverse with Stack // A bounded stack of characters. class Stack { private: char* ptr; int top; int size; public: Stack(int); ~Stack(); void push(char); char pop(); bool isempty() const; bool isfull() const; ;
String Reverse with Stack Stack::Stack(int n) { size = n; ptr = new char[size]; top = 0; Stack::~Stack() { delete []ptr; No such thing in Java. Why not? void Stack::push(char c) { assert(!isfull()); ptr[top++] = c;
String Reverse with Stack int main() { const int STACK_SIZE = 100; Stack s(stack_size); cout << "Enter a string: "; char c; cin.get(c); while (c!= '\n') { s.push((char) toupper(c)); cin.get(c); cout << endl; while (!s.isempty()) { // print string backwards cout << s.pop(); cout << endl; return 0;
C++ Review separate compilation header files implementation files object files
Header File // A bounded stack of characters. // Author: Drue Coles class Stack { private: char* ptr; int top; // index into array at next position int size; // maximum size of stack public: // Constructs a stack with a given amount of space. Stack(int); // Releases the dynamically allocated stack space. ~Stack();
Implementation File #include <cassert> #include "stack.h" Stack::Stack(int n) { size = n; ptr = new char[size]; top = 0; g++ -c stack.cpp Stack::~Stack() { delete []ptr; void Stack::push(char c) { assert(!isfull()); ptr[top++] = c;
Client Program /* * Prompts user for string of alphabetic characters and * then prints it backwards. Non-alphabetic chars are * ignored, and each input character is converted to * uppercase. * * Author: Drue Coles */ #include <iostream> #include <cctype> #include "stack.h" using namespace std; int main() {... g++ main.cpp stack.o
C++ Review copy constructor default arguments overloaded assignment operator
Header File class Stack { private: char* ptr; int top; int size; public: Stack(int = 10); Stack(Stack&); Stack& operator=(const Stack&); ~Stack(); void push(char); char pop(); bool isempty() const; bool isfull() const; ;
Implementation File Stack::Stack(int n) { size = n; ptr = new char[size]; top = 0; Stack::Stack(Stack& s) { ptr = new char[s.size]; for (int i = 0; i < s.size; i++) ptr[i] = s.ptr[i]; size = s.size; top = s.top;
Implementation File Stack& Stack::operator=(const Stack& s) { if (this == &s) return *this; delete []ptr; ptr = new char[s.size]; for (int i = 0; i < s.size; i++) ptr[i] = s.ptr[i]; top = s.top; return *this;
Client Program int main() { Stack s(10); s.push('a'); s.push('b'); Stack t(s); t.push('c'); t.push('d'); Stack u; u = t; u.push('e'); u.push('f'); Why not demonstrate assignment operator with: Stack u = t; while (!u.isempty()) cout << u.pop() << endl; return 0;
C++ Review template functions template classes separate compilation
Template Function #include <iostream> int main() { int a = 3, b = 5; double u = 3.7, v = 9.1; swap(a, b); swap(u, v); std::cout << a << " " << b << std::endl; std::cout << u << " " << v << std::endl; return 0;
Template Function #include <iostream> template <typename T> void swap(t& x, T& y); int main() { template <typename T> void swap(t& x, T& y) { T temp = x; x = y; y = temp;
Template Function int main() { int a, b; double u, v; swap(a, b); swap(u, v); void swap(int& x, int& y) { int temp = x; x = y; y = temp; void swap(double& x, double& y) { double temp = x; x = y; y = temp;
Header File template <typename T> class Stack { private: T* ptr; int top; int size; public: Stack(int = 10); Stack(Stack&); Stack& operator=(const Stack&); ~Stack(); void push(t); T pop(); bool isempty() const; bool isfull() const; ;
Implementation File #include <cassert> #include "stack.h" template <typename T> Stack<T>::Stack(int n) { size = n; ptr = new T[size]; top = 0; template <typename T> Stack<T>::Stack(Stack<T>& s) { ptr = new T[s.size]; for (int i = 0; i < s.size; i++) ptr[i] = s.ptr[i]; size = s.size; top = s.top;
Implementation File template <typename T> Stack<T>& Stack<T>::operator=(const Stack<T>& s) { delete []ptr; ptr = new char[s.size]; for (int i = 0; i < s.size; i++) ptr[i] = s.ptr[i]; top = s.top; return *this; template <typename T> Stack<T>::~Stack() { delete []ptr;
Implementation File template <typename T> void Stack<T>::push(T c) { assert(!isfull()); ptr[top++] = c; template <typename T> T Stack<T>::pop() { assert(!isempty()); return ptr[--top]; template <typename T> bool Stack<T>::isEmpty() const { return top == 0;
Client Program Stack<int> s; cout << "Pushing: "; while (!s.isfull()) { int k = rand() % 1000; cout << k << " "; s.push(k); cout << "\n\npopping: "; while (!s.isempty()) cout << s.pop() << " "; cout << endl; Must include stack.cpp, not stack.h... Why? Pushing: 383 886 777 915 793 335 386 492 649 421 Popping: 421 649 492 386 335 793 915 777 886 383 3. Your powers are weak, old man. 2. You weren't on any mercy mission this time. 1. An elegant weapon, for a more civilized age. Stack<const char*> t; t.push("1. An elegant weapon, for a more civilized age."); t.push("2. You weren't on any mercy mission this time."); t.push("3. Your powers are weak, old man."); while (!t.isempty()) cout << t.pop() << endl; return 0;
Separate Compilation? stack.h template <typename T> class Stack { void push(t); stack.cpp template <typename T> class Stack { g++ -c stack.cpp stack.o? template <typename T> void Stack<T>::push(T c) { assert(!isfull()); ptr[top++] = c; main.c #include stack.h gcc main.c stack.o int main() { Stack<int> s; s.push(23);
C++ Review the Standard Template Library stack and vector iterators stream insertion operator operator overloading friend functions
STL Stack stack<int> s; for (int i = 0; i < 10; i++) s.push(i); while (!s.empty()) { cout << s.top() << " "; s.pop(); 9 8 7 6 5 4 3 2 1 0
STL Vector vector<int> v(5); v[0] = 27; v.push_back(56); v.resize(10); v[8] = 355; 27 0 0 0 0 56 0 0 355 0 27 0 0 0 0 56 0 0 355 0 for (int i = 0; i < v.size(); i++) cout << v[i] << " "; cout << endl; vector<int>::iterator iter; for (iter = v.begin(); iter!= v.end(); ++iter) cout << *iter << " ";
STL Vector vector<int> v(5); v[0] = 27; v.push_back(56); v.resize(10); v[8] = 355; v.operator[](0) = 27; v.operator[](8) = 355; for (int i = 0; i < v.size(); i++) cout << v[i] << " "; cout << endl; v.operator[](i) vector<int>::iterator iter; for (iter = v.begin(); iter!= v.end(); ++iter) cout << *iter << " ";
STL Vector class MyClass { private: int x; public: MyClass(int y) { x = y; MyClass() { x = 0; int main () { vector<myclass> w(5); w[0] = MyClass(17); w[3] = MyClass(23); w.resize(8); vector<myclass>::iterator iter; for (iter = w.begin(); iter!= w.end(); ++iter) cout << *iter << " "; cout << endl; return 0; ; friend ostream& operator<<(ostream& out, MyClass& m) { out << m.x; return out; 17 0 0 23 0 0 0 0
C++ Review operator overloading friend functions
Rational #include "rational.h" int main() { Rational r(3, 8); Enter rational number (num den): 5 12 Sum: 19/24 Product: 5/32 3/8 is smaller than 5/12. int x, y; cout << "Enter rational number (num den): "; cin >> x >> y; Rational s(x, y); cout << "Sum: " << r + s << endl; cout << "Product: " << r * s << endl; if (r < s) cout << r << " is smaller than " << s << ".\n"; else cout << s << " is smaller than " << r << ".\n"; return 0;
Header File class Rational { private: int num; int den; void reduce(); // reduces to lowest common terms public: Rational(int=0, int=1); ; // modified assignment operators Rational& operator+=(rational&); Rational& operator-=(rational&); Rational& operator*=(rational&); Rational& operator/=(rational&); // Displays number in standard format (e.g., 2/3, -23/17, 5). friend ostream& operator<<(ostream&, const Rational&); // friend functions for arithmetic operations friend Rational operator+(const Rational&, const Rational&); friend Rational operator-(const Rational&, const Rational&); friend Rational operator*(const Rational&, const Rational&); friend Rational operator/(const Rational&, const Rational&); // friend functions for relational operations friend bool operator==(const Rational&, const Rational&); friend bool operator!=(const Rational&, const Rational&); friend bool operator<(const Rational&, const Rational&); friend bool operator<=(const Rational&, const Rational&); friend bool operator>(const Rational&, const Rational&); friend bool operator>=(const Rational&, const Rational&);
Implementation File Rational::Rational(int a, int b) { assert (a >= 0 && b > 0); num = a; den = b; reduce(); Rational& Rational::operator+=(Rational& r) { *this = *this + r; return *this; Rational operator+(const Rational& r, const Rational& s) { Rational sum; sum.num = r.num * s.den + s.num * r.den; sum.den = r.den * s.den; sum.reduce(); return sum;
Stream Insertion Operator ostream& operator<<(ostream& out, const Rational& r) { if (r.num == 0) { out << r.den; else if (r.den == 1) { out << r.num; else out << r.num << "/" << r.den; return out;