**Discussion 2** 09/01, 09/03 [(back to course webpage)](./mcs360_fall2020.html) # Reference for looking up functions and data structures in C++ Whenever I forget any Standard Library functions or try to learn about a new data structure, I refer to [C++ Reference](https://www.cplusplus.com/reference/). It's a useful website which contains everything that you want to know about C++ functions and data types! # Part 1: Arrays and Vectors ## 1.1: Arrays + An array is a contiguous collection of data. + `int a[200];` declares an array of size 200 in C++. + C++ arrays have fixed size. You cannot append, delete entries. + If you declare an array `int a[200]`, then the entry `a[0]` is exactly `*a`. The `*` operator is a dereference operator which dereferences the pointer `a`. *********************************** * ------------------------------- * * |a[0]|a[1]| | | | | | * * ------------------------------- * * ^ ^ * * | | * * * * a (a+3) * *********************************** + Looking at the above diagram, you can imagine how `*a = a[0]` and `*(a+3) = a[3]`. + C++11 and above does allow dynamic array allocation, so the following code would work: ~~~~~~~~cpp #include int main() { std::cout << "Enter the size of your dynamic array: "; int n; std::cin >> n; int a[n]; for(int i = 0; i < n; i++) { a[i] = i * i * i; } std::cout<<"Our generated array is: "; for(int i = 0; i < n; i++) { std::cout << a[i] << " "; } return 0; } ~~~~~~~~ But even then, arrays are very inconvenient since you cannot change the size of an array. Once you declare it, it sits as a block in the memory until the program execution ends. These limitations are lifted by vectors.
Aside C++ does not support the power operator `**` unlike python. So to compute $a^3$ you need to do $a\cdot a\cdot a$. To compute $a^{100}$, you need to use the function `pow()` in `cmath` header. Eg, ~~~~~~~~cpp #include #include int main() { double pi = 2 * asin(1); // since arcsin(1) = pi/2 std::cout.precision(4); std::cout << std::fixed << pi << std::endl; std::cout << std::scientific << pow(pi,10) << std::endl; return 0; } ~~~~~~~~
## 1.2: Vectors + Vectors are a much better alternative to python lists because they can have variable sizes! + Vectors are included in the `vector.h` header. + You can declare a vector of integers using `std::vector a;`. + To add new entries, use the function `push_back()`, eg `a.push_back(10);`. This is the cousin of `a.append()` in python. + `a.size()` returns the size of the vector. This is the cousin of `len(a)` in python. Here's the sample code we went over in discussion: ~~~~~~~cpp #include #include int main() { std::vector a; for(int i = 0; i < 10; i++) { a.push_back(i*i); } // Print the elements of the vector // Unlike python, there's no convenient function like print(a) to print the whole vector. std::cout << "The array a is:\n"; for(int i = 0; i < a.size(); i++) { std::cout << a[i] << " "; } std::cout << std::endl; return 0; } ~~~~~~~ If you run this code, you'll see the following output: ``` 0 1 4 9 16 25 36 49 64 81 ``` # Part 2: Random Number Generator + A random integer is obtained by the function `rand()` in the `cstdlib` header. ## 2.1: Without seeding Let's take a look at the following code that generates a random number between $0$ and $99$, and try running it a bunch of times in the terminal: ~~~~~~~cpp #include #include int main() { std::cout << "A random number between 0 and 99 (inclusive): " << rand()%100 << std::endl; return 0; } ~~~~~~~ ``` potla@EKR:~/Desktop/mcs360$ g++ -o random random.cpp potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 83 potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 83 potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 83 ``` It seems that no matter how many times you run the code, you get the same output. This is because the random number generator needs what's called a *seed*. Computers cannot generate perfect random numbers, and they run some funky math algorithm (with prime numbers and modular arithmetic) in the background to come up with numbers that **look** random. This is why these generators are called _Pseudo Random Number Generators_. The way the algorithm works is that it has a _starting integer_, and then it does the funky math to pop out random-looking numbers. If the starting point is the same every time, we would end up with the same number. That's why we need to use a different seed every time to get the proper results. ## 2.2: With seeding ~~~~~~~cpp #include #include #include int main() { //std::cout << time(0) << std::endl; std::srand(time(0)); std::cout << "A random number between 0 and 99 (inclusive): " << rand()%100 << std::endl; return 0; } ~~~~~~~ ``` potla@EKR:~/Desktop/mcs360$ g++ -o random random.cpp potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 47 potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 36 potla@EKR:~/Desktop/mcs360$ ./random A random number between 0 and 99 (inclusive): 57 ```
Remarks
  • The time when the code is executed is obtained by the `time(0)` function. It converts the `yyyy-mm-dd-hh-mm-ss` info into an int. There are other interesting methods in the `ctime` library, you can look it up on https://cplusplus.com/reference if you want to. :)
  • Actually, **quantum computers** are able to generate "perfect" random numbers. It's a shame that currently we don't even have a single-qubit perfect quantum computer, but the computers developed in the 1-5 qubit range are very accurate!
