Lesson # 12. Recursive algorithms

Theory

Sample 1: Executing Recursive Factorial by Hand (without recursion)

int factorial(int n) {
    if (n <= 0) {
        return 1;
    }
    return n * factorial(n - 1);
}
 
int main()
{
    int x = factorial(3);
    std::cout << x;
}

Sample 2: Recursive Factorial

int factorial(int n) {
    // determine if n is less than or equal to 0 or not
    if (n <= 0) {
        // if so, then just answer 1
        return 1;
    }
    //otherwise
    else {
        // compute (n-1)! , call it n_minus1_fact
        int n_minus1_fact = factorial(n - 1);
        // multiply n_minus1_fact \8n
        // the resulting product is the answer
        return  n_minus1_fact* n;
    }
  }
 
int main()
{
    int x = factorial(3);
    std::cout << x;
}

Labs and tasks

Lab 1: Simple recursion
To do: You should calculate the numbers between x and y, which are entered by user. You are given a code how to do it without recursion, just using loop. You should transfer this code to complete the task, using recursion.

Expected output:

Enter x and y, x<y
2 4
Sum = 9

✍ How to do:

  1. Create an empty console application.
  2. Type the following code to complete the task without recursion and test it:
  3. int main()
    {
        int x,y;
        std::cout << "Enter x and y, x<y";
        std::cin >> x;
        std::cin >> y;
        
        int sum = 0;
        for (int i = x; i <= y; i++) {
            sum += i;
        }
        std::cout << "Sum = " << sum;
    }
    
  4. After, comment this code out, using /* ... */. We don't need this code anymore.
  5. Create a function called recursive_sum with two parameters, they are x and y.
  6. int recursive_sum(int x, int y) {
    }
  7. In order not to make an infinite repetition of the recursive function we need to place the condition there, it is called base case:
  8. if (x == y) {
            return x;
        }
  9. The base case will break our recursion.
  10. Then, you should add the main part, the recursion. So, you should invoke the function itself:
  11. return x + recursive_sum(x + 1, y);
  12. Return to the main function and place the code to call the function after x and y initiliazing code:
  13. std::cout << "Sum = " << recursive_sum(x, y);
  14. Run the application and check the output.
Lab 2: Recursive Fibonacci sequence

To do: You should output the n-th number of Fibonacci sequence (n is a positive integer). You should complete the task, using recursion.

Note: Fibonacci sequence:

0 1 2 3 5 8 13 21...
Each specified number is the sum of two preceding numbers of the sequence.

Expected output:

enter a number:
6
6! = 8

✍ How to do:

  1. Create an empty console application.
  2. Create a function called fib with one parameter, which is n - the order of a sequence number ti output.
  3. int fib(int n) {
    }
  4. In order not to make an infinite repetition of the recursive function we need to place the condition there, it is called base case. We have two of them: when n = 0 and when n = 1:
  5. if (n == 1) { 
            return 1;
        }
        else if (n == 0) {
            return 0;
        }
  6. The base case will break our recursion.
  7. After, we should create a code to output the result in the case when n > 1. In that case we should compute the sum of two preceding numbers of the sequence. In recursive meaning it means that we should invoke the same function for n-1 and for n-2 and add the results:
  8.  else if (n > 1) {
            return fib(n - 1) + fib(n - 2);
     
        }
  9. Return to the main function and place the code to input n and call the function:
  10. std::cout << "enter a number: \n";
    int n;    
    std::cin >> n;
    std::cout << n << "! = " << fib(n);
  11. Run the application and check the output.

Video of all the lessons

Lesson # 1. Introduction C++ in Visual Studio

