# Chapter 12 - Worked Exercises 1

## Exercise 1 - Vector&#x20;

### Preamble

C++ provides to us in the standard library a `vector` class, which is a dynamically sized array that can grow in size as we add elements to it.&#x20;

In this example we'll learn how to implement our own `vector` class that mimics some of the behaviour of the `std::vector` class.

### Part 1

Create a class `VectorInt` that is like a vector class that stores a collection of `ints`.&#x20;

The class should have a private member variable for a dynamic array of `ints`, call this member variable `values`.

The class should also have two member variables of type `int`:&#x20;

* One called `capacity`, representing the size of the `values` array.&#x20;
* One called `size`, representing the number of elements currently stored by the `VectorInt`.&#x20;

{% hint style="info" %}
Note that `capacity` and `size` serve different roles. A vector may have a capacity of 100, but its size may only be 10, meaning that only 10 of the 100 slots in the array are currently being used. Adding to this vector would add an element at index `10`, then incrementing the size to `11`.&#x20;
{% endhint %}

### Part 2&#x20;

Provide a default constructor that creates a dynamic array for 50 elements.&#x20;

Provide a constructor with one `int` argument for the number of elements in the initial dynamic array.&#x20;

Provide member functions `capacity`, `size` that simply return the capacity and size of the vector.&#x20;

Provide a destructor to ensure that all dynamically allocated memory is cleaned up when the vector is destroyed.&#x20;

### Part 3

Create a member function `push_back` which accepts an integer value, and adds it to the end of the `values` array. The `size` variable should also be updated to account for this.&#x20;

### Part 4

When there is no more room in the `values` array, then a new dynamic array with **twice the capacity** of the old dynamic array is created.&#x20;

The values of the old array are copied into the new dynamic array, then the element is added to the end of it.&#x20;

The `size` and `capacity` variables should be updated accordingly.&#x20;

### Part 5&#x20;

Implement a **copy constructor**, and a suitable overloading of the **assignment operator** to ensure that deep copies of the vector are made when these are invoked.&#x20;

Provide two examples in your `main` function showing when each of these copy methods are invoked.&#x20;

### Part 6&#x20;

Create a `const char*` member variable called `contents_str`.&#x20;

Now create a **conversion operator** that converts the `VectorInt` into a `const char*` type. You will need to use the member variable `contents_str` to store the string (character array) that is to be returned by the function.&#x20;

The conversion operator should return the contents of the `VectorInt` in the following format:

`[ a, b, c, d ... ]`

where a, b, c, d are elements of the `VectorInt`.

This should allow you to pipe a `VectorInt` object to `std::cout`, do this in your main function.

## Exercise 1 - Rational Numbers

In this exercise we will explore why operator overloading is useful. You will first create a class without operator overloading, where the convenience of operator overloading will later become apparent.&#x20;

### Preamble&#x20;

In mathematics, a rational number is a number that can be expressed as a fraction of two integers, a **numerator** and a **denominator**.&#x20;

For example, the numbers 1/2, 2/3, 15/32, 65/4, 16/5 are all rational.&#x20;

### Part 0&#x20;

Create a `Rational` class that will be used to represent rational numbers. The class is composed of two integers representing the numerator and denominator respectively.&#x20;

In each of the subsequent parts below, implement a driver `main` function to test the functionality of your implementation of the `Rational` class.&#x20;

### Part 1&#x20;

Provide a constructor to create a `Rational` object from two `int` parameters corresponding to the numerator and denominator respectively.&#x20;

Since all integers are also rational numbers (as in 2/1 or 17/1), provide a constructor that takes `int` parameter called `whole_number`, and constructs a `Rational` object with a denominator of 1.&#x20;

Provide a default constructor that initialises an object to value 0 (i.e. 0/1).&#x20;

### Part 2&#x20;

Provide member functions `add`, `sub`, `mul` and `div` that takes another `Rational` object as a parameter, and returns a new value of type `Rational`.&#x20;

You will find the following formulas useful for defining your functions:

* Addition: `a/b + c/d = (a * d + b * c) / (b * d)`
* Subtraction: `a/b - c/d = (a * d - b * c) / (b * d)`
* Multiplication: `(a/b) * (c/d) = (a * c) / (b * d)`
* Division: `(a/b) / (c/d) = (a * d) / (c * b)`

Provide member functions `less` and `equals` that takes another `Rational` object as a parameter, and returns a `bool` value.&#x20;

You will find the following formulas useful for defining your functions:

* Less than: `(a/b) < (c/d) means (a * d) < (c * b)`
* Equals to: `(a/b) == (c/d) means (a * d) == (c * b)`

{% hint style="info" %}
Let any sign be carried by the numerator, keeping the denominator positive.
{% endhint %}

### Part 4&#x20;

Overload the increment and decrement operators (both prefix and postfix) such that it increments or decrements the rational number by 1.&#x20;

For decrementing, this would be subtracting the numerator by the denominator. For example, decrementing 1 from 15/8 would result in 7/8.&#x20;