# Part 3: Basics of a Class + Classes are made to model real-world objects into programs. Every property of the object is modeled as an attribute, and every function modeled as a method! + If you think of a bank account as a class, then you could think of attributes to be the Account number, Pin, Balance, and the methods to be `deposit()`, `withdraw()` etc. + Every class has a bunch of private members/functions and a bunch of public members/functions. + Private members/functions can only be accessed by other functions inside the class itself (or friend functions which we will see later). + Public members/functions can be accessed by any function that's not in the class. ## The Bubblegum Dispenser This is a homework problem in the lecture notes: > Consider a bubble gum dispenser. The dispenser releases one bubble gum at a time until empty. Filling of the dispenser adds a positive number of bubble gums. Write the ADT and draw a UML class diagram.
> Define a C++ class for a bubble gum dispenser object.The number of bubble gums in the dispenser is private.
> Write an implementation for the class. Write a simple test program to demonstratethat your class is implemented correctly. Let's first think about the UML diagram. Basically, we need to think about the different private and public attributes and methods of the bubblegum dispenser. ****************************** *----------------------------* *| class BubblegumDispenser |* *|--------------------------|* *| + int quantity |* *| - void fill(fill_amt) |* *| - void dispense() |* *| - void printQuantity() |* *----------------------------* ****************************** Now, here's a CPP code along with the tester code that I left for you guys to complete in discussion: ~~~~~~~cpp #include class BubblegumDispenser { int quantity = 0; // number of gums in the dispenser public: void fill(int fill_amt) { // Add fill_amt many gums to the dispenser std::cout << "Adding " << fill_amt << " many gums.\n"; quantity += fill_amt; } void dispense() { // Remove one gum from the dispenser std::cout << "Dispensing a gum.\n"; quantity--; // fix this code so that it doesn't dispense when the dispenser is already empty. } void printQuantity() { // Print how many gums are left std::cout << "Number of gums: " << quantity << std::endl; } }; int main() { BubblegumDispenser B; B.fill(10); B.printQuantity(); for(int i = 0; i < 11; i++){ B.dispense(); B.printQuantity(); } return 0; } ~~~~~~~ Here's the output of the program (that clearly needs to be fixed): ``` Adding 10 many gums. Number of gums: 10 Dispensing a gum. Number of gums: 9 Dispensing a gum. Number of gums: 8 Dispensing a gum. Number of gums: 7 Dispensing a gum. Number of gums: 6 Dispensing a gum. Number of gums: 5 Dispensing a gum. Number of gums: 4 Dispensing a gum. Number of gums: 3 Dispensing a gum. Number of gums: 2 Dispensing a gum. Number of gums: 1 Dispensing a gum. Number of gums: 0 Dispensing a gum. Number of gums: -1 ```
Solution We fix the dispense function using an if statement. ~~~~~~~cpp void dispense() { // Check if the dispenser is empty or not. if(quantity == 0) { std::cout << "Dispenser is empty, no more gums to dispense.\n"; } else { // Remove one gum from the dispenser std::cout << "Dispensing a gum.\n"; quantity--; } } ~~~~~~~