COURSERA_ Object-Oriented Data Structures in C++

  • introduction
  • std library
  • CodeBeauty:
    Целиком

  • variables, data types
    If/else statement, check odd/even number
  • Nested if/else, Determine the type of a triangle
  • Switch/case statement, Make Calculator application
  • Ternary (Conditional) operator
  • while loop, What is infinite loop
  • while loop, How to count digits of a number
  • For loop, How to calculate factorial of a number
  • How to nest loops, How to nest for and do-while loop
  • Caleb Curry Очень хорошее, кратко, емко понятно, хороший английский:
    Целиком

  • 3:27:32 — If Statement Practice
  • Logical and Comparison Operators
  • Switch Statement and Enum
  • Intro to Loops
  • For Loops (How to Calculate Factorial)
  • While Loop and Factorial Calculator
  • Do While Loop
  • Break and Continue
  • Conditional Operator
  • Derek Banas:
    здесь

    Lesson # 2. C++ Methods / Functions. Multi-file layout

    Мальчик:
    здесь

    Caleb Curry Очень хорошее, кратко, емко понятно, хороший английский:

  • Intro to Creating Custom Functions
  • Pow Function
  • Creating Custom Functions
  • Creating Void Functions
  • CodeBeauty:

  • What are functions?
  • What is function parameter/argument (multiple, default)
  • Functions return statement, How to check prime number
  • What is function overloading?
  • What is recursion?
  • What are generic functions and templates?
  • Lesson # 3. (L#3) Arguments by Reference

    Caleb Curry

    Course c++ about the pointers, Swapping:

    Lesson # 5. Single-dimensional arrays. Vectors

    Мое о векторах:

  • здесь
  • мальчик:

  • arrays
  • векторы
  • 2d arrays
  • Derek Banas:

  • Arrays
  • Vectors
  • целиком
  • COURSERA_ Object-Oriented Data Structures in C++

  • Template Types
  • CodeBeauty

    Lesson # 6. Using strings

    Мое занятие

  • здесь
  • Курсы С++ Pointers, Arrays, and Recursion

  • 1 Compare two strings
  • 2 Copy a string
  • 3 incompatible representations
  • 4 Buffer overflow
  • Мальчик:

  • Здесь
  • Derek Banas:

  • Здесь
  • Lesson # 7. Pointer Basics

    Мои занятия:

    COURSERA_ Object-Oriented Data Structures in C++

    Caleb Curry

    CodeBeauty

    Курсы С++ Pointers, Arrays, and Recursion
    1 0 Naive Swap
    1 1 Pointers
    1 2 Corrected Swap
    1 3 Swap with Hardware
    3 1 Compare Two Strings
    3 2 Copy a String
    3 3 Incompatible Representations
    3 4 Buffer overflow

    мальчик:
    здесь
    Derek Banas:
    здесь

    Lesson # 8. Dynamic memory. Arrays of pointers

    Курсы С++ Pointers, Arrays, and Recursion

     
    Culeb Curry

    CodeBeauty

    Lesson # 9. Structures

    Мои занятия:

  • здесь
  •   
    Caleb Curry
    здесь

     
    CodeBeauty
    C++ Structures for beginners (explained in 30 minutes)

    Lesson # 10. C++ classes

    Мое занятие: https://youtu.be/Am-mugz6yAo

    COURSERA_ Object-Oriented Data Structures in C++

    Derek Banas
    здесь

    Caleb Curry
    здесь

    CodeBeauty

    Lesson # 1. Lists

    CodeBeauty

  • introduction to Linked Lists, Arrays vs Linked Lists, Advantages/Disadvantages
  • Derek Banas

    Много «воды»

    Lesson # 8. Dynamic memory. Arrays of pointers.

    Theory

      Function template

    • A template variable is defined by declaring it before the beginning of a class or function:
    • template <typename T>
      int max(T a, T b) {
        if (a > b) { return a; }
           return b;
      }
    • Templated variables are checked at compile time, which allows for errors to be caught before running the program.
    • #include <iostream>
      using namespace std;
       
      template <typename T>
      T max(T a, T b) {
      	if (a > b) { return a; }
      	return b;
      }
      int main()
      {
      	cout << "max(3, 5): " << max(3, 5) << endl; // 5
      	cout << "max('a', 'd'): " << max('a', 'd') << endl; // d
      	cout << "max(\"Hello\", \"World\"): " << max("Hello", "World") << endl; // Hello
      	cout << "max(3, 5, 6): " << max(3, 5, 6) << endl; // error
       
      	system("pause");
      	return 0;
      }
    • A function template defines a family of functions.
    • Function and class templates should be defined only in the header file.
    • lib.cpp

      #include "lib.h"

      lib.h

      template<typename T>
      class My
      {
          My() { }
      T f(T a, T b);
      };
       
      template<typename T>
      T My::f(T a, T b)
      {
        return a + b;
      }
    • A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function.
    • An explicit instantiation definition forces instantiation of the function or member function they refer to. It may appear in the program anywhere after the template definition, and for a given argument-list, is only allowed to appear once in the program, no diagnostic required.
    • template<typename T>
      void f(T s)
      {
          std::cout << s << '\n';
      }
       
      template void f<double>(double); // instantiates f<double>(double)
      template void f<>(char); // instantiates f<char>(char), template argument deduced
      template void f(int); // instantiates f<int>(int), template argument deduced
    • Implicit instantiation: When code refers to a function in context that requires the function definition to exist, and this particular function has not been explicitly instantiated, implicit instantiation occurs. The list of template arguments does not have to be supplied if it can be deduced from context.
    • #include <iostream>
       
      template<typename T>
      void f(T s)
      {
          std::cout << s << '\n';
      }
       
      int main()
      {
          f<double>(1); // instantiates and calls f<double>(double)
          f<>('a'); // instantiates and calls f<char>(char)
          f(7); // instantiates and calls f<int>(int)
          void (*ptr)(std::string) = f; // instantiates f<string>(string)
      }

      1. A pointer to a one-dimensional array in dynamic memory

      int* p = new int[10];
      for (int* q = p; q<p+10; q++)
        *q = 1;
       
      for (int i=0; i<10; i++)
        p[i] = 1;
       
      delete [] p;

      For simple types, you can write delete p (the runtime subsystem knows that we allocated an array), but for classes this is an error.

      Errors related to using of dynamic memory

      Error 1. Accessing a section of dynamic memory that we have already returned using delete

      int* p = new int;
      *p = 777;
      delete p;
      *p = 666;
    • What to do?:
    • int* p = new int;
      *p = 777;
      delete p;
      p = nullptr; // !
      *p = 666;
    • Why it’s not enouph?:
    • int* p = new int;
      int * q = p;delete p;
      p = nullptr; // !
      *q = 666;
    • Error 2. We returned dynamic memory twice using delete
    • int* p = new int;
      *p = 777;
      delete p;delete p;
    • Error 3. Dynamic memory leak
    • int* p = new int[1000];
      *p = 777;// and forgot to delete!
    • Error 3a. Dynamic memory leak in the loop
    • for (int i = 0; i<100000; i++)
      {
        int* p = new int[1000];
        *p = 777;// and forgot to delete!
       
      }
    • Error 3b. Dynamic memory leak in the function.
    • void p()
      {
        int* p = new int[1000];
        *p = 777;// and forgot to delete!
      }
    • The rule. If dynamic memory is allocated in a function, then it must be returned in the same function. There are exceptions.
    • Two-dimensional arrays

    • A two-dimensional array is considered as a one-dimensional array of one-dimensional arrays
    • int a[3][4];
    • Two-dimensional rectangular arrays («matrices») are conveniently modeled using pointer arrays:
    • int ** mat = new int *[rows]; // future matrix of rows of rows

      Each element mat[i] of this array is a pointer, it should be initialized in a loop, assigning it the result new int [cols], where cols is the desired number of columns of the matrix.

    • The reference to the (i, j)-th element of the matrix looks like this: mat[i][j]. To iterate over the matrix, just as in the case of a regular array, you can use pointers.
    • It is necessary to empty (devastate) memory, it should be done in the reverse order: first, the memory for each row is released in the loop: delete [] mat[i]. And then the memory of the array of pointers mat: delete [] mat is released. This procedure should be executed as a function with one argument rows(number of rows).
    • Another example:

    • This is an array of three elements of type int [4]
    • a[i][j] ~ *(a[i] + j) ~ *(*(a + i) + j)

      Printing an array:

      void print(int a[][4], int m, int n)
      {
        for (int i=0; i<m; i++)
        {
          for (int j=0; j<n; j++)
          cout << a[i][j] << " ";
          cout << endl;
        }
      }

      Two-dimentional arrays and dynamic memory

    • In order to pass a two-dimensional array of arbitrary dimension to a function, it should be allocated in dynamic memory:
    • void print(int** a, int m, int n)
      {
        for (int i=0; i<m; i++)
        {
          for (int j=0; j<n; j++)
          cout << a[i][j]; // a[i][j] ~ *(*(a + i) + j)
          cout << endl;
        }
      }
      int main()
      {
      // allocation in memory
        int** p = new int*[3]; // pointer pointing to pointer (3 rows)
        for (int i=0; i<3; i++)
           p[i] = new int[4]; // 4 columns
        print(p,3,4);}
    • After using it in the function, the allocated memory must be returned:
    • int main()
      {
        int** p = new int*[3];
        for (int i=0; i<3; i++)
          p[i] = new int[4];
       
      print(p,3,4); // Нарисовать на доске
      // deallocation of memory:
      for (int i=0; i<3; i++)
        delete [] p[i];
      delete [] p;
      p = nullptr;
      }

      Stepwise two-dimensional dynamic arrays

      int main()
      {
        int** p = new int*[3];
       
        for (int i=0; i<3; i++)
          p[i] = new int[4];
       
        print(p,3,4);
        for (int i=0; i<3; i++)
          delete [] p[i];
        delete [] p;
        p = nullptr;
      }

    Labs and Tasks

    1. One-Dimensional Array In Dynamic Memory

    Lab 1:
    To do: Create a solution with two function templates. One of them inputs the elements of a one-dimensional array of a specified size, the other outputs the elements of a one-dimensional array of a given size. It is possible to create all the code in the main cpp file. Input and output the array elements of double type.

    Note: The signature of the function templates should be as following:

    template <typename T> 
    void inputArr(T* arr, int &size);
     
    template <typename T>
    void printArr(const T* arr, int &size);

    Expected output:

    Lab 1:
    Array[0] 1.1
    Array[1] 2.1
    Array[2] 3.2
    Array[3] 4.1
    Array[4] 5.4
    
    1.1 2.1 3.2 4.1 5.4 
    

    ✍ How to do:

    • To perform the lab, create an empty console application with a name Lesson8. Add file: L8Lab1main.cpp.
    • Include all the necessary libraries.
    • Create int main function that returns 0.
    • Above the main function, add the function template code for entering the elements of an array. The function will have two parameters — a pointer to the array and a reference to a variable that stores the size of the array.
    • template <typename T> 
      void inputArr(T* arr, int &size) { // arr is a pointer to the array of any type
      	for (int i = 0; i < size; i++) {
      		cout << "Array[" << i << "] ";
      		cin >> arr[i]; // dereference of the pointer arr
      	}
      }
      
    • In the main function, initialize the variable that stores the size of the array (the array will have 5 elements), and declare a pointer to a new array of double type:
    •   int size = 5;
        double* myArray = new double[size];
      
    • Call the function:
    • inputArr(myArray, size);
      
    • Above the main function, add the function template code to output the elements of the array:
    • template <typename T>
      void printArr(const T* arr, int &size) {
      	for (int i = 0; i < size; i++) {
      		//cout << arr[i] << " "; // dereference way 1:
      		cout << *(arr + i) << " "; //dereference way 2:
      	}
      }
      
      Use one of two ways to dereference the pointer.
    • Call the function in the main method:
    • printArr(myArray, size);
      
    • Once the dynamic array is allocated in the memory, it must be deallocated. Let's deallocate the array in the main:
    • delete[]myArray;
      myArray = NULL;
      
      After the delete operator, the myArray pointer is allocated to something that doesn't belong to our program. To prevent the array of pointers from pointing to any address, you must assign a NULL value.
    • Run the program.
    Task 1:

    To do: An array of integers (A) is given. Create an array in which the number 0 is inserted instead of the elements, the last digit of which is equal to 0. In this task, you need to use dynamic memory (new / delete). Make a template function to print the array.

    Note 1: Make sure that in the main program, after printing the resulting array, you did not forget to deallocate memory (delete []).

    Note 2: The signature of the function should be as follows:

    void MakeArrayWithZero(int* a, int& size);

    Where a is a given array, and size is a size of the array.

    Note 3: Template function to print the array must be in header file and have the following signature:

    template<typename T>
    void printArray(T const * arr, int size, char delim = ' ') {
      ...
    }

    Expected output:

    Task 1:
    Array before the task is done:
    1 20 30 4 5 
    Result:
    1 0 0 4 5
    

    [Solution and Project name: Lesson_8task1, file name L8Task1main.cpp, L8Task1imp.cpp, L8Task1.h]

    Task 2:

    To do: An integer array is given. Сreate a new array, based on the given one, in which all occurrences of a given number are deleted. The original array does not change. You shouldn't use here any standard function.

    Note 1: First, it is better to calculate the number of elements of the new array, and then create a new array with the specified number of elements. To do this, use a function with the following signature:

    int* delete_all_entries(int* a, int size, int n, int& new_size)

    Note 2: Create template function to print out the array elements. Use the following signature:

    template<typename T>
    void print_array(T const* a, int size, char delim = ' ');

    Expected output:

    Task 2:
    original array:
    1 2 3 2
    number to be deleted:
    2
    new array:
    1 3
    

    [Solution and Project name: Lesson_8task2, file name L8Task2main.cpp, L8Task2imp.cpp, L8Task2.h]

    Two-dimensional arrays

    Lab 2:

    To do: Define the function for creating a matrix of specified dimensions, all elements of which are equal to a given number:
    header file:

    int ** createMatrix(int rows, int cols, int value = 0);

    The default value of 0 for the value parameter should be specified only in the header file. In the cpp file, the header contains three parameters in the usual form:
    implementation file:

    int ** createMatrix(int rows, int cols, int value) {
    }

    The default value indicates that the function can be called with two arguments, then the value of the value parameter will be the number 0.

    Note: To print the matrix you should create one more function with a signature:

    void printMatrix(int ** mat, int rows, int cols);

    Expected output:

    Lab 2:
    matrix 5 by 5:
    0 0 0 0 0
    0 0 0 0 0
    0 0 0 0 0
    0 0 0 0 0
    

    [Solution and Project name: Lesson_8Lab2, file name L8Lab2main.cpp, L8Lab2imp.cpp, L8Lab2.h]

    ✍ How to do:

    1. To perform the lab, create an empty console application with a name Lesson8Lab2.
    2. Include all the necessary libraries and header file.
    3. Since we must create a matrix in the function, let's start with a function code. Open the header file and add the signature of the function:
    4. #pragma once
      
      #ifndef HEADER_H
      #define HEADER_H
      
      int ** createMatrix(int rows, int cols, int value = 0);
      
      #endif
      
    5. Then, open the implementation file and add the function:
    6. // ...
      int ** createMatrix(int rows, int cols, int value) {
        //...
      }
      
    7. First of all, we should allocate the memory for our two-dimensional array (matrix). To do it, add the code into the function:
    8. int** res = new int*[rows];
      for (int i = 0; i < rows; i++)
      	{
      		res[i] = new int[cols];
      		for (int j = 0; j < cols; j++) {
      			res[i][j] = value;
      		}
      	}
      
      In the first line we declare a pointer that points to the addresses of rows which are the pointers themselves pointing to the addresses of columns. So we allocate the memory for the matrix.
      In the line #4 for each row we allocate the memory for the columns. The number of rows and columns we take from the arguments.
    9. The function will return the matrix, so add the code:
    10.   return res;
      } // end of function scope
      
    11. Now, we can turn to the main file and ain function to call this function we've created.
    12. Since our function will return a created matrix, we should create a variable to store that matrix and assign the result of our function to it.
    13. int main() {
        // create a matrix with 4 rows and 5 columns each element equals 0:
        int** matrix = createMatrix(4, 5, 0);
        //...
      }
      
    14. Try to run the program and make sure that there are no errors.
    15. After, we're going to create a function to output the elements of the matrix. There will be three arguments there - to accept the matrix itself and the number of columns and rows. Add the code into the implementation file:
    16. void printMatrix(int ** mat, int rows, int cols) {
      	for (int i = 0; i < rows; i++) {
      		for (int j = 0; j < cols; j++) {
      			cout << mat[i][j] << " ";
      		}
      	cout << endl;
      	}
      }
      
    17. Add the signature of the function into header file. Do it yourself.
    18. Run the program and make sure that there are no errors.
    19. Once a dynamic array was created, we should deallocate the memory when the task with that array is done. Let's create a function to deallocate the memory. Add the code of the function:
    20. void freeMemory(int ** mat, int rows) {
      	for (int i = 0; i < rows; i++) {
      		delete[] mat[i];
      	}
      	delete[] mat;
      	mat = NULL;
      }
      
      Since we need to use the pointers, we should know the number of rows only, it is passed in from the main program as argument.
    21. Add the signature of the function to the header file and call the function in the main source file.
    Task 3:

    To do: Create a function to find the minimum and maximum values of the matrix. To do the task you can use the similar functions from lab # 2 (to create a matrix, to print it out and to deallocate the memory). The elements of the matrix must be randomly generated. The signature of the function to find min and max should be as follows:

    void matrixMinMax(int ** mat, int rows, int cols, int &min, int &max);

    Note: to have randomly generated elements you should include the following library:

    #include <ctime>
    // ...
    srand(time(0));
    //.. inside nested loops:
    array_name[i][j] = 1 + rand() % 10;

    Expected output:

    Task 3:
    matrix 4 by 5:
    5 4 0 7 0
    0 8 0 1 2
    0 5 0 7 0
    4 0 0 9 0
    
    max = 9  min = 0
    

    [Solution and Project name: Lesson_8task3, file name L8Task3main.cpp, L8Task3imp.cpp, L8Task3.h]

    Task 4:

    To do: A square matrix of integer elements is given. Calculate the sum of the elements of its main diagonal. Make sure that in the main program, after the matrix returned by functions is no longer needed, the corresponding memory is freed.

    Expected output:

    Task 4:
    matrix:
    8 3 3 6
    6 4 9 8
    6 1 9 6
    4 5 1 5
    
    sum = 26
    

    [Solution and Project name: Lesson_8task4, file name L8Task4main.cpp, L8Task4imp.cpp, L8Task4.h]

    Lesson # 10. Classes

    Theory

    • Classes are an expanded concept of data structures: like data structures, they can contain data members, but they can also contain functions as members.
    • An object is an instantiation of a class. In terms of variables, a class would be the type, and an object would be the variable.
    • Classes are defined using either keyword class or keyword struct, with the following syntax:
    • class class_name {
        access_specifier_1:
          member1;
        access_specifier_2:
          member2;
        ...
      } object_names;
      

      Where class_name is a valid identifier for the class, object_names is an optional list of names for objects of this class. The body of the declaration can contain members, which can either be data or function declarations, and optionally access specifiers.

    • C++ classes encapsulate data and associated functionality into an object:
    • // C++ class: 
      class Cube {
       public:
        double getVolume();
         // ...
       private:
        double length_;
      };
    • Thus, Classes have the same format as plain data structures, except that they can also include functions and have these new things called access specifiers. An access specifier is one of the following three keywords: private, public or protected. These specifiers modify the access rights for the members that follow them.
    • Encapsulation encloses data and functionality into a single unit (called a class)
    • In C++, data and functionality are separated into two separate protections: public and private.
    • The protection level determines the access that «client code» has to the member data or functionality:

    • Public members can be accessed by client code. So, public members are accessible from anywhere where the object is visible. protected members are accessible from other members of the same class (or from their «friends»), but also from members of their derived classes.
    • Private members cannot be accessed by client code (only used within the class itself). So, private members of a class are accessible only from within other members of the same class (or from their «friends»).
    • Example of header-file code (Cube.h):

      #pragma once
      class Cube {
       public:
         double getVolume();
         double getSurfaceArea();
         void setLength(double length);
       private:
         double length_;
      };

      Example of implementation-file code (Cube.cpp):

      #include "Cube.h"
      double Cube::getVolume() {
        return length_ * length_ * length_;
      }
      double Cube::getSurfaceArea() {
         return 6 * length_ * length_;
      }
      void Cube::setLength (double length) {
        length_ = length;
      }

      Example of main-file code (main.cpp):

      #include "Cube.h"
      int main() {
       Cube c;
       c.setLength(3.48);
       double volume = c.getVolume();
       std::cout << "Volume: " << volume << std::endl;
       return 0;
      }

      Arguments passed by …

        Identical to storage, arguments can be passed to functions in three different ways:

      • Pass by value (default)
      • Pass by pointer (modified with *)
      • Pass by reference (modified with &, acts as an alias)

      Values returned by …

      Similarly, values can be returned all three ways as well:

    • Return by value (default)
    • Return by pointer (modified with *)
    • Return by reference (modified with &, acts as an alias)
    • Class destructor

      • When an instance of a class is cleaned up, the class destructor is the last call in a class’s lifecycle.
      • An automatic default destructor is added to your class if no other destructor is defined.
      • The only action of the automatic default destructor is to call the default destructor of all member objects.
      • An destructor should never be called directly. Instead, it is automatically called when the object’s memory is being reclaimed by the system:
      • If the object is on the stack, when the function returns
      • If the object is on the heap, when delete is used
      • To add custom behavior to the end-of-life of the function, a custom destructor can be defined as:
      • A custom destructor is a member function.
      • The function’s destructor is the name of the class, preceded by a tilde ~.
      • All destructors have zero arguments and no return type.
      • Cube::~Cube(); // Custom destructor

      Labs and tasks

      Lab 1:
      To do: Create a Rectangle class and an object (i.e., a variable) of this class, called rect.
      1) The class should contain four members:
      — two data members of type int (member width and member height) with private access,
      — and two member functions with public access: the functions set_values and area.

      2) Define two member functions: set_values function should set the variables width and height to the values; are function should return width*height.

      3) Create a Custom default constructor to have the initial values for width and height (set them to 5).

      4) Set the width and height values for the rect object and print out the information about this object.

      Expected output:

      Lab 1:
      please, enter width:
      >> 20
      please, enter height:
      >> 2
      rect area: 40
      

      ✍ Algorithm:

      • To do the lab create empty console application with a name Lesson9. Add files: mainLab1.cpp, ImpLab1.cpp, HeaderLab1.h.
      • Include all the needed libraries and files.
      • 1.Create a Rectangle class:

      • The class must be defined inside a header file. So, open the header file and add the code to define the class with two private data members, they are width and height; and two member functions with public access, they are set_values and area.
      • class Rectangle {
        private:
        	int width, height;
        public:
        	void set_values(int, int);
        	int area(void);
        } ;
        
      • Here Rectangle is the class name (i.e., the type).
      • The functions set_values and area have a public access, it means that they can be accessed from inside the main function by simply inserting a dot (.) between object name and member name (e.g. rect.set_values…).
      • width and height members cannot be accessed from outside the class, since they have private access and they can only be referred to from within other members of that same class.
      • 2. Define two member functions:

      • Since members width and height have private access, access to them from outside the class is not allowed. So, we should define a member function to set values for those members within the object: the member function set_values.
      • Let’s create the definition of set_values member function. We’re going to have a member of a class outside the class itself, so, we have to use scope operator (::, two colons). You should create the definition of the function inside the implementation file:
      • void Rectangle::set_values(int x, int y) {
        	width = x;
        	height = y;
        }
        
        The scope operator (::) specifies the class to which the member being defined belongs, granting exactly the same scope properties as if this function definition was directly included within the class definition. For example, the function set_values has access to the variables width and height, which are private members of class Rectangle, and thus only accessible from other members of the class, such as this.
      • The second member function, that is area function, we’re going to have inside the class itself, just to try different ways of definition. So, return to the header file and add the definition inside the class next to int area(void) statement:
      • int area() {return width*height;}
        
        The function is automatically considered an inline member function by the compiler.

        3) Create a Custom default constructor to have the initial values for width and height (set them to 5).

      • Add the declaration of a Custom default constructor inside the public access of the class (header file):
      • public: // you had this code
        	Rectangle(); 
        	void set_values(int, int); // you had this code
        //...
        
      • Open your implementation file to add the definition of that constructor:
      •  Rectangle::Rectangle() {
        	width = 5;
        	height = 5;
        }
        

        4) Set the width and height values for the rect object and print out the information about this object:

      • Open a main file in the editor window. You should create an object (i.e., a variable) of the Rectangle class, called rect. And after this, ask user to input the width and height values. Call the set_values function and output the result:
      • int main() {
        	Rectangle rect;
        	int w, h;
        	cout << "please, enter width:\n";
        	cin >> w;
        	cout << "please, enter height:\n";
        	cin >> h;
        	rect.set_values(w, h);
        	cout << "rect area: " << rect.area() << endl;
        	system("pause");
        	return 0;
        }
        
      • Run the program and check the output.
      Task 1:

      To do: Create a LessonDate class to output the date of a lesson.

      1) The class should contain the following members:
      — three data members of type int with private access, they are day, month and year;
      — and two member functions with public access:
      void setDate(int, int, int); to set the date for the next lesson and
      void getDate(); to print out the date of the lesson.

      2) Create a three argument constructor to have the initial values for date; in the constructor body call the setDate function to set the date.

      3) Inside the main function create an object (i.e., a variable) of this class, called objLesson. Set the values of three parameters — day, month and year. Print out the information about this object.

      Expected output:

      Task 1:
      Lesson date: 11.11.2021
      Please, enter day, then month and year of the next lesson
      28
      12
      2020
      Lesson date: 28.12.2020
      

      [Solution and Project name: Lesson_10task1, file name L10Task1main.cpp, L10Task1imp.cpp, L10Task1.h]

      Lab 2:
      To do: Create a Cube class.
      1) The class should contain four members:
      length_ data member of type double with private access,
      — three member functions with public access: the functions double getVolume(); , double getSurfaceArea(); and void setLength(double length);.

      2) Give the definitions (implementations) of those functions:
      getVolume() function have to calculate a volume of the cube: length_ * length_ * length_;
      getSurfaceArea() function have to calculate a Surface Area of the cube: 6 * length_ * length_;;
      setLength(double length) function have to set the value for the cube length.

      3) Create a Custom default constructor to have the initial values for length_ (set it to 1).

      4) Inside the main cpp file create double cube_on_stack() function to create an object (i.e., a variable) of this class and get volume of it. This object will be in a stack memory. Also, inside the main function create a new cube of length 10 which is going to be in heap memory. Set the values. Print out the information about those objects.

      5) Create a custom destructor to delete an information about the cube.

      Expected output:

      Lab 2:
      Volume of c cube:
      Destructor called for cube with length 2
      Volume of c cube in the heap memory: 27
      Destructor called for cube with length 3
      

      ✍ Algorithm:

      • To do the lab create an empty console application with a name Lesson9Lab2. Create new files: mainLab2.cpp, ImpLab2.cpp, HeaderLab2.h.
      • Include all the needed libraries and files.
      • 1.The class should contain four members:

      • The interface of the class must be inside a header file. So, open the header file and add the code to define the class with one private data member, it is length_ of a cube; and three member functions with public access, they are getVolume(), getSurfaceArea() and setLength(double length).
      • class Cube
        {
        public:
        	double getVolume();
        	double getSurfaceArea();
        	void setLength(double length);
        private:
        	double length_;
        };
        
      • Here Cube is the class name (i.e., the type.
      • The functions getVolume(), getSurfaceArea() and setLength(double length) have a public access, it means that they can be accessed from anywhere where the object is visible.
      • length_ member cannot be accessed from outside the class, since it has a private access and it can only be accesses from within the class itself.
      • 2. Give the definitions (implementations) of the functions:

      • Let’s create the definition of setLength member function. We’re going to have a member of a class outside the class itself, so, we have to use scope operator (::, two colons). You should create the definition of the function inside the implementation cpp file:
      • void Cube::setLength(double length) {
        	length_ = length;
        }
        
        The scope operator (::) specifies the class to which the member being defined belongs, granting exactly the same scope properties as if this function definition was directly included within the class definition. For example, the function setLength has access to the variable length_, which is a private member of the class Cube, and thus only accessible from other members of the class, such as this.
      • The second and th third member functions are getVolume and getSurfaceArea function, we’re going to have them inside the implementation file too:
      • double Cube::getVolume() {
        	return length_ * length_ * length_;
        }
        double Cube::getSurfaceArea() {
        	return 6 * length_ * length_;
        }
        
        The getVolume function will return the volume of that cube, for which this function will be called.
        The getSurfaceArea function will return the surface area of that cube, for which this function will be called.

        3) Create a custom default constructor to have the initial values for length_ (set it to 1).

      • Add the declaration of a custom default constructor inside the public access of the class (header file):
      • public: // you had this code
        	Cube(); 
                //...
        
      • Open your implementation file to add the definition of that constructor:
      • Cube::Cube() {
        	length_ = 1;
        }

        4) Inside the main cpp file create double cube_on_stack() function to create an object (i.e., a variable) of this class and get volume of it:

      • Open a main file in the editor window. Before the main function add the code to create cube_on_stack() which will create the object of Cube class and return the volume of this object:
      • double cube_on_stack() {
        	Cube c;
        	c.setLength(2);
        	return c.getVolume();
        }
        int main() {
         // ...
        }
        
      • Inside the main function ptint out the message and call that function:
      • int main() {
          cout << "Volume of first cube: " << endl;
          cube_on_stack();
        }
        

        Also, inside the main function create a new cube of length 10 which is going to be in heap memory. Set the values. Print out the information about those objects.

      • Then, inside the main function you should create a new cube of length 10 which is going to be in heap memory:
      •   Cube * pcube = new Cube;
          pcube->setLength(3);
          cout << "Volume of c cube in the heap memory: " << pcube->getVolume() << endl;
        
        To have an object to be stored in the heap memory you should use star (*) sign. Such objects or instances to the objects can be used together with arrow operator to access their members.

        5) Create a custom destructor to delete an information about the cube.

      • Open header file to declare a class destructor, which will be called to clean up the instance of the class. Add it right after the class constructor to the public protection level:
      • ~Cube();
        
      • Add the implementation for that destructor inside implementation file:
      • Cube::~Cube(){
        	cout << "Destroyed cube with length " << length_;
        }
        
      • Return to the main file and add the delete keyword to clean up the memory of the pcube object:
      • // ...
        delete pcube;
        
        If the object is on the heap, the destructor is only called when that delete keyword is used, to reclaim that memory that the object was using.
      • Run the program and check the output.
      Task 2:

      To do: Create a Student class to output information about the students.

      1) The class should contain the following members:
      — two data members of type string with private access, they are name and surname, and one data member of type int - age;
      — and two member functions with public access:
      void set_info(string, string, int); to set the information about the student
      and void get_info(void); to print out the information.

      2) Create a three argument constructor to have the initial values for student.

      3) Inside the main cpp file create void student_on_stack() function to create an object (i.e., a variable) of this class and get volume of it. This object will be in a stack memory. Also, inside the main function create a new student with some info about, which is going to be in a heap memory. Print out the information about those objects.

      4) create a custom destructor to delete an information about student.

      Expected output:

      Task 2:
      info about student1: name: Johnsurname: Ivanovage: 20
      Destructor called for Student Ivanov
      info about student2: name: Petersurname: Panage: 17
      Destructor called for Student Pan
      

      [Solution and Project name: Lesson_10task2, file name L10Task2main.cpp, L10Task2imp.cpp, L10Task2.h]

      Task 3:

      To do: Create a BookShop class to store and output an information about the selling books.

      1) The class should contain the following members:
      data members with private access:
      title_ (a title of a book) of type string;
      author_ (an author of a book) of type string;
      _price (a price of a book) of type double;
      _discount (a discount for a price of a book) of type int.
      data members with public access:
      - void getInfo() function to print out the information about the book;
      - void set_info(string title, string author, double price, int discount) function to set the information about the book;
      - double getTotalPrice() function calculate the price of a book considering the discount (price - (price * discount)).

      2) Create a four argument constructor to have the initial values for books.

      3) Create two objects and print out the information about those objects. Print out the info about the price considering the discount.

      Expected output:

      Task 3:
      // book 1 info:
      Dostoevsky Demons 205 roubles, discount 0.05, total price 194,75 roubles
      // book 2 info:
      Kuprin Duel 125 roubles, discount 0.1, total price 112,5 roubles
      

      [Solution and Project name: Lesson_10task3, file name L10Task3main.cpp, L10Task3imp.cpp, L10Task3.h]


      Lab 3:
      To do:

      1) Create a base class called Professor.
      The class should contain the following members:
      - Name_ data member of string type with protected access,
      - Age_ data member of int type with private access,
      - Rating_ data member of int type with protected access,
      - Subjects_ data member of list type with private access,

      Three member functions with public access:
      - void getInfo(); (to output information about a professor),
      - void addSubject(); (to add a new subject to the list),
      - void checkRating(); (to check a rating and output some message).

      2) Create a derived class called ItProfessors. The class should have its own methods called void MoreInfo(); (to output an addition information) and incRating(); (to increase a rating and output some info).

      3) Create a derived class called MathProfessors. The class should have its own methods called void MoreInfo(); (to output an addition information) and incRating(); (to increase a rating and output some info) .

      4) Create an object of the base class inside the main function. Call all existing methods of the class for that object.

      5) Create object of the derived classees inside the main function. Call all existing methods of the class.

      Expected output:

      Lab 3:
      name = Ivanov, age =56, subjects = Math
      name = Johnson, age =50, subjects = Basics_of_programming
      name = Peterson, age =50, subjects = geometry
      Ivanov is good in programming
      name = Petrov, age =45, subjects =
      IT area professor Johnson's rating was increased and now it is 4
      IT area professor Johnson's rating was increased and now it is 5
      IT area professor Johnson's rating was increased and now it is 6
      Johnson has good rating
      Ivanov has no enouph good rating
      

      ✍ Algorithm:

      • To complete the task you should create a L10lab3.cpp file only. All code should be inside one file.
      • Include all the needed libraries:
      • #include
        #include<string>
        #include<list>
        #include <assert.h>
        using namespace std;
        

        Create a base class:

        class Professor {
          private:
        	// ...
          protected:
        	// ...
          public:
                // ...
        };
        
      • Data members should be declared inside the private area:
      •         int Age_;
        	list Subjects_;
        
      • Since the Name_ and Rating_ members must be accessible from the derived class, we should declare them inside the protected area:
      •  
               string Name_;
               int Rating_;
        
      • Now we're going to create a constructor with three arguments. It should be placed inside the public area. Check the values of passed parameters using assert statements:
      • Professor(string name, int age, int count) :
        		Name_(name), Age_(age), Rating_(count)
        	{
        		assert(name != "");
        		assert(age >= 20);
        		assert(age >=0);
        	}
        
      • Let's create a getInfo() method to output all the information. To output the list we're going to use a for : loop, iterating over the elements of the list. The method should be inside the public area:
      • void getInfo() {
        	cout << "name = " << Name_;
        	cout << ", age =" << Age_;
                cout << ", subjects = ";
        	for (string subj : Subjects_) {
        		cout << subj << " ";
        	}
                cout << endl;
        }
        
      • We're going to create a member function to add a new value to the list of subjects. In order to do it we need to use push_back() method:
      •            void addSubject(string subject) {
        			Subjects_.push_back(subject);
        		}
        

        Create a derived class:

      • After the closing curly brace of the base class, we're going to add the code of a derived class to store information about IT professors. Let's declare the class:
      • class ItProfessor:public Professor {
        public:
           // ...
        };
        
      • This class inherits all the members of the base Professor class. But we need to have public default constructor to have those members accessible outside of this class. Let's add the code of constructor in the public area:
      • ItProfessor(string name, int age, int count):Professor (name, age, count){
        	}
        
      • The derived class can have its own specific member. Let's add it in the public area as well:
      • void moreInfo(){
        	cout <" is good in programming" << endl;;
        }
        
      • We're going to create one more derived class with a name MathProfessor:
      • class MathProfessor:public Professor {
        public:
          // ...
        };
        
      • We need to have public default constructor to have the members from the base class accessible outside of this class:
      • MathProfessor(string name, int age, int count):Professor (name, age, count){
        }
        
      • Let's create the objects of these classes inside the main function:
      • ItProfessor IvProfessor("Ivanov", 56,5);
        ItProfessor JohnProfessor("Johnson", 50, 5);
        MathProfessor PeterProfessor("Peterson", 50, 5);
        
      • We are able to evoke all of those methods which were implemented within the base class:
      • 	IvProfessor.addSubject("Math");
        	IvProfessor.getInfo();
        	JohnProfessor.addSubject("Basics_of_programming");
        	JohnProfessor.getInfo();
        	PeterProfessor.addSubject("geometry");
        	PeterProfessor.getInfo();
        	IvProfessor.moreInfo();
        
      • Now, let's create an object of the base class:
      •          Professor pr("Petrov", 45, 6);
                 pr.getInfo();
        	// pr.moreInfo(); error! is not available for the base class
        
      • Both of the derived classes should have a method to increase a rating. The names of the methods should be the same, but their implementations must be different. We can call it Polymorphism. Let's add the following method to ItProfessor class:
      • void incRating() {
        	cout << "IT area professor ";
        	Rating_++;
        	cout << Name_ << "'s rating was increased and now it is " << Rating_ << endl;
        }
        
      • The same method for MathProfessor class will be a bit different:
      • void incRating() {
        	cout << " Math area professor ";
        	Rating_++;
        	cout << Name_ << "' rating is " << Rating_ << endl;
        	}
        
      • Now, let's add a method to check the rating. Since the method must be accessible in the derived classes, it should be defined inside the base class - Professor:
      • void checkRating() {
        	if (Rating_ < 3) {
        		cout << Name_<< " has no enouph good rating" << endl;
        	}
        	else {
        		cout << Name_ << " has good rating" << endl;
        		}
        	}
        
      • Now, let's increase the rating of the object by calling the incRating() method:
      • JohnProfessor.incRating();
        JohnProfessor.incRating();
        JohnProfessor.incRating();
        
      • In order to call the checkRating() method we should use the pointers. Inside the main function we're going to assign address of the object of the derived class to a pointer of the base class:
      • Professor *p1 = &JohnProfessor;
        Professor *p2 = &IvProfessor;
        
      • Now, we can call the method to check the rating:
      • p1->checkRating();
        p2->checkRating();
        
      • Run the program.
      Task 4:
      1) Create a base class called Animals.
      The class should contain the following data members:
      - Name_ data member of string type with protected access,
      - Class_ data member of int type with private access (class of vertebrate animal),
      - Countries_ data member of List type with private access (countries of residence),
      - Population_ data member of int type with private access;
      The class should contain the following member functions with public access:
      - void getInfo(); (to output information about an animal),
      - void addCountry(); (to add a new country to the list and output new list),
      - list getAnimalsCountry(); (to return the list of animals by the specified country) .
      2) Create a derived class called AfricanAnimals. Class inherits all the members of Animals class. The class should have its own method called void MoreInfo(); (to output an addition information about African animals).

      3) Create an object of the base class inside the main function. Call all existing methods of the class for that object.

      4) Create an object of the derived class inside the main function. Call all existing methods of the class.

      Note: Create a header file for classes.

      Expected output:

      Task 4:
      name = polar_bear
      сlass = mammal
      population =  20000
      countries = Russia USA Canada
      what country to add? Greenland
      new info about countries = Russia USA Canada Greenland
      name = elephant
      сlass = mammal
      population =  20000
      countries = Africa India
      more info about African animals: The fauna of Africa varies greatly depending on the climatic zone.
      
      the animals from which country? USA
      polar_bear
      

      [Solution and Project name: file names L10Task4main.cpp, L10Task4.h]

    Lesson # 11. Lists

    Theory

    Forward_list or singly-linked lists


      Sequence

    • Elements in sequence containers are ordered in a strict linear sequence. Individual elements are accessed by their position in this sequence.
    • Linked list

    • Each element keeps information on how to locate the next element, allowing constant time insert and erase operations after a specific element (even of entire ranges), but no direct random access.
    • How to create?


      List node class:

      template <typename T>
      struct node
      {
        T data;
        node<T>* next;
        node(T data, node<T>* next)
        {
          this->data = data;
          this->next = next;
        }
      };
      Creating a singly-linked list

      Пустой список:

      node<int>* p = null;

      Adding an item to the top of the list:

      p = new node<int>(5,p);
    • the new operation allocates dynamic memory to a single node
    • after allocating dynamic memory, the constructor is called with the specified parameters
    • Example:

      p = new node<int>(3,p);

      Function templates with lists

      Example add_first function template:

      template <typename T>
      void add_first(T data, node<T>*& p)
      {
        p = new node<T>(data,p);
      }
      int main()
      {
        node<int>* p = nullptr;
        add_first(5,p); // two stages of compiling a function template
        add_first(3,p);
      }

      Creating and Printing a singly-linked (forward) list:

      template <typename T>
      void print(node<T>* p)
      {
        while (p)
        {
          cout << p-> data;
          p = p->next;
        }
      }
      int main()
      {
        node<int>* p = nullptr;
        add_first(5,p);
        add_first(3,p);
        print(p);
      }

      Freeing the memory occupied by a singly linked list

      template <typename T>
      void free(node<T>* p)
      {
        while (p)
        {
          auto p1 = p;
          p = p->next;
          delete p1;
        }
      }
      int main()
      {
        node<int>* p = nullptr;
        add_first(5,p);
        add_first(3,p);
        print(p);
        //free(p);
        //p = nullptr;
      }

      Complicated:

      Construct forward_list object
      // forward_list constructors
      #include <iostream>
      #include <forward_list>
       
      int main ()
      {
       
        std::forward_list<int> first;                      // (1) default: empty
        std::forward_list<int> second (3,77);              // (2) fill: 3 seventy-sevens
        std::forward_list<int> third (second.begin(), second.end()); // (3) range initialization
        std::forward_list<int> fourth (third);            // (4) copy constructor
        std::forward_list<int> fifth (std::move(fourth));  // (5) move ctor. (fourth wasted)
        std::forward_list<int> sixth = {3, 52, 25, 90};    // (6) initializer_list constructor
       
        std::cout << "first:" ; for (int& x: first)  std::cout << " " << x; std::cout << '\n';
        std::cout << "second:"; for (int& x: second) std::cout << " " << x; std::cout << '\n';
        std::cout << "third:";  for (int& x: third)  std::cout << " " << x; std::cout << '\n';
        std::cout << "fourth:"; for (int& x: fourth) std::cout << " " << x; std::cout << '\n';
        std::cout << "fifth:";  for (int& x: fifth)  std::cout << " " << x; std::cout << '\n';
        std::cout << "sixth:";  for (int& x: sixth)  std::cout << " " << x; std::cout << '\n';
       
        return 0;
      }

      Expected output:

      first:
      second: 77 77 77
      third: 77 77 77
      fourth:
      fifth: 77 77 77
      sixth: 3 52 25 90

      (1) — default — Constructs an empty container, with no elements.
      (2) — fill constructor — Constructs a container with n elements. Each element is a copy of val (if provided).
      (3) — range constructor — Constructs a container with as many elements as the range [first,last), with each element emplace-constructed from its corresponding element in that range, in the same order.
      (4) — copy constructor (and copying with allocator) — Constructs a container with a copy of each of the elements in fwdlst, in the same order.
      (5) — move constructor (and moving with allocator) — Constructs a container that acquires the elements of fwdlst. If alloc is specified and is different from fwdlst‘s allocator, the elements are moved. Otherwise, no elements are constructed (their ownership is directly transferred). fwdlst is left in an unspecified but valid state.
      (6) — initializer list constructor — Constructs a container with a copy of each of the elements in il, in the same order.

    Forward_list::assign

    Syntax:
    range (1)

    template 
    void assign (InputIterator first, InputIterator last);

    fill (2)

    void assign (size_type n, const value_type& val);

    initializer list (3)

    void assign (initializer_list il);
  • In the range version (1), the new contents are elements constructed from each of the elements in the range between first and last, in the same order.
  • In the fill version (2), the new contents are n elements, each initialized to a copy of val.
  • In the initializer list version (3), the new contents are copies of the values passed as initializer list, in the same order.
  • Any elements held in the container before the call are destroyed and replaced by newly constructed elements (no assignments of elements take place).
    Parameters:
    first, last
    Input iterators to the initial and final positions in a sequence. The range used is [first,last), which includes all the elements between first and last, including the element pointed by first but not the element pointed by last.
    The function template argument InputIterator shall be an input iterator type that points to elements of a type from which value_type objects can be constructed.
    n
    New size for the container.
    Member type size_type is an unsigned integral type.
    val
    Value to fill the container with. Each of the n elements in the container will be initialized to a copy of this value.
    Member type value_type is the type of the elements in the container, defined in forward_list as an alias of its first template parameter (T).
    il
    An initializer_list object. The compiler will automatically construct such objects from initializer list declarators. Member type value_type is the type of the elements in the container, defined in forward_list as an alias of its first template parameter (T).
    Example:

    #include <iostream>
    #include <forward_list>
     
    int main ()
    {
      std::forward_list<int> first;
      std::forward_list<int> second;
     
      first.assign (4,15);                           // 15 15 15 15
     
      second.assign (first.begin(),first.end());     // 15 15 15 15
     
      first.assign ( {77, 2, 16} );                  // 77 2 16
     
      std::cout << "first contains: ";
      for (int& x : first) std::cout << ' ' << x;
      std::cout << '\n';
     
      std::cout << "second contains: ";
      for (int& x : second) std::cout << ' ' << x;
      std::cout << '\n';
     
      return 0;
    }

    Output:

    first contains: 77 2 16
    second contains: 15 15 15 15
    Assignment operator = with forward_list

    Syntax:
    copy (1)

    forward_list& operator= (const forward_list& fwdlst);

    move (2)

    forward_list& operator= (forward_list&& fwdlst);

    initializer list(3)

    forward_list& operator= (initializer_list il);

    Assigns new contents to the container, replacing its current contents.

  • The copy assignment (1) copies all the elements from fwdlst into the container (with fwdlst preserving its contents).
  • The move assignment (2) moves the elements of fwdlst into the container (x is left in an unspecified but valid state).
  • The initializer list assignment (3) copies the elements of il into the container.
  • The container preserves its current allocator, except if the allocator traits indicate fwdlst’s allocator should propagate. This allocator is used (through its traits) to allocate or deallocate if there are changes in storage requirements, and to construct or destroy elements, if needed.
    Parameters:
    fwdlst
    A forward_list object of the same type (i.e., with the same template parameters, T and Alloc).
    il
    An initializer_list object. The compiler will automatically construct such objects from initializer list declarators. Member type value_type is the type of the elements in the container, defined in forward_list as an alias of its first template parameter (T).
    Example:

    #include <iostream>
    #include <forward_list>
     
    template<class Container>
    Container by_two (const Container& x) {
      Container temp(x); 
      for (auto& x:temp) 
          x*=2;
      return temp;
    }
     
    int main ()
    {
      std::forward_list<int> first (4);      // 4 ints
      std::forward_list<int> second (3,5);   // 3 ints with value 5
     
      first = second;                        // copy assignment
      second = by_two(first);                // move assignment
     
      std::cout << "first: ";
      for (int& x : first) std::cout << ' ' << x;
      std::cout << '\n';
     
      std::cout << "second: ";
      for (int& x : second) std::cout << ' ' << x;
      std::cout << '\n';
     
      return 0;
    }

    In the first assignment, second is an lvalue: the copy assignment function is called.
    In the second assignment, the value returned by by_two(first) is an rvalue: the move assignment function is called.
    Output:

    first: 5 5 5
    second: 10 10 10
    resize () function
    void resize (size_type n);
    void resize (size_type n, const value_type& val);

    Resizes the container to contain n elements.
    If n is smaller than the current number of elements in the container, the content is trimmed to contain only its first n elements, removing those beyonf (and destroying them).
    If n is greater than the current number of elements in the container, the content is expanded by inserting at the end as many elements as needed to reach a size of n elements. If val is specified, the new elements are initialized as copies of val, otherwise, they are value-initialized.
    Example

    // resizing forward_list
    #include <iostream>
    #include <forward_list>
     
    int main ()
    {
      std::forward_list<int> mylist = {10, 20, 30, 40, 50};
                                    // 10 20 30 40 50
      mylist.resize(3);             // 10 20 30
      mylist.resize(5,100);         // 10 20 30 100 100
     
      std::cout << "mylist contains:";
      for (int& x: mylist) std::cout << ' ' << x;
      std::cout << '\n';
     
      return 0;
    }
    mylist contains: 10 20 30 100 100
    insert_after function

    Example

    // forward_list::insert_after
    #include <iostream>
    #include <array>
    #include <forward_list>
     
    int main ()
    {
      std::array<int,3> myarray = { 11, 22, 33 };
      std::forward_list<int> mylist;
      std::forward_list<int>::iterator it;
     
      it = mylist.insert_after ( mylist.before_begin(), 10 );          // 10
                                                                       //  ^  <- it
      it = mylist.insert_after ( it, 2, 20 );                          // 10 20 20
                                                                       //        ^
      it = mylist.insert_after ( it, myarray.begin(), myarray.end() ); // 10 20 20 11 22 33
                                                                       //                 ^
      it = mylist.begin();                                             //  ^
      it = mylist.insert_after ( it, {1,2,3} );                        // 10 1 2 3 20 20 11 22 33
                                                                       //        ^
     
      std::cout << "mylist contains:";
      for (int& x: mylist) std::cout << ' ' << x;
      std::cout << '\n';
      return 0;
    }

    Output:

    mylist contains: 10 1 2 3 20 20 11 22 33

    Doubly linked lists

    • Lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions.
    • template < class T, class Alloc = allocator > class list;
    • List containers are implemented as doubly-linked lists.
    • Doubly linked lists can store each of the elements they contain in different and unrelated storage locations. The ordering is kept internally by the association to each element of a link to the element preceding it and a link to the element following it.
    • Doubly linked list keeps two links per element: one pointing to the next element and one to the preceding one, allowing efficient iteration in both directions, but consuming additional storage per element and with a slight higher time overhead inserting and removing elements.
    • Compared to other base standard sequence containers (array, vector and deque), forward_list perform generally better in inserting, extracting and moving elements in any position within the container, and therefore also in algorithms that make intensive use of these, like sorting algorithms.

    * Information has taken from: http://www.cplusplus.com/reference/forward_list/forward_list/.

    Labs and tasks

    Lab 1: Creating Linked Lists
    To do: Create a linked lists with three elements (nodes) named root, first and second. Create a function to print the elements of the list.

    Expected output:

    Lab 0
    1 2 3
    

    ✍ How to do:

    1. Create an empty console application. Add the source file and open its code. Include all the necessary libraries and main function.
    2. First of all, let’s create a linkled list. It can be done as a structure above the main function:
    3. struct LinkedList {
      	int data;
      	LinkedList *next;
      };
      
      data is to store a value of the element, and *next is a pointer to point at the memory address of the next list element.
    4. In the main function, three linked lists must be declared:
    5. LinkedList *root, *second, *third;
      
      root = new LinkedList;
      second = new LinkedList;
      third = new LinkedList;
      
      
    6. After we’ve declared lists, let’s assign the values:
    7. root->data = 1;
      root->next = second;
      
      second->data = 2;
      second->next = third;
      
      third->data = 3;
      third ->next = NULL;
      
      data is a value of the element, while next is a stored address to the next element.

    8. Now, let’s create a function to print out the values of the list. It will have an argument — a pointer to the root element. Add the following code above the main function:
    9. void printLinkedList(LinkedList*root) {
      	while (root)
      	{
      		printf("%d ", root->data);
      		root = root->next;
      	}
      }
      
      We use the while loop to iterate over the list’s nodes. Each iteration we assign the address of the next element to the root. The value of the next of the last element equals to 0 (NULL), thus the while loop will stop.
    10. Call this function inside the main function:
    11. printLinkedList(root);
      
    12. Run the application and check the output.
    Lab 2: Circular lists:
    To do: Create a circular list with three nodes. Assign values for nodes and print them out.

    Expected output:

    List contains the following nodes:
    1 2 3
    

    ✍ How to do:

    1. Create an empty console application. Add the source file and open its code. Include all the necessary libraries and main function.
    2. First of all, let’s create a structure which represents a node. It can be done above the main function:
    3. struct Node
      {
      	int data;
      	struct Node *next;
      };
      
    4. Now, we’re going to сreate a function to add the first node to the list. This means the list is empty. The function will take two arguments: an address of node to create and the data to store it in node being created. Add the signature of the function above the main:
    5. struct Node *addToEmpty(struct Node *last, int data) 
      {
      	// ...
      };
      
    6. Inside this function it is better to check if the list is really empty. If it is not, we should return the address of the created node to work them inside another function.
    7. if (last != NULL) return last;
      
    8. Then, we need to allocate a dynamic memory for a new node. Let’s call this node temp:
    9. struct Node * temp = new Node;
      
    10. Now, we must assign data value and address value to the node. We have to do it to make the list circular:
    11. temp->data = data; // we assign passed data to the node
      last = temp; // since we have no anything inside list, so last node will be the only one
      last->next = last; // this line makes link circular; the node actually points to itself (because the only one)
      return last;
      
    12. Now, we’re going to сreate a function to add the node to the list, which is not empty. The function will take two arguments: an address of node to create and the data to store it in node being created. Add the signature of the function above the main:
    13. struct Node *addEnd(struct Node *last, int data)
      {
        // ...
      }
      
    14. Inside this function it is better to check if the list is empty. If it is, we should return the calling of addToEmpty function:
    15. if (last == NULL) 
      		return addToEmpty(last,data);
      
    16. If the function is not empty, we need to allocate a dynamic memory for a new node:
    17. struct Node * temp = new Node; 
      
    18. After, we must assign data value and address value to the node. We have to do it to make the list circular:
    19. temp->data = data;
      temp->next = last->next; // the address of the previous node is assigned 
      last->next = temp; // assign the address of the current node to the previous node
      last = temp;
      return last;
      
    20. Now we’re going to create a function to traverse the list. It will have single argument — a pointer to the list to be traversed. Add the signeture begore main:
    21. void traverse(struct Node *first)
      {
        //...
      }
      
    22. Inside the function we should create a pointer to the list:
    23. struct Node *tmp = first;
      
    24. After, we’re going to loop over the list nodes and print them out:
    25. if (first != NULL) {
      		do
      		{
      			cout << tmp->data << " ";
      			tmp = tmp->next; // move to the next node
      		} while (tmp != first);
      	}
      
    26. Now, we can turn to the main function and create the future list. The NULL must be assigned to it (it is empty).
    27. struct Node *last = NULL;
      
    28. To add the first node we should call the addToEmpty() function, since it is empty. To create the second and third nodes we should call the addEnd() function. The values must be 1, 2 and 3:
    29. last = addToEmpty(last, 1); // data = 1
      last = addEnd(last, 2);
      last = addEnd(last, 3);
      
    30. At last, we must call the function to print the nodes out:
    31. cout << "List contains the following nodes:" << endl;
      traverse(last->next);
      
    32. Run the application and check the output.
    Lab 3: Forward lists: Using list methods
    To do: Create a solution to test the methods of a list type. Create three lists and use the following methods with them:

    1. insert_after
    2. emplace_after
    3. reverse
    4. splice
    5. sort
    6. merge
    7. remove
    8. remove_if

    Expected output:

    Lab 3
    list 1: 5 4 3 2
     list 2: 1 4 7 6
     list 3: 9 8 7
     1. insert_after method, list1 (insert 8 number in the position 2):
    5 8 4 3 2
     2. emplace_after method, list3 (add 5 to list3 in the position 2):
    9 5 8 7
     3. reversed method(list1):
    2 3 4 8 5
     4. splice method (list1 with list3):
     after splice, list1:
    2 9 5 8 7 3 4 8 5
     after splice, list 3:
    
     5. sort method, list 1:
    2 3 4 5 5 7 8 8 9
     sort method, list 2:
    1 4 6 7
     6. merged method (list1 and list2):
    1 2 3 4 4 5 5 6 7 7 8 8 9
     7. remove method, list1 (2 is removed):
    1 3 4 4 5 5 6 7 7 8 8 9
     8. remove_if method, list1 (numbers>4 are removed):
    1 3 4 4
    

    ✍ How to do:

  • To perform the lab, create an empty console application with a name Lesson12. Add file: L12Lab3main.cpp.
  • Include all the necessary libraries.
  • Create int main function that returns 0.
  • In the main function declare three lists, initialize them with values and print them out to the console:
  • #include <forward_list> 
    //...
    forward_list<int> list1 = { 5,4,3,2 };
    forward_list<int> list2 = { 1,4,7,6 };
    forward_list<int> list3 = { 9,8,7 };
    cout << "\n list 1: ";
    for (auto &elem : list1)
      cout << elem << " ";
    cout << "\n list 2: ";
    for (auto &elem : list2)
      cout << elem << " ";
    cout << "\n list 3: ";
    for (auto &elem : list3)
      cout << elem << " ";
    

    Test the following functions and consider results:

    1. insert_after method
    2. Insert 8 into 2 position of list1:

      cout << "\n 1. insert_after function, list1 (insert 8 number in the position 2):" << endl;
      list1.insert_after(list1.begin(), 8);
      for (auto &elem : list1)
      	cout << elem << " ";
      
    3. emplace_after
    4. Insert 5 into 2 position of list3:

      cout << "\n 2. emplace_after function, list3 (add 5 to list3 in the position 2):" << endl;
      list3.emplace_after(list3.begin(), 5);
      for (auto &elem : list3)
      	cout << elem << " ";
      
    5. reverse
    6. Reverse list1 by yourself and output the result.

    7. splice_after:
    8. You should splice list3 from the position 2 of list2

      list1.splice_after(list1.begin(), list3);
      cout << "\n 4. splice function (list1 with list3):" << endl;
      cout << "\n after splice, list1:" << endl;
      for (auto &elem : list1)
        cout << elem << " "; 
      cout << "\n after splice, list 3:" << endl;
      for (auto &elem : list3)
        cout  << elem << " "; //must become empty
      
    9. sort
    10. Sort list1 and list2 by yourself and output the results.

    11. merge:
    12. Merge list1 and list2. Note that lists must be sorted:

      list1.merge(list2);
      cout << "\n 6. merged function (list1 and list2):" << endl;
      for (auto &elem : list1)
         cout << elem << " "; 
      
    13. remove
    14. Remove 2 from the list1:

      list1.remove(2);
      cout << "\n 7. remove function, list1 (2 is removed):" << endl;
      for (auto &elem : list1)
        cout << elem << " ";
      
    15. remove_if
    16. Remove all the elements which are greater than 4 from the list1:

      list1.remove_if([](int n) {
      	return n > 4;
      });
      cout << "\n 8. remove_if function, list1 (numbers>4 are removed):" << endl;
      for (auto &elem : list1)
        cout << elem << " ";
      
  • Run the program.
  • Lesson # 9. Structures

    Theory

    Structures in C++

  • A data structure is a group of data elements grouped together under one name. These data elements, known as members, can have different types and different lengths.
    • Example:

      1
      2
      3
      4
      5
      6
      7
      
      struct product {
        int weight;
        double price;
      } ;
       
      product apple;
      product banana, melon;
      This declares a structure type, called product, and defines it having two members: weight and price, each of a different fundamental type. This declaration creates a new type (product), which is then used to declare three objects (variables) of this type: apple, banana, and melon. Note how once product is declared, it is used just like any other type.
    • Right at the end of the struct definition, and before the ending semicolon (;), the optional field object_names can be used to directly declare objects of the structure type. For example, the structure objects apple, banana, and melon can be declared at the moment the data structure type is defined:
    • 1
      2
      3
      4
      
      struct product {
        int weight;
        double price;
      } apple, banana, melon;
      In this case, where object_names are specified, the type name (product) becomes optional: struct requires either a type_name or at least one name in object_names, but not necessarily both.

    Access to the objects’ members

  • Once the three objects of a determined structure type are declared (apple, banana, and melon) its members can be accessed directly. The dot notation is used. Dot (.) must be inserted between the object name and the member name. For example, we could operate with any of these elements as if they were standard variables of their respective types:
  • 1
    2
    3
    4
    5
    6
    
    apple.weight
    apple.price
    banana.weight
    banana.price
    melon.weight
    melon.price
    Each one of these has the data type corresponding to the member they refer to: apple.weight, banana.weight, and melon.weight are of type int, while apple.price, banana.price, and melon.price are of type double.

    Pointers to structures

  • Structures can be pointed to by its own type of pointers:
  • 1
    2
    3
    4
    5
    6
    7
    
    struct Product_t {
      int weight;
      double price;
    } apple, banana, melon;
     
    Product_t aproduct;
    Product_t * pproduct;
    Here aproduct is an object of structure type Product_t, and pproduct is a pointer to point to objects of structure type Product_t.
  • Therefore, the following code would also be valid:
  •  
    pproduct = &aproduct;
    
    The value of the pointer pproduct would be assigned the address of object aproduct.
  • The following example serve to introduce a new operator: the arrow operator (->):
  • //...
    struct Product_t {
      int weight;
      double price;
    } ;
     
    int main ()
    {
      string mystr;
     
      Product_t aproduct;
      Product_t * pproduct;
      pproduct = &aproduct;
     
      cout << "Enter weight: ";
      cin >> pproduct ->weight;
      cout << "Enter price: ";
      cin >> pproduct ->price;
     
      cout << "\nYou have entered:\n";
      cout << pproduct ->weight << " ";
      cout << pproduct ->price;
     
      return 0;
    }

    Tuples

  • A tuple is an object that can hold a collection of items. Each item can be of a different type.
  • Example:

    #include <string>
    #include <tuple> // std::tuple, std::get, std::tie, std::ignore
     
    using namespace std;
     
    int main()
    {
      tuple<int, char, string> t {4, 'z', "C++"}; // the 1-st way of declaration
      auto x = make_tuple(4, 'z', "C++"); // the 2-d way of declaration
     
      auto s1 = get<2>(x);  // access element
      get<0>(t) = 20; // set to another value
      int i; char c; string s;
      tie(i, c, s) = t; // unpack elements
      tie(ignore, ignore, s) = t; //unpack (with ignore) 
    }

    Labs and tasks

    Lab 1:
    To do: Create a Books_t structure to store data about books. Add the following properties (members) of the object:

    • book’s title
    • year of work

    Tasks:

    1. Create a Books_t structure
    2. Implement a method for printing out the information about the objects:
    3. void printBook(Books_t book);
    4. Specify two object names (e.g. Pushkin, Chekhov).
    5. In the main program, create at least 2 objects, display summaries of those books.

    Expected output:

    Lab 1:
    Enter year of Chekhov work Three Sisters:
    1897
    Pushkin's work is:
     Eugene Onegin 1823
    And Chekhov's:
     Three Sisters 1897
    

    ✍ How to do:

    • To perform the lab, create an empty console application with a name Lesson8. Add files: main8.cpp, structBooks8.cpp, structBooks8.h.
    • Include all the necessary libraries and files.
    • 1. Create a Books_t structure to store data about books. Add the following properties (members) of an object: book’s title, year of work.

    • The structure must be defined inside a header file. So, open the structBooks8.h and add the code to define the structure with two members, they are title and year:
    • struct Books_t
      {
      	string title;
      	int year;
      };
      

      2. Implement a method to print out the information about the objects.

    • Also, inside the header file, you should define the method with a parameter of the Books_t type, to accept a specific book from the main program. Add the code after the structure:
    • //method for printing out the information about the objects
      void printBook(Books_t book);
      
    • The implementation of the function must be placed into the structBooks8.cpp file:
    • void printBook(Books_t book)
      {
      	cout << book.title;
      	cout << " " << book.year << endl;
      }
      

      3. Specify two objects (e.g. Pushkin, Chekhov).

    • Open the main.cpp file and inside the main function add the code to create two objects of the structure type:
    • Books_t Pushkin;
      Books_t Chekhov;
      

      4. In the main program, create at least 2 books, display summaries on these books.

    • After the objects' definitions, add the code to initialise the members (fields) with specific values. Ask user to enter one of the fields value, e.g. the year of the book:
    • Pushkin.title = "Eugene Onegin";
      Pushkin.year = 1823;
      
      Chekhov.title = "Three Sisters";
      cout << "Enter year of Chekhov work Three Sisters: "<cin >> Chekhov.year;
      
    • Print information about the books using the printBook method:
    • cout << "Pushkin's work is:\n ";
      printBook(Pushkin);
      cout << "And Chekhov's:\n ";
      printBook(Chekhov);
      
      system("pause");
      
    • Add the code to return a value 0 inside the main function. Run the program and check the output.
    Task 1:

    To do: Create a Cars_t structure to store information about cars. Add members (fields) about the car's color, car's brand and year of issue. Create at least 4 objects and output information about those objects, using a printCars method.

    Note: The signature of the printCars method should be as follows:

    void printCars(Cars_t car);

    Expected output:

    Task 1:
    Enter car's brand:
    >>audi
    Enter car's color:
    >>grey
    Enter car's year of issue:
    >>1997
    Summary info:
    audi grey 1997
    bmw green 2009
    suzuki white 2015
    honda black 2019
    

    [Solution and Project name: Lesson_9task1, file name L9Task1main.cpp, L9Task1imp.cpp, L9Task1.h]

    Lab 2, arrays of structure type:

    To do: Create a Toys_t structure to store data about toys for sale. Add following properties (members) of the object:

    • toy's title of string type
    • age of children to play with that toy (integer type)

    Tasks:

    1. Implement a method for printing out the information about the objects:
    2. void printBook(Toys_t toy);
    3. Implement a method for printing out the toys for small children (up to 4 years old):
    4. void printToy4(Toys_t toy);
    5. Specify an array of objects toys. Since structures are types, they can also be used as a type of arrays to construct tables or databases of them.
    6. In the main program, create at least 4 elements of the array, display summaries on those toys.

    Expected output:

    Enter toy's title:
    >>cat
    Enter child's age:
    >>2
    Summary info:
    car 3
    doll 4
    crocodile 6
    cat 2
    Summary info for small children:
    car 3
    doll 4
    cat 2
    

    ✍ How to do:

    • To perform the lab create an empty console application with a name Lesson9Toys. Add files: main9.cpp, structToys9.cpp, structToys9.h.
    • Include all needed libraries into the code of those files.
    • 1. Create a Toys_t structure for storing data about the toys for sale

    • The structure must be defined inside a header file. So, open the structToys8.h and add the code to define the structure with two properties (members), they are title and age:
    • struct Toys_t
      {
      	string title;
      	int age;
      };
      

      2. Implement a method to print out information about the objects.

    • Also inside the header file you should define a method with a parameter of Toys_t type, to accept a specific toy from the main program. Add the code after the structure:
    • //method for printing out the information about the objects
      void printToys(Toys_t toy);
      
    • The implementation of the function should be placed into the structToys8.cpp file:
    • void printToys(Toys_t toy)
      {
      	cout << toy.title;
      	cout << " " << toy.age << endl;
      }
      

      3. Implement a method to print out the toys for small children (up to 4 years old)

    • Inside the header file, define a method with a parameter of Toys_t type:
    • //method to print out the toys for small children
      void printToy4(Toys_t toy);
      
    • The implementation of the function should be placed into the structToys8.cpp file:
    • void printToy4(Toys_t toy)
      {
      	if (toy.age <= 4) {
      		printToys(toy);
      	}
      }
      

      4. Specify an array of objects toys.

    • Open the main.cpp file and inside the main function add the code to create an array of objects of structure type:
    • Toys_t toys[4];
      

      5. In the main program, create at least 4 elements of the array, display summaries on those toys.

    • After the objects' definitions, add the code to initialise members (fields) with specific values. Ask user to enter the values of one array element:
    • toys[0].title = "car";
      toys[0].age = 3;
      toys[1].title = "doll";
      toys[1].age = 4;
      toys[2].title = "crocodile";
      toys[2].age = 6;
      cout << "Enter toy's title: " << endl;
      cin >> toys[3].title;
      cout << "Enter child's age: " << endl;
      cin >> toys[3].age;
      
    • Print out the information about the toys using the printToys method, and information about the toys for small children:
    • cout << "Summary info:\n ";
      for (auto x: toys)
      	printToys(x);
      cout << "Summary info for small children:\n ";
      for (auto x : toys)
      	printToy4(x);
      
      system("pause");
      
    • Add the code to return a value 0 inside the main function. Run the program and check the output.
    Task 2:

    To do: Create a Tours_t structure to store information about tours for tourists. Add members (fields) to implement the following info about the tour: country name, number of people, number of days, country rate (of double type). Create a method to print the data, as well as method of the structure to calculate the cost of a trip based on: number of people * number of days * country rate. Inside the main function, specify an array of objects tours. Both methods must be called for the array elements.

    Note: The signature of the printTourCost method should be as follows:

    // returnes the result of calculation, double type
    double printTourCost(Tours_t tour);

    Expected output:

    Task 2:
    Summary info:
     Sweden: people 2, days 3, rate 155.5
     the price is 933
    Norway: people 1, days 3, rate 265.5
     the price is 796.5
    UK: people 2, days 4, rate 455.5
     the price is 3644
    

    [Solution and Project name: Lesson_9task2, file names L9Task2main.cpp, L9Task2imp.cpp, L9Task2.h]

    Lab 3, Pointers to structures:

    To do: Create a Movies_t structure for storing data about movies. Add the following properties (members) of an object:

    • movie's title of string type
    • the year of issue (integer type)

    Specify an array of movies (ask user to enter the info of one film). Implement a method for printing out information about the objects, use a pointer to those objects and an arrow operator.

    Expected output:

    Please, enter a title: 
    >>Matrix
    Please, enter year: 
    >>1999
    
    Summary information:
    Matrix 1999
    Titanic 1997
    

    ✍ How to do:

    • To perform the lab create an empty console application named Lesson8Movies. Add files: mainMovies9.cpp, structMovies9.cpp, structMovies9.h.
    • Include all necessary libraries into code of those files.
    • A structure must be defined inside a header file. So, open the structMovies9.h and add the code to define a structure with two properties (members), they are title and year:
    • struct Movies_t {
      	string title;
      	int year;
      };
      
    • Also, inside the header file, you should define a method with a parameter of Movies_t type, to accept an array of movies from the main program. Add the code after the structure:
    • //method for printing out the information about the movies array with n elements
      void printMovies(Movies_t* movie, int n);
      
    • Implementation of the function should be placed into structMovies9.cpp implementation file:
    • void printMovies(Movies_t* array, int n) {
      	Movies_t *ptr = array;
      	for (int i = 0; i < 2; i++) {
      		cout << ptr->title << " " << ptr->year << endl;
      		ptr++;
      	}
      }
      
      *ptr is a pointer to point at location which *array pointer points at.
      The arrow operator (->) is a dereference operator that is used exclusively with pointers to objects that have members. This operator serves to access a member of an object directly from its address.
    • Open the mainMovies9.cpp file and inside the main function add the code to create an array of objects of structure type and a pointer to point at that array:
    • Movies_t amovie[3];
      Movies_t * pmovie;
      
      pmovie = amovie;
      
    • After the objects' definitions, add the code to initialise properties (fields) with specific values. Ask user to enter the values of one array element:
    • amovie[1].title = "Titanic";
      amovie[1].year = 1997;
      cout << "Enter title: ";
      cin >> pmovie->title;
      cout << "Enter year: ";
      cin >> pmovie->year;
      
    • Print out the information about the movies using the printMovies method:
    • cout << "\nThe summary:\n";
      printMovies(amovie, 2);
      
      system("pause");
      
    • Inside the main function, add the code to return a value 0. Run the program and check the output.
    Task 3:

    To do: Create an Employee_t structure to store information about employees of some company. Add members (fields) to implement the following info about the employees: name, department, phone, salary. Specify an array of employees. Implement a method for printing out the information about the objects, use pointer to those objects and arrow operator. Also, create a smallSalary method to print out information about the employees, whose salary is less than 30 000 roubles.

    Note: A signature of the smallSalary method should be as follows:

    void smallSalary(Employee_t* array, int n);

    Expected output:

    Task 3:
    Summary info:
    Ivanov: bookkeeping department, t. 233-33-33, 28000 roubles
    Petrov: IT department, t. 233-33-34, 45000 roubles
    Sidorov: client department, t. 233-33-35, 25000 roubles
    
    Salary is less than 30 000 roubles:
    Ivanov
    Sidorov
    

    [Solution and Project name: Lesson_9task3, file names L9Task3main.cpp, L9Task3imp.cpp, L9Task3.h]


    Tuples

    Task 4:

    To do: Declare a tuple mytuple of two elements, they are a number (5) and a character ('a') (think about their type). Perform the following tasks:

  • Change the value of the first element to 6
  • Unpack elemetns and print them
  • Expected output:

    Task 4:
    mytuple contains: 6 and a
    

    [Solution and Project name: Lesson_9task4, file names L9Task4main.cpp]

    Lesson # 7. Pointer Basics

    Theory

    1. Pointer Basics

    • Pointers are a way to specify the location of a variable. Instead of storing a value such as 5 or the c character, the pointer value is the location of another variable.
    • Pointer variables have a size (the number of bytes in memory), a name, and a value. They must be declared and initialized.
    • «Pointer» (by itself) it is not a type. This is a type constructor — a language construct that, when applied to another type, gives us a new type. In particular, adding an asterisk ( * ) after any type names the type that is a pointer to that type. For example:
    • /*
      declares a variable named my_char_pointer 
      with the type - pointer to char 
      (a variable pointing to a character)
      */
      char * my_char_pointer; // pronounced "char star my char pointer"
      Declaring a pointer
    • The pointer declaration tells us the name of the variable and the type of the variable that this pointer will point to.
    • Assigning to a pointer
    • We can assign to pointers, changing their values. In the case of a pointer, changing its value means changing where it points.
    • We have to initialize a pointer (giving it something to point at) before we use it for anything else.
    • If we do not initialize a pointer before we use it, we have an arrow pointing at some random location in our program (this may cause the program’s crash).
    • To get an arrow pointing at some address of that cell in memory, we need a way to name that box, and then we need to use the & operator (the operator is named the «address-of» operator). Conceptually, the & operator gives us an arrow pointing at its operand.
    • /* you can see code that declares an integer x 
      and a pointer to an integer xPtr */
      int x = 5;
      int *xPtr;
      xPtr = &x; // sets the value of the variable xPtr to the address of x
    • the value of x is initialized to 5 in the same line in which it is declared;
    • the value of xPtr is initialized to the location of x;
    • after it is initialized, xPtr points to the variable x.
    • The code &x = 5; will not compile. A programmer can access the location of a variable, but it is not possible to change the location of a variable.
    • Dereferencing a pointer

    • Once we have arrows pointing at locations of variables, we want to make use of them by «following the arrow» and operating on the box it points at the end of the arrow (when the value of the variable is changing). Following the arrow is accomplished using the star symbol *, a unary (унарный) operator that dereferences the pointer.
    • 6
      7
      
      // An example of the use of the derference operator: 
      *xPtr = 6; // changes the value that xPtr points at 6
    • Note that the green arrow indicates that this line has not been executed yet, hence x still has the value 5 in the conceptual representation. Once line 7 is executed, however, the value will be 6.
    • Two contexts in which you will see the star (*) symbol, don’t mix them:
      1. In a variable declaration, such as int *p;, the asterisk is part of the type name, and tells us that we want a pointer to some other type (in our example, int * is the type of p).
      2. When the asterisk is the dereference operator. For example, the code r = *p; gives the variable r a new value, namely the value inside the memory cell that p points to. The code *p = r; changes the value inside the memory cell that p points at to be a new value, namely the value of the variable r.

    • When you work with pointers, you will use the asterisk first to declare the variable and then later to dereference it. Only variables that are of a pointer type may be dereferenced.
    • int * q = &y; // is the same as the two statements:
      int *q; 
      q = &y;
      Summarizing
    • There are only three basic pointer actions — declaring, assigning (including initializing), and dereferencing.

    Correct version of swap

    Solution: We have to pass the swap function pointers to the original variables a and b, as it follows below:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    #include <iostream>
    using namespace std;
     
    void swap(int *x, int *y) {
    	int temp = *x; // temp temporarily stores the value that x points at, =3
    	*x = *y; // we take the value that y points to, which is the value of b (=4) 
                      //and store that in the value that x points to, namely the variable a
    	*y = temp; // we take the temp = 3 and store that into the integer that y points at, 
                        //which is the variable b
    }
     
    int main() {
    	int a = 3;
    	int b = 4;
     
    	swap(&a, &b);
    	cout<<"a = "<< a<< ", b = "<<  b << endl;
    	system("pause");
    	return 0;
    }
      
    the swap function takes two arguments, x and y, which are pointers to integers;
    as we access the values of the integers that x and y point to in the code inside swap, we’re going to have to de-reference x and y. And so, that’s why we’ll see these asterixes (*) before x and y throughout the code;
    inside the main, instead of passing in a and b, we now have to pass in the address of a and address of b.

    A program and memory

    • On a 32-bit machine, where addresses are 32 bits in size, the entire memory space starts with 0x00000000 (in hexadecimal format, each 0 represents 4 bits of 0) and ends at 0xFFFFFFFF (recall that 0x indicates hexadecimal, and that each F represents four binary 1’s). Each program has this entire address space at its disposal and there is a convention for how a program uses this range of addresses.
    • Let’s look at the figure to understand where the various components of the program are stored in memory.

      Null
    • When we use NULL, we’re going to indicate that it does not point at anything. Whenever we have NULL, we can use the pointer itself (which just has a numeric value 0), however, we cannot follow the arrow (as it does not point at anything).
    • The NULL pointer has a special type that we have not seen yet — void *. A void pointer indicates a pointer to any type, and is compatible with any other pointer type — we can assign it to an int *, a double*, or any other pointer type we want.

    2. Accessing an Array

    • Accessing an array element using pointer arithmetic works fine, and sometimes is the natural way to access elements. But in the case when we just want the n-th element of an array, it would be cumbersome to declare a pointer, add n to it, then dereference it.
    • Let’s look at an example of a function that prints the elements of an array and uses pointer manipulation to access those elements:
    • // * array : the name of the array is a pointer to its first element, that is 3
      void printArr(int *array, int n) { 
      	int *ptr = array; // *ptr is a pointer to point at the loaction which *array pointer points at
      	for (int i = 0; i < n; i++) {
      		cout << *ptr; // 1st step output 3, 2dt step output 1, 3d step output 7,
                      // to make pointer point at the memory cell of the next element in the array:
                      // example address ptr = 0x00b5f9a0
      		ptr++;  // 1st 0x00b5f9a4, 2nd 0x00b5f9a8, 0x00b5f9ac, 
                              // no element in the array, but there be no error
                              // it would cause the problem if we dereference pointer 
      	}
      }
      int main(){
      	int arr[4] = { 3,1,7,2 };
      	printArr(arr, 4);
      }
    • We can achieve this goal more succinctly by indexing the array. When we index an array, we write the name of the array, followed by square brackets containing the number of the element we want to refer to. It is important to note that in C++, array indexes are zero-based — the first element of the array is myArray[0].
    • // * array : the name of the array is a pointer to its first element, that is 3
      void printArr(int *array, int n) { 
           for (int i = 0; i < n; i++) {
      	 cout << array[i]; // 1st step output 3, 2dt step - 1, 3d step - 7, and then 2
           }
      }
      int main(){
      	int arr[4] = { 3,1,7,2 };
      	printArr(arr, 4);
      }
      To put the pointer at the beginnig of array:
      int a[] {1,3,5,7,9};
      int* p = a;
      // shift the pointer to the second element:
      p++;
      p++;
      Access by index:
      int a[] {1,3,5,7,9};
      int* p = a;
      cout << *(p + 1) << endl; // = a[1]=3
      cout << *(p + 2) << endl; // = a[2]=5

    Labs and tasks

    All the tasks that you did not have time to complete in class automatically become your homework. The homework must be completed before the next lesson.

    1. Pointer Basics

    Lab 0:
    To do: Create a function to calculate the addition of pointer and a variable of integer type. That is, function should return the sum of the pointer and the variable value.

    Note: The signature of the function must be as follows:

    int addP(int var1, int var2);

    Expected output:

    please, enter the first number (for pointer):
    >>>2
    please, enter the second number (to add):
    >>>500
    the result: pointer + 500 = 502
    

    ✍ How to do:

    1. To do the lab create empty console application with a name Lesson7. Add files: main7lab0.cpp, L7lab0.cpp, L7lab0.h.
    2. Include all the needed libraries and files.
    3. Open the main7.cpp file in the code editor. Type the code to output a message to the user, and enter the value of two variables. The first of them is for pointer to point to the location of it, and the second for adding to that pointer:
    4. cout << "Lab 0:" << endl;
      cout << "please, enter the first number (for pointer): "<< endl;
      int var1; 
      cin >> var1;
      cout << "please, enter the second number (to add): " << endl;
      int var2; 
      cin >> var2;
      
    5. After that, let’s turn to the string7.h file and include all the necessary directives:
    6. #pragma once
      #ifndef STRING7_H
      #define STRING7_H
      
      #include 
      // your code is here
      #endif
      
    7. The signature of the function was recommended in the task text, let’s add that code with a comments of the task text:
    8. //lab 0: Create a function to calculate the addition of pointer and a variable of integer type
      int addP(int var1, int var2);
      
    9. Now let’s create the implementation of the function. To do this, open the string7.cpp file, include all the directives you need, and add the code:
    10. //lab 0: to calculate the addition of pointer and a variable of integer type
      int addP(int var1, int var2) {
      	int* p_var = &var1;
      	return *p_var + var2;
      }
      
      Here, p_var is initialized with the location of var1. The function returs a derference operator — *p_var — which means we take the value that p_var points to (that is the value of var1) and add the value of var2 to it.
    11. Now you can call the function we’ve created and print the results. You should do this inside the main7.cpp file:
    12. cout << "Result:" << endl;
      cout << "pointer + " << var2 << " = " << addP(var1,var2) << endl;
      
    13. Add the code to return a value 0 inside the main function. Run the program and check the output.
    Task 1:

    To do: Create an application with a function that takes two arguments, they are integer numbers (var1 and var2), and prints the following calculations with its arguments, using pointers (p1 and p2):

    1) multiplication of pointer and variable: p1 * var1
    2) addition of pointers:  p1 + p2
    3) changing the value of var1 = 5 using pointer p1
    4) changing the address of pointer: p1(address) = p2(address)
    

    Note 1: To change the value of a variable:

    int* p1 = &var1; // if p1 is a pointer
    *p1 = 1; // 1 is a new value for the variable

    Note 2: The signature of the function must be as follows:

    void task1(int var1, int var2);

    Expected output:

    Task 1:
    please, enter the first var value:
    >>5
    please, enter the second var value:
    >>10
    multiplication of pointer and variable: 25
    addition of pointers: 15
    the result of changing the value of var1, var1 = 5
    the result BEFORE changing the address, p1 = 0098F7E8
    the result of changing the address, p1 = 0116FC90
    

    [Solution and Project name: Lesson_7task1, file name L7Task1main.cpp, L7Task1imp.cpp, L7Task1.h]

    2. Accessing an array

    Lab 1:
    To do: Create a function to calculate the addition of array elements. The task should be done using two functions. The first function shouldn't use a pointer accessing the array element by index, but the second function should use.

    Note 1: The signature of the functions must be the same except the names:

    int sumArray1(int * array, int n);
    int sumArray2(int * array, int n);

    Expected output:

    array:
    1 2 3 4 5
    the result of the first function: sum = 15
    the result of the second function: sum = 15
    

    ✍ How to do:

    1. At first, let's create a function which iterates over the array elements without using a pointer accessing the array element by index:
    2. int sumArray1(int * array, int n) // array points at the value 1
      {
      	// start with sum being 0
      	int AnswerSum = 0;
      	// count from 0 to n
      	for (int i = 0; i < n; i++) {
      		// update sum by adding array[i]
      		AnswerSum += array[i];
      
      	}
      	// give sum as your answer
      	return AnswerSum;
      }
      
      int main() {
      	int data[] = { 1,2,3,4,5 };
      	cout << "array: " << endl;
      	for (auto x : data) {
      		cout << x << " ";
      	}
      	cout << endl;
      	int sum= sumArray1(data, 5);
      	cout << "the result of the first function: sum = " << sum<< endl;
      
    3. Consider memory location:
    4. 1. The first loop iteration:
      2. The second loop iteration:
      3. The third loop iteration:
      4.The last loop iteration:
      Back to main function
      and destroying the frame of sumArray1:
    5. Now, let's create a function which iterates over the array elements using a pointer accessing the array element by index:
    6. int sumArray2(int * array, int n) // array points at the value 1
      {
      	// start with sum being 0
      	int AnswerSum = 0;
      	//  loop counter is a pointer to point at the address of the 1-st array element
      	for (int *p = array; p < array + n; p++) {
      		// update sum by adding redereference of p
      		AnswerSum += *p;
      
      	}
      	// give sum as your answer
      	return AnswerSum;
      }
      
    7. Call the function within the main and run the program.
    Lab 2, Arrays:
    To do: An array of integers is given (1, 2, 3, 4, 5, 6, 7, 8, 9). Make every second element being set to 0 (that is even elements must be = 0). You should use indexing the array.

    Note 1: The signature of the function should be as follows:

    void DelEveryEven(int* array, int n);

    Expected output:

    Lab 2, Arrays:
    The array before lab is done:
    1 2 3 4 5 6 7 8 9
    Result:
    1 0 3 0 5 0 7 0 9
    

    ✍ How to do:

    1. To do the lab open the application you've created for lab1 or, if you haven't done it, so make the next: Create empty console application with a name Lesson7. Add files: main7.cpp, string7.cpp, string7.h.
    2. Include all the needed libraries and files (if you didn't do it before).
    3. Open the main7.cpp file in the code editor. Type the code to output a message to the user, and to initialize an array in the same line in which you declare it:
    4. cout << "Lab 2, Arrays:\n";
      int my_arr[] = { 1,2,3,4,5,6,7,8,9 };
      
    5. Print the array elements before the lab is done:
    6. cout << "The array before lab is done: " << endl;
      for (auto x : my_arr) {
      	cout << x << " ";
      }
      
    7. After that, let's turn to string7.h file and include all necessary directives (if you didn't do it before for the lab1):
    8. #pragma once
      #ifndef STRING7_H
      #define STRING7_H
      
      #include 
      
      #endif
      
    9. The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
    10. // lab 2, arrays: An array of integers is given (1, 2, 3, 4, 5, 6, 7, 8, 9). 
      // Make every second element being set to 0
      void DelEveryEven(int* , int);
      
    11. Now, let's create the implementation of the function. To do this, open the string7.cpp file, include all the directives you need, and add the code:
    12. //lab 2, arrays:  An array of integers is given. 
      // Make every second element being set to 0 (that is even elements must be = 0).
      void DelEveryEven(int* array, int n) {
      	for (int* p = array + 1; p < array + n; p = p + 2) {
      		*p = 0;
      	}
      }
      
      The * array parameter is initialized to the location of the array, that will be passed on.
      Here, as a loop counter we use a pointer to point at the address of the 1-st array element+1.
      Let's consider the line int* p = array + 1;.

    13. array returns the memory cell of the first element. But we must make the second element being set to 0. So, we have array + 1.
    14. Having *p = 0 we dereference the pointer, and we make the second element equal to 0.
    15. To do the same manipulations with the fourth element (even), we can increment the pointer by 2 (p = p + 2).
    16. array + n means the memory cell of the first element plus n, which is 9. This provides an exit from the loop.
    17. Now you can call the function we've created and print the results. You must do it inside the main7.cpp file:
    18. DelEveryEven(my_arr, 9);
      cout << "Result: " << endl;
      for (auto x : my_arr) {
      	cout << x << " ";
      }
      cout << endl;
      
    19. Add the code to return a 0 value inside the main function. Run the program and check the output.
    Task 2_0:

    To do: An array of integers is given. Create an application with two functions which return a value of the largest element of the array. One of the functions should be without using of a pointer accessing the array element by index, another one should use the pointer.

    Note: The signature of the functions should be the same:

    int maxArray1(int * array, int n);
    int maxArray2(int * array, int n);

    Expected output:

    array:
    1 2 3 4 5
    the result of the first function: max = 5
    the result of the second function: max = 5
    

    [Solution and Project name: Lesson_7task2_0, file name L7Task2_0main.cpp, L7Task2_0imp.cpp, L7Task2_0.h]

    Task 2:

    To do: An array of positive and negative integers is given. Create an application with a function that sets its negative elements to positive values.

    Note: The signature of the function should be as follows:

    void SetNegToPos(int* array, int n);

    Expected output:

    Task 2:
    The array before lab is done:
    1 -2 3 4 5 -6 7 8 -9
    Result:
    1 2 3 4 5 6 7 8 9
    

    [Solution and Project name: Lesson_7task2, file name L7Task2main.cpp, L7Task2imp.cpp, L7Task2.h]

    Task 3:

    To do: An array of integers is given. Create a function that returns an index of the largest element of the array.

    Note 1: The signature of the function should be as follows:

    int findLargestInd(int * array, int n);

    Note 2: Withitn the function you should make the comparison:

    if (array[i] > array[largestIndex]) 
    {
    ...
    }

    Expected output:

    Task 3:
    array:
    1 5 3 2 1
    index of the largest element = 1
    

    [Solution and Project name: Lesson_7task3, file name L7Task3main.cpp, L7Task3imp.cpp, L7Task3.h]

    3. String characters access with pointer indexing

    Lab 3:
    To do: Two strings are given. Create the function which returns 1 if the strings are equal, and returns 0 otherwise.

    Note 1: To access the characters of a string with pointer indexing you should use char type for that string:

    char str1[] = "Apple";

    Note 2: The signature of the function should be as follows:

    int stringEqual(const char * str1, const char * str2);

    Expected output:

    // lab 3:
    the result for 'apple' and 'apple' is: 1
    ++++
    // lab 3:
    the result for 'apple' and 'apples' is: 0
    

    ✍ How to do:

    1. Let's declare a function with two arguments, they are constant char pointers to the strings:
    2. int stringEqual(const char * str1, const char * str2){
      ...
      }
      
    3. Then, we're going to declare the pointers pointing at the first letter of str1 and the first letter of str2. Add the code into the function:
    4. const char* p1 = str1;
      const char* p2 = str2;
      
    5. Then, we're going to create a loop to be repeated as long as what p1 points at is the same as what p2 point at. We should use dereference operator to take the values, that is to take the characters of the strings:
    6.  while (*p1 == *p2) {
      
      	}
      
    7. Then, we need to check if p1 is equaled to \0, that is the last character which means a termination of a string. In this case the function must return 1 (that is answer "yes"):
    8. if (*p1 == '\0') {
          return 1;
      }
      
    9. After, we advance p1 and p2 to the next letter:
    10. p1++;
      p2++;
      
    11. After the loop we need to return answer "no", that is in our function means 0:
    12. return 0;
      
    13. Now, we're going to return to the main function and create two c-string. And then to call the function:
    14. char str1[] = "apple";
      char str2[] = "apples";
      cout << "the result for \'"<< str1 <<"\' and \'"<< str2 <<"\' is: " << stringEqual (str1,str2) << endl;
      
    15. Run the program and check the output.
    Task 4:
    To do: Create a function to check if c-string contains a combination of letters 'mo'. Return 1 (if found) or 0 (if not found). It is not allowed to use any standard functions. You should use pointer.

    Note 1: The signature of the function must be as following:

    bool findMo(const char * str);

    Note 2: To check if this is not an end of the string, you can use the following loop condition:

    while (*str != '\0')

    Expected output:

    Task 4:
    the result for 'the movie was nice' is: 1
    

    [Solution and Project name: Lesson_7task4, file name L7Task4main.cpp, L7Task4imp.cpp, L7Task4.h]

    Lab 4:
    To do: Reverse the order of characters in the string. To do this, define a pointer to the last character and, moving two pointers from the beginning and end of the line to the middle, swap the corresponding characters.

    Note 1: To access the characters of a string with pointer indexing you should use char type for that string:

    char str[] = "Hello world";

    Note 2: The signature of the function should be as follows:

    void reverseString (char * str);

    Expected output:

    // lab 4:
    The string before lab is done:
    Hello world
    The string after lab is done:
    dlrow olleH
    

    ✍ How to do:

    1. To do the lab open the application you've created for lab1 or, if you haven't done it, so make the next: Create empty console application with a name Lesson7. Add files: main7.cpp, string7.cpp, string7.h.
    2. Include all necessary libraries and files (if you didn't do it before).
    3. Open the main7.cpp file in the code editor. Type the code to output a message to the user, and to initialize an array of char type (the string will be treated as an array of chars):
    4. cout << "Lab 4:" << endl;
      char str[] = "Hello world"; 
      cout << "The string before lab is done: " << str << endl; 
      
    5. After that, let's turn to string7.h file and include all the needed directives (if you didn't do it before for the lab1):
    6. #pragma once
      #ifndef STRING7_H
      #define STRING7_H
      
      #include 
      
      #endif
      
    7. The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
    8. // Lab 4: Reverse the order of characters in the string. 
      void reverseString(char* str);
      
      str is initialized to the location of str.
    9. Now, let's create the implementation of the function. To do this open the string7.cpp file, include all the directives you need, and add the code:
    10. // Lab 4: Reverse the order of characters in the string. 
      void reverseString(char* str) {
      	char* str1 = str;
      	char* res = nullptr;
      	while (*str1) {
      		res = str1; 
      		*(str1++); 
              } // end of while
      // ...
      } // end of function
      
      Here, we define a pointer to string's first character. The line (char* res = nullptr;) returns a "null pointer", that is 0x00000000 address. Then, we use the while loop to iterate over the array's elements addresses. After the loop, the variable res will get the value of the address of the last character of the string, that is can be 0x00cffae6, for example, for "d" character).
    11. Then we're going to assign the value of the characters to the *str variable, moving the pointer from the last character to the middle. To do it, we use the temporary variable t. And at the same time we're going to substitute the values of the array elements, beginning from the last element, and assigning the value of the first element to it. We should do the dereferencing for this purpose:
    12. 	auto l = res;
      	while ((l) > (str)) {
      		auto t = *l; // temporary variable to store the values, moving from the last, 'd'
      		*l = *str; // dereferencing, we take the value that *str points to, which is the value of str 
                                 //and store that in the value that *l points to
      		*str = t; // changes the value that *str points to
      		l--; // moving from the last address to the middle
      		str++; // moving from the first address to the middle
      	}
      
      
    13. Now you can call the function we've created and print the results. You must do it inside the main7.cpp file:
    14. reverseString(str);
      cout << "The string after lab is done: " << str << endl;
      
    15. Add the code to return a 0 value inside the main function. Run the program and check the output.
    Task 5:
    To do: There is a string that contains the positive integer ('Happy 2021 year to u!'). Create a function to display a substring containing this number.

    Note 1: Use the following function signature. It returns integer (you should make a number using the digits):

    void numbFromStr(char* str);

    To understand where the end of the string is, you can use the following loop:

    while (*str1)
      {
    	  pLast = str1; // the address of the last character
    	  *(str1++);
       }

    Note 2: The result must be of string type, so you should include the string library:

    #include <string>

    Note 3: to check if the character is a digit, you should create a function:

    bool isdigit(char c) {
    	if ((c <= '9') && (c >= '0')) {
    		return true;
    	}
    	else
    		return false;
    }

      
    Expected output:

    Task 5:
    The string for the task is: Happy 2021 year to u!
    the substring of numbers: 2021
    

    [Solution and Project name: Lesson_7task5, file name L7Task5main.cpp, L7Task5imp.cpp, L7Task5.h]

    Task 6:

    To do: A string of characters is given. Convert all uppercase Latin letters to lowercase in it. The function should return the number of substitutions performed.

    Note 0: You should use the character string type:

    char s[] ="...";

    Note 1: Use the following function signature. It returns an integer (the number of substitutions):

     int to_lower(char * str);

    Note 2: To check if this is not an end of the string, you can use the following loop condition:

    while (*str != '\0')

    Note 3: To check if a letter is uppercase letter, you should use the following function:

    bool isCappital(char ch)
    {
        return (ch >= 'A' && ch <= 'Z');
    }

    Note 4: To convert a letter to lowercase, you should use the standard tolower(ch) function.
      
    Expected output:

    Task 6:
    The string for the task is: HelLo wOrLD
    The result is: hello world
    

    [Solution and Project name: Lesson_7task6, file name L7Task6main.cpp, L7Task6imp.cpp, L7Task6.h]

    Task 7:

    To do: A string of characters is given representing an arithmetic expression of the form "<digit>±<digit>±...±<digit>", where the arithmetic operator "+" (plus) or "" (minus) is located in place of the operation sign "±" (for example, "4+7-2-8"). Calculate the result of this expression (an integer).

    Note 1: Use the following function signature. It returns an integer (the number of substitutions):

    int eval(char * expr);

    Note 2: To find the first operand (digit) you can use the following code:

    int res = *expr++ - '0'; // here *expr++ is the first character in the string

    or a function:

    char r = *expr; //*expr is a code in ascii-table
    int res = atoi(&r); // converts code to digit

    Note 3: To store the operation or a digit you can use the following concept:

    char ch1 = *expr++; //arithmetic operator or digit

    ch1 will be set to 53'9' - 53 is an address and 9 is a digit stored.

    // to take the digit only insted of ch1 you must use :
    ch1-'0';

    Expected output:

    Task 7:
    The string for the task is: 9+4-2-0
    The result is: 11
    

    [Solution and Project name: Lesson_7task7, file name L7Task7main.cpp, L7Task7imp.cpp, L7Task76.h]



    Lesson # 6. Using strings

    Theory

    String type

    • To work with a string the string library must be included:
    • #include <string>
    • Variables of string type can be understood as an array of characters.
    • A specific character in a string can be accessed as in a regular array, that is, by its index:
    • string str="it's possible to understand it";
      cout << str[2] << endl; // output: '
      for (int i = 0; i <= s.size(); i++) { // to iterate over the characters of a string
      		if (s[i] == ' ')
      			//to do sth
      	}

    String functions

    • Find()
    • size_t find (const string& str, size_t pos = 0) const;
    • Searches the string for the first occurrence of the sequence specified by its arguments.
    • When pos is specified, the search only includes characters at or after position
    • pos, ignoring any possible occurrences that include characters before pos.

    • size_t is an unsigned integral type, able to represent the size of any object in bytes
    • npos constant — Maximum value for size_t (usually = 4294967295)
    • This value, when used as the value for a len (or sublen) parameter in string’s member functions, means «until the end of the string».
    • As a return value, it is usually used to indicate no matches.
    • This constant is defined with a value of -1, which because size_t is an unsigned integral type, it is the largest possible representable value for this type.
    • The method to find how many times the subsctring occurs in the string:
      string str="it's possible to understand it";
      string substr="it";
      size_t f = -1; 
      int counter = 0;
      while (true) // infinite loop
       {
          // f = str.find(substr); // f will be equaled to 0
          // 'f+1' is required to move to the next position after found match
          f = str.find(substr, f+1); // in the 2-nd iteration f = 28
          // in the 3-rd iteration f = 4294967295, it means that there is no more matches 
          // string::npos = 4294967295
          if (f == string::npos)
               break;
          counter++;
        }
      cout << counter;

      Escape sequences are used to represent certain special characters within string literals and character literals: \‘ single quote

      char c = '\''

    Strings as char and pointers

  • A C-character string is a string (character array) with a null character at the end (\0).
  • char s[6] = "Hello"; // \0 is added automatically 
    char s[] = "Hello"; // the same reuslt
    char* p = s; // H

    To iterate over the string characters:

    char* p = s;
    while (*p != 0)
      cout << *p++;

    or

    char* p = s;
    while (*p)
      cout << *p++;

    Labs and tasks

    All the tasks that you did not have time to complete in class automatically become your homework. The homework must be completed before the next lesson.

    To do all the tasks and labs of this lesson you must create three files:

    1. a header file (basicStrings.h) (functions definitions for all the tasks must be placed here);
    2. a basicStrings.cpp file (the implementations of the functions with comments for all the tasks must be placed here)
    3. a main.cpp must provide prompts for user, calling created functions and output results for all the tasks.
    4. Each function should be accompanied by a comment about what it is intended for, and a number of the task must be provided.

    String type

    Lab 1:

    To do: A string type variable (s="Hello world") is given and character (variable c) is given (ask user to input it). Check if the character c is among the characters of the string. Create a function named checkIfChar to do the task. The function must return 1 if entered character is found or 0 otherwise.

    Note 1: The signature of the function must be as follows:

    bool checkIfChar(string s, char c)

    Expected output:

    lab 1
    A sentence is "Hello world"
    Enter character:
    >>> o
    result:
    1
    

    ✍ Algorithm:

    1. Open visual studio and create a console application named Lesson6. While creating, check the Empty project (Пустой проект) item.
    2. Two .cpp files must be added to the source files folder of the project (basicStrings.cpp and main.cpp) and one header file must be added to the Header files folder.
    3. Open the main.cpp file’s code and add all the libraries we need to do the lab:
    4. #include 
      #include  //
      #include  // is needed to work with string type
      using namespace std;
      
    5. Inside the main function, ask user to input a sentence and assign the input value to str variable. Don’t forget to declare the variable:
    6. int main() {
      	cout << "lab 1:" << endl;
      	string str="Hello world"; // declaration of the variable
      	
        // ..
      }
      
    7. Then, ask user to input a character to find it in the sentence. Set the input value to a variable c:
    8. cout << "Enter character :" << endl;
      	char c;
      	cin >> c;
      
    9. Now, we’re going to create a function to check if the input charecter is within the input sentence. The function must be supplied with two values — the sentence (str) and character (c), they are the arguments of the function. Add the signature of the function before the main function:
    10.  //lab 1: Check if the character c is among the characters of the string
      bool checkIfChar(string s, char c)
      {
      	// to do
      }
      
    11. We’re going to itereate over the characters of the string using for loop. Inside the the loop body we must check if a current character of the string matches the character c. If it does, the function must return 1, in the case when it doesn’t, the function returns 0.
    12. for (int i=0;i<= s.size();i++){
      		if (s[i]==c){
      			return 1;
                              break;
                       }
      	}
      return 0;
      
    13. Come back to the main function code and call the function. The results of the function must be printed out, so, the calling should be inside cout<< statement:
    14. cout << "result :" << checkIfChar(str, c) << endl;
      
    15. Be careful not to forget to add a statement to stay the console window opened:
    16. //...
      system("pause");
      return 0;
      //...
      
    17. Run the program and check the output.
    Task 1:

    To do: Create a function to check if input text contains a combination of letters 'mo'. Return 1 (if found) or 0 (if not found). It is not allowed to use any standard functions. To store the text, you should use a string type variable.

    Note 1: The signature of the function must be as following:

    bool findMo(string s)

    Note 2: To check two or more conditions in if statement you must use && (logical and):

    if (condition_1 && condition_2){
    }

    Expected output:

    task 1
    result for 'Hello world' is:
    0
    ---
    task 1
    result for 'My mom' is:
    result:
    1
    

    Task 2: C-character string

    To do: Create a function to check if the value of string variable contains the word 'dog'. Return 1 (if found) or 0 (if not found). You should use c character string and a pointer. It is not allowed to use any standard functions.

    Note 1: The signature of the function must be as following:

    bool findMo(char* p)

    Expected output:

    task 2
    the string is: Hello world
    result:
    0
    ---
    task 2
    Enter a sentence:
    the string is: my dog is nice
    result:
    1
    
    Task 3:

    To do: A sentence is given: str = "word1 word2 word3 word4". Calculate the number of words in it. It is not allowed to use any string standard functions.

    Note 1: You have to count the number of words by the number of spaces between the words.

    Note 2: Don't forget to check if the sentence contain extra spaces at the beginning and end of the sentence.

    Note 3: The signature of the created function must be as following:

    void countWords(string s, int& counter)

    Expected output:

    task 3
    Enter a sentence:
    >>>  word1 word2 word3 word4
    result:
    4
    

    Task 4:

    To do: A string is given. Check if its first and last characters match. Create a function named LastAndFirst to do the task. It is not allowed to use any string standard functions (except size() function).

    Note 1: The signature of the created function must be as following:

    bool LastAndFirst(string s)

    Note 2: The size() method of the string can be useful to find the last character (s.size()).

    Expected output:

    task 4
    for sentence Hello world
    the result is:
    false
    ---
    task 4
    for sentence lucky ball
    result is:
    true
    

    String functions

    Task 5:

    To do: Create a function to check if the text contains the word cat. Print the position (order number) of the word in the text. You should use standard find function.

    Note 1: The signature of the created function must be as follows:

    void findCatFunction(string s, string s0)

    Note 2: About find() function:

    s.find(s0) // returns -1 if there are no matches of s0 in the text s

    Expected output:

    task 5
    for text: cat word1 word3 word4
    result :
    cat is found at: 0
    ---
    task 5
    for text: word1 word3 word4
    result :
    cat is not found
    ---
    task 5
    for sentence: word1 cat word3 word4
    result :
    cat is found at: 6
    
    Lab 2:

    To do: Two strings S and S0 are given (they are entered). Find the number of occurrences of the string S0 in the string S.

    Note 1: In the solution, it is convenient to use the find member function of the string class, which returns the position of the occurrence of type size_t (unsigned integer), or the value of string :: npos in case no occurrence was found. Look at the example to understand the way to use them.

    Note 2: The signature of the function must be as follows:

    int countOccurrence(string s, string s0)

    Expected output:

    Lab 2
    string 1: it's possible to understand it 
    string 2: it
    result : 2
    

    ✍ Algorithm:

    1. Open main.cpp file and inside the main function, under the previous task code, add the code to output the number of the task. After that, declare the variables of string type and initialize them with values:
    2. //lab 2
      cout << "lab 2:" << endl;
      string str1, str2;
      str1 = "it's possible to understand it";
      str2 = "it";
      cout << "string 1: " << str1 << "\n string 2: "<< str2 << endl;
      
      \n is used to insert a new line.
    3. Open the implementation file, that is basicStrings.cpp. Add the code of the signature of the function, and also, add comments with explanation of the task:
    4. // lab 2: Find the number of occurrences of the string S0 in the string S
      int countOccurrence(string s, string s0)
      {
         // to do:
      } 
      
    5. The function must return integer type (since int is the type of the function).
    6. The function has two parameters of string type: s is a string containing the sentence, and s0 is a substring which we must find inside the string s.
    7. To find the substring we're going to use the find() standard method and f variable of size_t type (an unsigned integral type). The f variable will store the position of the substring inside the s string. And if there isn't founded substring the f will store 0 number, since it will be increase by 1 (f+1). When the find() function will reach the end of the string, the npos value (npos is a constant — maximum value for size_t (usually = 4294967295)) will be set to f variable:
    8.  size_t f = -1;
       int res = 0; // counter of the numbers of occurrences 
       while (true) // infinite loop
      	{
      		f = s.find(s0,f+1); 
      		if (f == string::npos) // if the end of the string is reached
      			break; // exit loop
      		++res;
      	}
      	return res;
      
      The infinite loop is convenient to use when we don't know how many repetitions of the loop there will be. Here the break operator will be executed only if when seeking the substrings, we will reach the end of the string.
    9. Let's return to the main.cpp file and inside the main function add the call of our function. Since the function will return the integer value, that is the number of occurrences, we must store the results of the function inside the variable:
    10. int counter = countOccurrence(str1, str2);
      cout << "result :"  << counter << endl;
      
    11. Run the program and see the outputs.
    Task 6:

    To do: The strings S and S0 are given. Create a function to remove the last substring that matches S0 from the S string. If there are no matching substrings, then return the unchanged S string.

    Note 1: You can use the rfind member function of the string class to find the last occurrence of a substring, and you can use the erase member function to delete.

    Note 2: Look at the example to understand the way to use them.

    Note 3: The signature of the function must be as follows:

    string eraseLast(string s, string s0)
    {
    	// to do:
            // 
            //
    	return s;
    }

    Expected output:

    task 6:
    string 1: it's possible to understand it
    string 2: it
    result: it's possible to understand
    
    Task 7:

    To do: A string containing at least one space character is given. Return the substring between the first and last spaces of the string. If the string contains single space, an empty string must be returned.

    Note 1: You can use the substr member function of the string class to extract a substring.

    Note 2: Look at the example to understand the way to use them.

    Note 3: The signature of the function and the fragment of its code:

    string betweenSpaces(string s)
    {
    	size_t f1, f2;
    	f1 = s.find(" "); // the position of the first space
    	f2 = s.rfind(" "); // the position of the last space
    	// ...;
            // ...;
    	return  // ...;
    }

    Expected output:

    task 7:
    string: it's possible to understand it
    result : possible to understand
    

    Lesson # 5. Arrays. Vectors

    Theory

    Single-dimensional arrays

  • The size of an array is fixed.
  • Array elements are zero-indexed.
  • The array does not store its size.
  • sample 1:

    // Declaring an array of 5 int elements 
    int b[5];

    sample 2:

    #include <iostream>
    using namespace std;
    int main()
    {
     // Declaring and initialization an array of  
     int a[] = {2, 3, 5, 7};
     cout << a[3] << endl; // output: 1
     // reassigning a value to a last element of an array
     a[3] = 1;
     
     a[4] = 2; // the error will occur
    }
    Using foreach loop:

    x (array element) is read-only

    int a[] = {3, 7, 9, 5, 7, 2, 7};
    for (int x : a)     
        cout << x << " ";  // output only: 3 7 9 5 7 2 7

    x (array element) can be read and written

    int a[] = {3, 7, 9, 5, 7, 2, 7};
    for (int &x : a)  // x by reference
    { 
        x += 1;  
        cout << x << " ";  // output: 4 8 10 6 8 3 8
    }
    Using an automatic random number generator with scaling:

    sample 1:

    // random numbers will be generated in the range from 1 to 10    
    #include <iostream>
    #include <ctime>
    using namespace std;
     
    int main()
    {
    // to have new randomly generated numbers each time we run the program:
    	srand(time(0)); 
    	int b[5];
    	for (int &x : b)
    	{
    		x = 1 + rand() % 10;
    		cout << x << " "; // example of output: 8 4 2 6 5
    	}
    	return 0;
    }
    }

    sample 2: we can do the same with classic for loop:

    #include <iostream>
    #include <ctime>
    using namespace std;
     
    int main()
    {
    // to have new randomly generated numbers each time we run the program:
    	srand(time(0));
    	int b[5];
    	for (int i=0;i<5;i++)
    	{
    		b[i] = 1 + rand() % 10;
    		cout << b[i] << " "; // example of output: 8 4 2 6 5
    	}
    	return 0;
    }
    Formula for the bounds of generating numbers:
    min + (rand() % ((max — min) + 1))

    Two-dimensional arrays

    Example:

    int numbMatrix[2][3] = { {1,2,3},{4,5,6} };
     
    	for (int i =0; i < 2; i++){
    		for (int j = 0; j < 3; j++) {
    			cout << numbMatrix[i][j] << ' ';
    		}
    	}

    Vectors

    • Vectors are template type. A template type is a special type that can take on different types when the type is initialized.
    • std::vector standard library class that provides the functionality of a dynamically growing array with a “templated” type.
    • The main difference from arrays is that vectors are dynamic arrays. This means that the vector size does not need to be set initially, elements can be added dynamically.
    • std::vector uses a template type:

    • Example:

      #include <vector>   // Definition
      using namespace std;
      int main()
      {
      vector<int> mm(5);  // Initialization
      // or it can be empty: vector<int> mm(); 
      vector<int> a {1, 2, 3, 7};  // Initialization
      // Loop for to iterate and print values of vector
      for (int i=0; i < a.size(); i++)  // size() - Number of elements
         cout << a[i] << " "; // 1, 2, 3, 7
      // Another kind of for loop (foreach) to iterate and print values of vector
      for (auto x : a)
         cout << x << " "; // 1, 2, 3, 7
      for (int& x : a)
         x++;
      }
      To use vector #include directive need to be placed.
    • When initializing a “templated” type, the template type goes inside of < > at the end of the type name:
    • std::vector<char> v1;
      std::vector<int> v2;
      
    • pop_back function removes the last element
    • push_back function adds an element to the end:
    • Example 1:

      #include <iostream>
      #include <vector>
       
      int main()
      {
          // Create a vector containing integers
          std::vector<int> v = {7, 5, 16, 8};
       
          // Add two more integers to vector
          v.push_back(25);
          v.push_back(13);
       
          // print out the particular elements
          cout << v.at(0) << endl; // 7
          // or:
          cout << v[1] << std::endl; // 5
          cout << v[2] << std::endl;
       
          // insertion into exact position starting from the very beginning
          v.insert(v.begin() + 2, 5); // number 5 into third position
       
          // Iterate and print values of vector
          for(int n : v) {
              std::cout << n << '\n';
          }
      }

      Example 2:

      #include <vector>
      #include <iostream>
       
      int main() {
      vector<int> v;
      for (int i = 0; i < 100; i++) {
         v.push_back( i * i );
      }
       
      cout << v[12] << std::endl;
       
      return 0;
      }

    Function template

    • A template variable is defined by declaring it before the beginning of a class or function:
    • template <typename T>
      int max(T a, T b) {
        if (a > b) { return a; }
           return b;
      }
      
    • Templated variables are checked at compile time, which allows for errors to be caught before running the program.
    • #include <iostream>
      using namespace std;
       
      template <typename T>
      T max(T a, T b) {
      	if (a > b) { return a; }
      	return b;
      }
      int main()
      {
      	cout << "max(3, 5): " << max(3, 5) << endl; // 5
      	cout << "max('a', 'd'): " << max('a', 'd') << endl; // d
      	cout << "max(\"Hello\", \"World\"): " << max("Hello", "World") << endl; // Hello
      	cout << "max(3, 5, 6): " << max(3, 5, 6) << endl; // error
       
      	system("pause");
      	return 0;
      }
    • A function template defines a family of functions.
    • A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function.
    • An explicit instantiation definition forces instantiation of the function or member function they refer to. It may appear in the program anywhere after the template definition, and for a given argument-list, is only allowed to appear once in the program, no diagnostic required.
    • template<typename T>
      void f(T s)
      {
          std::cout << s << '\n';
      }
       
      template void f<double>(double); // instantiates f<double>(double)
      template void f<>(char); // instantiates f<char>(char), template argument deduced
      template void f(int); // instantiates f<int>(int), template argument deduced
    • Implicit instantiation: When code refers to a function in context that requires the function definition to exist, and this particular function has not been explicitly instantiated, implicit instantiation occurs. The list of template arguments does not have to be supplied if it can be deduced from context.
    • #include <iostream>
       
      template<typename T>
      void f(T s)
      {
          std::cout << s << '\n';
      }
       
      int main()
      {
          f<double>(1); // instantiates and calls f<double>(double)
          f<>('a'); // instantiates and calls f<char>(char)
          f(7); // instantiates and calls f<int>(int)
          void (*ptr)(std::string) = f; // instantiates f<string>(string)
      }

      Note: omitting <> entirely allows overload resolution to examine both template and non-template overloads.

    Labs and tasks

    All the tasks that you did not have time to complete in class automatically become your homework. The homework must be completed before the next lesson.

    To do all the tasks and labs of this lesson you must create three files:

    1. a header file (basicVectors.h) (functions definitions for all the tasks must be placed here);
    2. a basicVectors.cpp file (the implementations of the functions with comments for all the tasks must be placed here)
    3. a main.cpp must provide prompts for user, calling created functions and output results for all the tasks.
    4. Each function should be accompanied by a comment about what it is intended for, and a number of the task must be provided.

    1-d and 2-d Arrays

    Task 0: 1-d Arrays

    To do:
    A single-dimensional array of 10 elements is given. The elements of this array is randomly generated in the interval [5;15]. Output the number of even and odd elements of the array.

    Expected output:

    Array:
    5 10 19 16 6 7 8 11 9 11 
    number of evens = 4, number of odds = 6
    

    [Solution and Project name: Lesson_4, files: Task0header.h, Task0imp.cpp, Task0main.cpp]

    Task 00: 2-d Arrays

    To do:
    A two-dimensional array 2-by-3 is given. The elements of this array is randomly generated in the interval [1;10]. Create a function to print the maximum value of the array.

    Expected output:

    Array:
    2 8 5
    1 10 5
    max = 10
    

    [Solution and Project name: Lesson_4, files: Task00header.h, Task00imp.cpp, Task00main.cpp]

    Lab:
    The tasks of this lesson will be continuation of this lab.

    To do: An integer N (N > 0) and an integer vector (array) of length N are given. Fill the vector with the first N positive odd numbers: 1, 3, 5,… N. Do not use the conditional statement. Create an oddVectorGenerator() function to do the task.

    Note: To print the resulting vector, hereinafter, you must use the print_vector() function template. The function must be placed inside special header file printVect.h (you should add a new file to your application).

    Copy the print_vector function code and paste it to the printVect.h file:

    #ifndef PRINTVECT_H
    #define PRINTVECT_H
     
    #include <iostream>
    #include <vector>
     
    // note: function templates are always must be inside header files
     
    // function template to output vector
    template<typename T>
    void print_vector(const std::vector<T>& v, char delim = ' ') {
    	for (auto x : v)
    		std::cout << x << delim;
    	std::cout << std::endl;
    }
     
    /* #ifndef PRINT_VECT_H: */
    #endif

    Expected output:

    lab 1
    enter N - the number of vector elements
    >> 25
    1 3 5 7 9 11 13 15 17 19 21 23
    

    ✍ How to do:

    • Create a new console application with a name Lesson 5.
    • In the Source files folder of the Solution Explorer window, add new files: basicVectors.cpp and main.cpp. In the Header Files folder add a new header file: basicVectors.h.
    • Function templates are always placed in header files unlike regular functions. Add a new header file and name it printVect.h. Copy and paste the template function code into it.
    • Open your main.cpp file and include there all the header files that program will need:
    • #include <iostream>
      #include "basicVectors.h"
      #include "printVect.h"
      using namespace std;
      
      
    • Then, you must define an integer vector. You should do it inside the main.cpp file, right after all the included directives:
    • vector<int> v;
      
    • Output the comment to indicate that this is lab 1. Then, ask user to input a number of the vector elements. Set the entered value to the n variable:
    • cout << "lab 1"<< endl;
      cout << "enter N - the number of vector elements";
      int n;
      cin >> n;
      
    • Open your basicVectors.h header file. Include all necessary directives:
    • #pragma once
      #include <iostream>
      #include <vector>
      using namespace std;
      
    • We’re going to define our oddVectorGenerator() function, that must fill the vector with the first N positive odd numbers:
    • void oddVectorGenerator(vector<int>&, int);
      
      We’re going to pass vector parameter by reference (&), because we don’t need to locate a new memory space to store it.
    • Open basicVectors.cpp file to add an implementation of the created function. But first, add all the include directives to the file:
    • #include 
      #include <cassert>
      #include "printVect.h"
      #include "basicVectors.h"
      using namespace std;
      
    • After that, let’s create the oddVectorGenerator() function and all the code it must implement:
    • void oddVectorGenerator(vector<int> &v, int n)
      {
      	for (int i = 1; i < n; i += 2)
      	{
      		v.push_back(i);
      	}
      }
      
      push_back function adds an element to the end of the vector.
      Only odd numbers will be set to vector due to the for loop step=2.
    • Open your main.cpp file and call the function. To output the results call the print_vector() function too:
    • oddVectorGenerator(v, n);
      print_vector(v);
      system("pause");
      
    • Run the program. And proceed with Task 1.

    Vectors

    Task 1:

    To do: A vector is given (you can have the following elements values: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10). Output its elements in reverse order. Create a function to do it.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    cout << "task 1" << endl;

    Note 2: To use the same variable v in this task you should clear the vector, and then, set new values:

    v.resize(0);
    v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    Note 3: You can create a new vector with the reversed elements values.

    Expected output:

    task 1
    before task:
    1 2 3 4 5 6 7 8 9 10
    after task:
    10 9 8 7 6 5 4 3 2 1

    [Solution and Project name: Lesson_5
    or you can have individual files: L5Task1header.h, L5Task1imp.cpp, L5Task1main.cpp]

    Task 2:

    To do: An integer vector is given. Calculate the quantity of odd elements within this vector, as well as the quantity of positive elements within it.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Note 2: To use the same variable v in this task you should clear the vector, and then, set new values:

    v.resize(0);
    v = { -1, 2, 3, 4, -5, 6, 7, 8, -9, 10 };

    Note 3: It is better to use abs function, because negative element can be met within the array.

    Expected output:

    task 2
    vector:
    -1 2 3 4 -5 6 7 8 -9 10
    number of positive: 7 number of odd : 5
    

    [Solution and Project name: Lesson_5
    or you can have individual files: L5Task2header.h, L5Task2imp.cpp, L5Task2main.cpp]

    Task 3:

    To do: An integer vector is given. Output the index of its first even element.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Note 2: To use the same variable v in this task you should clear the vector, and then, set new values:

    v.resize(0);
    v = { -1, 2, 3, 4, -5, 6, 7, 8, -9, 10 };

    Expected output:

    task 3
    vector:
    -1 5 3 4 -5 6 7 8 -9 10
    the first even element number is: 4
    

    [Solution and Project name: Lesson_5
    or you can have individual files: L5Task3header.h, L5Task3imp.cpp, L5Task3main.cpp]

    Task 4:

    To do: An integer vector is given. Ouput the maximum of its local minima (a local minimum is an element that is less than any of its neighbors: e.g. ... 5 2 7 ... => number 2 is a local minimum, because 2 < 5 and 2 < 7).

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Note 2: To initialize a variable that should store the current value of the maximum local minimum, it is convenient to use the INT_MIN constant from the standard header:

    int max = std::numeric_limits<int>::min();

    Expected output:

    task 4
    vector:
    -1 5 3 4 -5 8 7 8 -9 10
    the maximum of local minima is: 7
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5Task4header.h, L5Task4imp.cpp, L5Task4main.cpp]

    Task 5:

    To do: An integer vector A of size N (> 0) is given. Fill it with powers of two from the 1 power to the N:

    A = 21, 22, 23, 24,… 2N

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Expected output:

    task 5
    Enter N number:
    >>> 5
    vector:
    2  4  8  16  32
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5Task5header.h, L5Task5imp.cpp, L5Task5main.cpp]

    Task 6:

    To do: An integer vector A of size N is given. It contains at least one even value. Find the first and the last even values within the vector. To do the task create getFirstAndLastEvenNumber() function.

    Note 1: Use parameters by reference (&) to return two values from a function.

    Note 2: Besides the getFirstAndLastEvenNumber() function you should create one more function of boolean type, to check if the number is even:

    inline bool isEven(int n)
    {
        // ...
    }

    Note 3: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Expected output:

    task 6
    Enter N number:
    >>> 5
    vector:
    2  12  1  16  3
    the first: 2, the last: 16
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5Task6header.h, L5Task6imp.cpp, L5Task6main.cpp]

    Task 7:

    To do: Three integer vectors A, B and C of the same size N are given. You must fill in vector C with values according to the following rule: each of its elements is equal to the maximum of the elements of vectors A and B with the same index.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Note 2: To compare two values you should use the standard max function, for example:

    int maximum = std::max(a, b);

    Note 3: You should check if the sizes of the vectors are equal, use assert() function, for example:

     assert((a.size() == b.size()) && (c.size() == a.size()));

    Note 4: You should create the following function signature:

    void maxInVectors(std::vector<int> &a, std::vector<int> &b, std::vector<int> &c)
    {
    // body function
    }

    Expected output:

    task 7
    A vector:
    0 1 2 3 4 42 6 7 8 422
    B vector:
    9 8 7 6 5 4 3 2 1 0
    vector C:
    9 8 7 6 5 42 6 7 8 422
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5Task7header.h, L5Task7imp.cpp, L5Task7main.cpp]

    Extra tasks

    *ExTask 1:

    To do: An integer vectors Ais given. You must create B vector of the same size and fill in the vector with all numbers from A vector that have the digit 2 in decimal notation.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Note 2: In the implementation of the function, use a function that checks whether a given integer has a given digit in its decimal notation. You should implement it yourself:

    bool hasDigit (int n, int digit);

    Note 3: You should check if the sizes of the vectors are equal, use assert() function.

    Note 4: You should use push_back(value) method to add the new value to a vector. The method adds a new element to the end of the vector, for example:

    b.push_back(x);

    Expected output:

    task 6
    vector A:
    0 1 2 3 4 42 6 7 8 422
    vector B:
    2 42 422
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5ExTask1header.h, L5ExTask1imp.cpp, L5ExTask1main.cpp]

    *ExTask 2:

    To do: An integer vector is given. Output the length of the largest series of consecutive zeros.

    Note 1: You must complete this task in the same application as Lab 1. Output the task number before the results of this task are printed. Or you can complete it using another multi-file application with a print() fuctction inside.

    Expected output:

    task 7
    vector:
    0 1 0 0 0 42 6 7 8 422
    maximum length of 0: 3
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5ExTask2header.h, L5ExTask2imp.cpp, L5ExTask2main.cpp]

    *ExTask 3:

    To do: Remove all odd elements from the vector by shifting the remaining elements to its beginning.

    Note 1: You should use the remove_if() standard method, which removes elements from the container that pass a specified test:

    auto newEnd = std::remove_if(a.begin(), a.end(), [](int n)
    	{
    		return // some test;
    	});

    Note 2: To delete the elements from the vector you can use the erase() standard method.

    Expected output:

    task 8
    before task:
    0 1 2 3 4 42 6 7 8 422
    after task:
    0 2 4 42 6 8 422
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5ExTask3header.h, L5ExTask3imp.cpp, L5ExTask3main.cpp]

    *ExTask 4:

    To do: A vector of size N and an integer K (0 ≤ K < N) are given. Remove the element with K index from the vector by shifting all the following elements one position to the left and decreasing the vector size by one.

    Note 1: To check the index you can use the following construction:

    if(index < 0 || index > size)
            throw "Incorrect index!";

    Note 2: To delete the elements from the vector you can't use the erase() standard method.

    Expected output:

    task 9
    enter the index to delete
    >>> 2
    before task:
    1 2 3 4 5 6 7 8 
    after task:
    1 2 4 5 6 7 8
    

    [Solution and Project name: Lesson_5
    you can have individual files: L5ExTask4header.h, L5ExTask4imp.cpp, L5ExTask4main.cpp]

    Lesson # 4. Enumerations

    Theory

    Enumerations

    The enum type declaration can be in the .cpp file at the top of the code (that is, outside of the functions), as well as in the header files.

    int main()
    {
      enum MyType { A, B, C }; // A=0 B=1 C=2
      enum YourType { D = 2, E, F = 0 }; // E=3
      MyType m = A;
    }
    Each enumerator is associated with a value of the underlying type. When initializers are provided in the enumerator-list, the values of enumerators are defined by those initializers. If the first enumerator does not have an initializer, the associated value is zero. For any other enumerator whose definition does not have an initializer, the associated value is the value of the previous enumerator plus one.
    Enumerations in style of C++11:
    int main()
    {
      enum class Color { Red, Green, Blue };
      Color c = Color::Blue;
    }

    One more example:

    enum Color { red, green, blue };
    Color r = red;
    switch(r)
    {
        case red  : std::cout << "red\n";   break;
        case green: std::cout << "green\n"; break;
        case blue : std::cout << "blue\n";  break;
    }
    // int n = r; // error: no scoped enum to int conversion
    int n = static_cast<int>(r); // OK, n = 0

    Type conversion by static_cast

    Sample 1:

    char c = 97;
    std::cout << static_cast<int>(c) << std::endl; // output 97, but not 'a'

    Sample 2:

    int i1 = 11;
    int i2 = 3;
    std::cout << i1/i2; // 3
    float x = static_cast<float>(i1) / i2;  // output x = 3.66667

    Labs and tasks

    All the tasks that you did not have time to complete in class automatically become your homework. The homework must be completed before the next lesson.

    Follow the rules:

    • To do the tasks, you must create a Visual Studio project: Lesson_4. When the tasks are done, it is necessary to upload the Lesson_4 project files (e.g. L4Task1Imp.cpp, L4Task1header.h and L4Task1main.cpp).
    • To do the tasks, you should use such C ++ structures as enumerations and switch statement.
    • All tasks must be done using functions, the results should be checked by assert statement from the header file , calling them from main with different arguments.
    • All functions and files must be accompanied by comments that describe the task.
    Lab 1:

    To do: Create a function (named printDay) that gets the number
    — the day of the week (from 1 to 7) and returns the full name of the corresponding day (if 1 is entered, so function must print «Monday», if 2«Tuesday», etc.)

    Note: Add a header file to your project. Type there a declaration of the enumeration and the signature of your method:

    // enum type for representing a day: MON for Monday, etc.
    enum Day {MON=1, TUE, WED, THE, FRI, SAT, SAN };
     
    // prints given day to the standard output
    void printDay(Day d);

    Expected output:

    please enter the number of a day of a week:
    >> 2
    Tuesday
    

    [Solution and Project name: Lesson_4, file name L4Lab1Imp.cpp, L4Lab1main.cpp, L4Lab1header.h]

    ✍ Algorithm:

    1. Open Microsoft Visual Studio. Create a new console project, name your project Lesson_4. Among the Additional options mark Empty project and nothing more. Click Finish button.
    2. In the Solution Explorer window find a Source files folder, click the right mouse button on it and select Add -> New Item. We’re going to create two .cpp files. Call them as it is written in this lab description.
    3. In the Solution Explorer window find a Header files folder, click the right mouse button on it and select Add -> New Item. We’re going to create .h file. Give it a name as it is written in this lab description.
    4. First, let’s define an enumeration to store the names of the week days. The definition must be placed inside the header file. So, open header file and add the code:
    5. #ifndef L4LAB1HEADER_H
      #define L4LAB1HEADER_H
      // type for representing a day of a week
      enum Day { MON = 1, TUE, WED, THE, FRI, SAT, SAN };
      
      #endif L4LAB1HEADER_H
      
    6. Add the definition of our function printDay(). It must accept one parameter – the number of the day of a week (the type of parameter is Dayenum). The function definition must be placed inside the header file too:
    7. // prints given day to the standard output
      void printDay(Day);
      
    8. Open the code of L4Lab1Imp.cpp, we’re going to create an implementation of our function. Include the header file and std namespace:
    9. #include <iostream>
      #include <cassert>
      #include "L4Lab1header.h"
      using namespace std;
      
    10. Add a signature of your function:
    11. // prints given day to the standard output
      void print_month(Day d) {
        // ...
      }
      
    12. To check the day number we need to use Switch statement. Add the code inside the function scope:
    13. switch (d)
      	{
      	case 1:
      		std::cout << "Monday" << std::endl;
      		break;
      	case 2:
      		std::cout << "Tuesday" << std::endl;
      		break;
      	case 3:
      		std::cout << "Wednesday" << std::endl;
      		break;
      	case 4:
      		std::cout << "Thursday" << std::endl;
      		break;
      	case 5:
      		std::cout << "Friday" << std::endl;
      		break;
      	case 6:
      		std::cout << "Saturday" << std::endl;
      		break;
      	case 7:
      		std::cout << "Sunday" << std::endl;
      		break;
      	}
      
    14. Open the L4Lab1main.cpp. Include the header file and needed libraries:
    15. #include <iostream>
      #include <cassert>
      #include "L4Lab1header.h"
      using namespace std;
      
    16. Inside the main function ask user to enter an integer and assign the value to dayNumb variable.
    17. int dayNumb;
      cout << "please enter the number of a day of a week:";
      cin >> dayNumb;
      
    18. To call the function we need to pass it one parameter of our enumeration type (Day type). But all we have is dayNumb variable of integer type. We can use static_cast to convert the variable to Day type:
    19. Day d;
      d = static_cast<Day>(dayNumb);
      
    20. Now we can call a function:
    21. printDay(d);
      
    22. Run the program and check the output.
    Task 1:

    To do: Define a Month enumeration data type to represent the month.
    Create a function (named printMonth()) that will display the full month name for the passed short month name. Use a switch statement.

    Note 1: Create another function (named inc()) that displays the next month for the passed short month name.

    Note 2: add the header file. Inside the file add the enum and your function declaration:

    // type for representing a month: JAN for January, etc.
    enum Month {JAN=1, FEB, MAR, /* TODO: ... */ DEC};
    // prints given month to the standard output
    void printMonth(Month m);
    // return next month
    Month inc(Month m);

    Note 2: Look at the code below and puzzle it out (using static_cast):

    (m == DEC)? JAN: static_cast<Month>(m + 1);
    // Test this function from the main:
     assert (JAN == inc (DEC));

    Expected output:

    Full name for JUN is: June
    The next month for DEC is: 1

    [Solution and Project name: Lesson_4, file name L4Task1Imp.cpp, L4Task1main.cpp, L4Task1header.h]

    Task 2:

    To do: Within the previous task create a function (named dec()) that, for the entered month, displays the preceding month.

    Note 1: Test this function from main:

    assert (JAN == dec (FEB));

    Note 2: Add the declaration into the header file:

    // return previous month
    Month dec(Month m);

    Expected output:

    Full name for JUN is: June
    The previous month for JUN is: 5

    [Solution and Project name: Lesson_4, file name L4Task2Imp.cpp, L4Task2main.cpp, L4Task2header.h]

    Task 3:

    To do: {2 points} Create function of Boolean type that returns True (or 1) if the year (positive integer) is a leap year, and False (or 0) otherwise.

    Note 1: A leap year is a year that is divisible by 4, except for those years that are divisible by 100 and not divisible by 400.
    Note 2: Add some tests to the main function. 2000 and 2012 are leap years, 2100 is a common year.

    Note 3: Add the declaration into the header file:

    // check if given year is leap
    bool is_leap(int);

    Expected output:

    please enter the year:2000
    year is leap - 1

    [Solution and Project name: Lesson_4, file name L4Task3Imp.cpp, L4Task3main.cpp, L4Task3header.h]

    Вставить формулу как
    Блок
    Строка
    Дополнительные настройки
    Цвет формулы
    Цвет текста
    #333333
    Используйте LaTeX для набора формулы
    Предпросмотр
    \({}\)
    Формула не набрана
    Вставить