Conversely, incrementing is adding denominator to the numerator.&#x20;

### Part 5&#x20;

Using the member functions you have created in Part 2, overload all the following operators so that they correctly apply to the type `Rational`:&#x20;

* `==`&#x20;
* `<`
* `<=`
* `>`
* `>=`
* `+`
* `-`
* `*`
* `/`

### Detour - Greatest Common Divisor&#x20;

The **greatest common divisor** (GCD) of two number is the largest number that divides them both.

For example, common divisors of 20 and 15 are 1, 3, and 5. Hence, the GCD is 5, as it is the largest of all the divisors.&#x20;

Create a function that returns the GCD of two numbers:

```cpp
int gcd(int x, int y) {
   // your code here
}
```

### Part 6

You may notice that our current `Rational` class does not attempt to simplify its fraction. For example multiplying `Rational(1, 2)` with `Rational(2, 1)` yields `Rational(2, 2)` instead of `Rational(1, 1)`.

Although the answers are semantically the same, this means that doing many operations over may result in seemingly large fractions, and may even lead to overflow.&#x20;

Use the `gcd` function you have created in the previous section to simplify the fraction in the constructor of the `Rational` class.

Show an example in your `main` function that implementing the above step solves the issue mentioned.&#x20;

## Exercise 3 - Freeing Memory&#x20;

For each of the below examples, write appropriate code that would free all memory that was dynamically allocated. If no freeing is required, state so.&#x20;

### Question 1

```cpp
int* a = new int(10);
int b = 5;
```

### Question 2

```cpp
int* a = new int;
int* b = new int;
```

### Question 3

```cpp
int* a = new int[10];
int* b = new int[12];

for (int i = 0; i < 10; i++) {
    a[i] = 4;
}
```

### Question 4

```cpp
int** a = new int*[50];
```

### Question 5

```cpp
int** a = new int*[5];

for (int i = 0; i < 5; i++) {
    a[i] = 0;
}
```

### Question 6

```cpp
int** a = new int*[16];

for (int i = 0; i < 16; i++) {
    a[i] = new int(2);
}
```

### Question 7

```cpp
int* a = 0;
int* b = 0;
int c = 10;
```

### Question 8&#x20;

```cpp
int* a = new int(5);
int* b = a;
int* c = new int(*b);
```

## Exercise 4 - String&#x20;

### Preamble&#x20;

Much like the `VectorInt` class that you have made in Exercise 1, you will now implement a `String` class that behaves similar to the `std::string` class of the standard library.&#x20;

Remember that the point of the exercise is to **not** use any standard libraries, unless explicitly specified.&#x20;

### Part 0&#x20;

Refresh your memory by reviewing the **C-style Character Strings** section of the textbook.

You are allowed and suggested to use the following standard library functions found in the `<string.h>` header in your code:

* `strcpy()` - [documentation](https://www.programiz.com/c-programming/library-function/string.h/strcpy)
* `strlen()` - [documentation](https://www.programiz.com/c-programming/library-function/string.h/strlen)
* `strcat()` - [documentation](https://www.programiz.com/c-programming/library-function/string.h/strcat)

### Part 1&#x20;

Create a `String` class that stores a string as a character array (`char*`) in a member variable called `contents`.&#x20;

Create a constructor that accepts a `const char*` parameter, and copies the contents from said parameter into its `contents` member variable.&#x20;

* The character array for the `contents` member variable should be dynamically allocated. &#x20;
* You will find the functions `strcpy()` and `strlen()` helpful.&#x20;

Create a suitable destructor that frees the memory allocated by `contents`.&#x20;

### Part 2&#x20;

Implement a conversion operator that would convert a `String` object into a `const char*`. This would be simply returning its `contents` member variable.&#x20;

Explain why this allows you to now do the following:

```cpp
String myStr = "Hello World!"
std::cout << myStr << std::endl;  // Prints "Hello World!"
```

### Part 3&#x20;

Overload the addition operator (`operator+`) so that you are able to concatenate two `String` objects together.&#x20;

```cpp
String myStr = "Hello World!";
String myStr2 = " Goodbye!";
String myStr3 = myStr + myStr2;
std::cout << myStr3 << std::endl;  // Prints "Hello World! Goodbye!"
```

Overload the addition operator (`operator+`) so that you are able to concatenate a `String` object with a `const char*` object together.&#x20;

```cpp
String myStr4 = "Good ";
String myStr5 = myStr + " morning!";
std::cout << myStr5 << std::endl;  // Prints "Good morning!"
```

### Part 4&#x20;

Implement a suitable **copy constructor** for the `String` class. Show in your main program an example of an issue that is addressed by the copy constructor that you've implemented.

Implement a suitable **copy assignment operator** for the `String` class. Show in your main program an example of an issue that is addressed by the copy constructor that you've implemented.

### Solution&#x20;

<https://replit.com/@chowder2/AbsoluteTightHexagon#main.cpp>
