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]

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 2:

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 2:
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_8task2, file name L8Task2main.cpp, L8Task2imp.cpp, L8Task2.h]

Task 3:

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 3:
matrix:
8 3 3 6
6 4 9 8
6 1 9 6
4 5 1 5

sum = 26

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 # 12. 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

    • 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.
    • 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.
    Task 0:

    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:

    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.
    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]

    Lesson # 3. Arguments by Reference

    Theory

    Note about for loop

    The for loop allows you to use several counters: the initialization and increment sections can contain several operators separated by the «,» (comma) operator

    int a = 0, b = 0;
    for (a = 1, b = 8; a < b; ++a, --b) {
        // empty body
    }
    cout << a << " " << b << endl; // output 5   4

    References

    References are not objects; they do not necessarily occupy storage; references are the other name of the variable:
    sample 1:

    int i = 5;
    int &pi = i;   // reference to i
     
    pi = 3;
    cout << i;     // i == 3

    sample 2:

    void double_numb(int &numb) {
    	numb *= numb; // 'numb' is the same as main()'s 'x'
    }
    void main(){
    int x = 2;
    	double_numb(x);
    	cout << x << '\n';
    	system("pause");
    }

    Sample 3. Passing an argument to a function by reference:

    void calcSquareAndPerimeter(double a, double b, double &S, double &P) {
        S = a * b;
        P = 2 * (a + b);
    }
     
    int main() {
        double SS = 0.0, PP = 0.0;
        calcSquareAndPerimeter(3.0, 4.0, SS, PP);
        cout << "Perimeter: " << PP << ", Square: " << SS << "\n";
    }

    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.
    • Create an empty application with a name Lesson_3. All the tasks and labs must be done within this application.
    • It means that all tasks must be done within the same header and source files. But you should put comments with the task number and explanation of what to do.
    • Every task has to be done using user functions. For example, if the task is to find the sum of a sequence of 5 entered numbers, you must create a function within .cpp file to do this task:
    • header.h:

      1
      2
      3
      4
      5
      6
      
      #ifndef HEADER_H
      #define HEADER_H
      // task 1
      // function to calculate the sum of 5 enterered numbers
      int sumSeq();
      #endif

      imp.cpp:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
      #include <iostream>
      #include "header.h"
      using namespace std;
       
      // function to calculate the sum of 5 enterered numbers
      int sumSeq() {
      	cout << "enter a sequence"<<endl;
      	int numb;
      	int sum = 0;
      	for (int i = 0; i < 5; i++) {
      		cin >> numb;
      		sum += numb;
      	}
      	return sum;
      }

      main.cpp:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      
      #include "header.h"
      #include <iostream>
      using namespace std;
      void main(){
              // task # 1
              // craeate a function to calculate a sum of 5 entered numbers
      	int result = sumSeq();
              cout << "task 1" << endl;
      	cout << result;
      	system("pause");
      }
    • Try to pass arguments of the functions by reference (in the tasks where it is needed).
    For loop:
    Task 1:

    To do: Create a function to output the sequence: -3 0 3 6 9 12 15 18 21 24. Make the task with FOR loop. An iterator of the loop has a step equaled 3.

    Note 1: To make a step equal to 3 see syntax:

    for ([initializers]; [condition]; [iterator]) 

    instead of the iterator you’ll have the variable counter += 3

    Note 2: The signature of the function must be void printSeq(int & a, int & b), where a = -3 and b = 24.

    Note 3: Don’t forget to use assert statement to check if the boundary b is greater than a.

    #include <cassert>

    Expected output:

    The sequence: -3 0 3 6 9 12 15 18 21 24

    [Solution and Project name: Lesson_3 files: header.h, imp.cpp, main.cpp]
    // task 1

    or files: L3Task1header.h, L3Task1imp.cpp, L3Task1main.cpp
    Task 2:

    To do: 10 integers are entered. Create a function (findPosNeg) to output the quantity of positive and negative among them.

    Note 1: Create for loop to input the numbers (they must be entered). Within the loop, check each number whether it is positive or negative. Use two counters for calculations.

    Note 2: The signature of the function must be:

    void findPosNeg(int & pos, int & neg){
      //TODO
    }

    Expected output:

    enter 10 numbers:
    1  -5  -12   2   3   9   -1  9   5   -8    
    counter_positive = 6, counter_negative = 4

    [Solution and Project name: Lesson_3 ]
    // Task 2

    Task 3:

    To do: Create a function to calculate the addition of the following sequence: 1 + 3 + 5 + 7 + 9 + 11 + 13 + 15 + 17 + 19 (numbers are NOT entered, they must be created using a loop). The first number (1) and last number (19) of the sequence must be parameters of the function passed by reference.

    Note: To calculate the addition, use a variable named sum.

    Expected output:

    the sequence:
    1 + 3 + 5 + 7 + 9 + 11 + 13 + 15 + 17 + 19   
    sum = 100
    

    [Solution and Project name: Lesson_3 ]
    // Task 3

    Task 4:

    To do: For each x changing in the interval [x1;x2] (x1 and x2 values are entered), calculate the value of the function z(x,y) = xy. The variable y changes in the interval [y1;y2] (y1 and y2 values are entered). You must create a function.

    Note 1: Create two for loops (nested loop): one loop within the other. Variable x has to be modified in the outer loop; variable y has to be modified in the inner loop.

    Note 2: To output the power of a number, use pow function and #include<cmath> directive:

    f = pow(base number, exponent);

    Note 3: Don’t forget to use the assert statement to check the boundaries (x2>x1 and y2>y1).

    Expected output:

    enter x1 and x2:
    >>>2 >>>8
    enter y1 and y2:
    >>>2 >>>4
    z(x,y) = 2^2 = 4
    z(x,y) = 2^3 = 8
    z(x,y) = 2^4 = 16
    z(x,y) = 3^2 = 9
    z(x,y) = 3^3 = 27
    z(x,y) = 3^4 = 81
    z(x,y) = 4^2 = 16
    z(x,y) = 4^3 = 64
    z(x,y) = 4^4 = 256
    z(x,y) = 5^2 = 25
    z(x,y) = 5^3 = 125
    z(x,y) = 5^4 = 625
    ... etc.

    [Solution and Project name: Lesson_3 ]
    // task 4

    While loop:
    Task 5:

    To do: Create a function to output the sequence 15 12 9 6 3 0 (from 15 down to 0 with a step = -3). Use while loop.

    Note: The signature of the function must be:

    void printSeqTask5(int & a, int & b){}

    Where a = 15 and b = 0

    Expected output:

    the sequence:
    15 12 9 6 3 0
    

    [Solution and Project name: Lesson_3 ]
    // task 5

    Task 6:

    To do: Create a function to calculate a multiplication of 2-digit even integers in the interval [10;20] (10 * 12 * 14 * 16 * 18 * 20). You have to do the task using a while loop.

    Note 1: To calculate a multiplication you should use a variable with the name product. Don’t forget to inisialize the product variable with 1.

    Note 2: The signature of the function must be:

    void findMult(int & a, int & b, int & prod){}

    where a = 10 and b = 20

    Expected output:

    10 * 12 * 14 * 16 * 18 * 20  
    the product: 9676800

    [Solution and Project name: Lesson_3 ]
    // task 6

    Task 7:

    To do: Two two-digit integers are entered. Create a BitwiseSum() function that computes their bitwise sum modulo 10. For example, the bitwise sum of the numbers 34 and 59 is the number 83 (3 + 5 = 8; 4 + 9 = 13; 13%10 = 3).

    Note: The BitwiseSum() method must accept three integers as arguments passed by reference (two numbers and sum).

    Expected output:

    Please enter two two-digit numbers:
    >>> 34   >>> 59
    The bitwise sum of 34 and 59 is: 83

    [Solution and Project name: Lesson_3 ]
    // task 7

    Task 8:

    To do: A sequence of integers is given (it is entered). The last element of the sequence is 0. Calculate the addition of all positive elements of this sequence and the number of its negative elements. While loop must be used.

    Note 1: In the task, you should use the endless loop with an exit from the middle:

    while (true)
    	{
    		// TODO something
    		if (num == 0)
    			break;
     
                    // TODO something
            }

    Note 2: To return two values from the function you should use function parameters by reference (&):

    void sumPosCountNeg(int & pos_sum, int & neg) {}

    Expected output:

    Please enter the sequence, the last element is 0:
    >>> 3   5   -1   2  -3   0
    The sum of positive numbers is: 10
    The number of negatives is: 2
    

    [Solution and Project name: Lesson_3 ]
    // task 8

    Task 9:

    To do: A sequence of integers is given (it is entered). The last element of the sequence is 0. Find minimum and maximum elements. A While loop must be used.

    Note 1: In the task, you should use the endless loop with an exit from the middle:

    while (true)
    	{
    		// TODO something
    		if (num == 0)
    			break;
                    // TODO something
                    //
            }

    Note 2: To return two values from the function you should use function parameters by reference (&):

    void minMax(int &min, int &max) {}

    Note 3: You should use INT32_MAX and INT32_MIN initial values for min and max variables.

    Expected output:

    Please enter the sequence, the last element is 0:
    >>> 3   5   -1   2  -3   0
    The minimum is: -3
    The maximum is: 5
    

    [Solution and Project name: Lesson_3 ]
    // task 9

    EXTRA TASKS

    ExtraTask 1 (while loop):

    To do: An integer is given. Find the number of its digits and their sum.

    Note: The function signature should look like this:

    void digitsCountAndSum (int n, int& count, int& sum)

    Expected output:

    Enter number: 
    >>> 12345
    The number of digits = 5, the sum = 15

    [Solution and Project name: Lesson_3, files: L3ExTask1header.h, L3ExTask1main.cpp, L3ExTask1imp.cpp]

    ExtraTask 2 (passing parameters by reference):

    To do: An integer N and a set of N positive real numbers are given. Calculate the sum of all integer parts, as well as the sum of all fractional parts of the sequence. Some of the standard header functions may be helpful.

    Expected output:

    Enter N: 
    >>> 4
    12,4  11,7  8,5  1,1
    Sum of integer parts is: 32 
    Sum of fractional parts is: 1.7

    [Solution and Project name: Lesson_3, files: L3ExTask2header.h, L3ExTask2main.cpp, L3ExTask2imp.cpp]

    Hometasks

    For loop

    Hometask 1:

    To do: 10 real numbers are input. Create a function to output the multiplication of the entered numbers.
    Note 1: Create for loop to input the numbers. To calculate the multiplication, use a variable named product.
    Note 2: Don’t forget to initialize the product variable with a double type value.

    double product = 1.0; 

    Expected output:

    1,1  2,4  5,1  7,2  6,4  8,1  6,7  3,2  3,3  2,4  
    product = 853338,921998746

    [Solution and Project name: Lesson_3, files: L3HomeTask1header.h, L3HomeTask1main.cpp, L3HomeTask1imp.cpp]

    Hometask 2:

    To do: For each x changing in the interval [30;33], calculate the value of the function z(x,y) = x - y. The variable y changes in the interval [1;5]. You must create a function.

    Note: Create two for loops (nested loop): one loop within the other. The variable x has to be modified in the outer loop; the variable y has to be modified in the inner loop.

    Expected output:

    z(x,y) = 30-1=29
    z(x,y) = 30-2=28
    z(x,y) = 30-3=27
    z(x,y) = 30-4=26
    z(x,y) = 30-5=25
    z(x,y) = 31-1=30
    ... etc.

    [Solution and Project name: Lesson_3, files: L3HomeTask2header.h, L3HomeTask2main.cpp, L3HomeTask2imp.cpp]

    While loop
    Hometask 3:

    To do: Create a function to output the sequence 3 5 7 9 ... 21 (from 3 to 21 with a step = 2).

    Note: the signature of the function must be void seq(int & a, int & b), where a = 3 and b = 21.

    Expected output:

    3 5 7 9 11 13 15 17 19 21

    [Solution and Project name: Lesson_3, files: L3HomeTask3header.h, L3HomeTask3main.cpp, L3HomeTask3imp.cpp]

    Hometask 4:

    To do: 5 real numbers are input. Create a function to calculate an addition (sum) of entered numbers. Make the task using a while loop.

    Note: Double type must be used for real numbers and for variable sum:

    double sum = 0;
    double numb;

    Please enter 5 numbers and press Enter

    1.1 4.2 2.1 9.3 2.5
    The sum of inputted numbers = 19.2

    [Solution and Project name: Lesson_3, files: L3HomeTask4header.h, L3HomeTask4main.cpp, L3HomeTask4imp.cpp]

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

    Theory

    Standard functions

    The math functions are declared in the header file:

    #include <cmath>
    abs(x);  
    floor(x);  
    sin(x);  
    pow(x, y);  
    sqrt(x);

    User functions

    sample 1:

    //...
    int abs(int x) {
    	return x > 0 ? x : -x;  // exit the function
    }
    int main() {
    	cout << abs(-35); // 35
    	system("pause");
    	return 0;
    }

    The abs function returns integer value and have got single integer x parameter.

    sample 2:

    //...
    void print(int i) {
    	cout << "value = " << i;
    }
    int main() {
    	print(40);
    	system("pause");
    	return 0;
    }

    The print function returns no value and have got single integer i parameter. We can call it procedure (because it doesn’t return value).

    Encapsulation

    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.
    • Private members cannot be accessed by client code (only used within the functions themselves).

    In C++, the interface (.h file) to the function is defined separately from the implementation (.cpp file).

    Multi-file layout

    To make an application, you usually need to create 3 files: header file (.h), implementation file (.cpp), and main file (.cpp).

    • A header file (.h) defines the interface to functions, that is declaration(s) of the function(s)
    • Implementation .cpp file contains all of the logic of the functions or methods. Header .h file must be included here.
    • Main .cpp file contains of the main function, the starting point of all C++ programs, and here header .h file also need to be included.

    Let’s look at the example of 3 files of single application.
    Sample header file (tasks.h):

    #ifndef TASKS_H
    #define TASKS_H
    //calculates a triangle perimeter 
    double perimeter(double, double, double);
    #endif TASKS_H

    Sample implementation file (.cpp):

    #include "tasks.h"
    //calculates a triangle perimeter 
    double perimeter(double a, double b, double c)
    {
    	//TODO
    }

    Sample main file (.cpp):

    #include <iostream>
    #include "tasks.h"
    using namespace std;
    void main()
    {
    	//prompt user to enter data 
    	//call the function
    	//print out the result
    	system("pause");
    }
  • The.cpp files make requests to include various header files.
  • Then, the cpp file with all of its extra included content will be compiled into object file. (a file has a .o extension, that is an object file.) Each cpp file is separately compiled into an object file.
  • 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.
    Lab 1:

    To do: Create an application to find the volume and surface area of a cube. The length of the cube side is given (it is entered).
    Note: Three solutions must be presented: 1) Without using functions and multi-file application, 2) Using functions, 3) Creating a multi-file application.

    Expected output:

    Please enter the cube side length: 3.48
    Volume: 42.1442
    Surface area: 72.6624

    [Solution and Project name: Lesson_2Lab1, files’ names HeaderL2Lab1.h, ImpL2Lab1.cpp, MainL2Lab1.cpp]

    ✍ How to do:

    1. Open Microsoft Visual Studio. Select menu item File -> New project. In the Template region find C++ and then, Win32 Console Application.
    2. Create a new console project, name your project Lesson_2Lab1. Among the Additional options mark Empty project and nothing more must be marked. Click Finish button.
    3. 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 ImpL2Lab1.cpp – implementation file and MainL2Lab1.cpp – file with a main function.
    4. Now, find a Header files folder, click the right mouse button on it and select Add -> New Item. We’re going to create .h file, and give it a name HeaderL2Lab1.h.
    5.   
      1) Without using functions and multi-file application:

    6. First, we’re going to make this task without functions and encapsulation. So, we should set the cube side length value, and calculate the cube volume and surface area.
    7. Declare a variable of type double for length and set a value for it. Don’t forget to include iostream header, since we’re going to read/write to the console:
    8. #include <iostream>
      int main() {
      double length;
      	std::cout << "please enter the cube side length: ";
      	std::cin >> length;
      	// …
      }
      
    9. To prevent console window from closing, you should use pause. The main function must return 0:
    10. //…
         system("pause");
         return 0;
      }
      
    11. Declare variables for the cube volume and surface area. Calculate the values for them:
    12. 	double volume = length * length * length;
      	double surfaceArea = 6 * length * length;
      
    13. After, you can print out the result to the console:
    14.    std::cout << "Volume: " << volume << std::endl;
         std::cout << "Surface area: " << surfaceArea << std::endl;
      
    15. Run the application and check the output.
    16.  
      2) Using functions:

    17. We’re going to modify our application creating methods to calculate the values of volume and surface area.
    18. Find the lines with the variables declarations and calculations and comment them out:
    19. //double volume = length * length * length;
      //double surfaceArea = 6 * length * length;
      
    20. Let’s create a method named getVolume to calculate a cube volume. It must return double type, since the cube side length is also of double type. Before the method signature you should define the method. You must add the code before the main function:
    21. double getVolume(double length);
      double getVolume(double length)
      {
      	return length * length * length;
      }
      int main() {
          //…
      
    22. Place the declaration of the length inside the main function:
    23. int main() {
      	double length;
      
    24. Create a method named getSurfaceArea to calculate a cube surface area. It must be of double type too. Place the code before the main function:
    25. double getSurfaceArea(double length);
      double getSurfaceArea(double length) {
      	return 6 * length * length;
      }
      
    26. The compiler doesn’t run functions until we call them. Therefore, you must call your methods. Now you can use the variables to store the function returning results. Place the code inside the main function:
    27. double volume = getVolume(length);
      double surfaceArea = getSurfaceArea(length);
      
    28. Run the application and check the output. The results must be as they were.
    29. 3) Creating a multi-file application

    30. We’re going to modify our application creating a multi-file one.
    31. In the Solution Explorer window select (mouse double click) the header file you created (HeaderL2Lab1.h). Inside the code editor window, you must add your method declarations only (you can cut them from your main file and paste here):
    32. #pragma once
      // calculates a cube volume
      double getVolume(double length);
      // calculates a cube surface area
      double getSurfaceArea(double length);
      
      — Notice in this .h file we have not defined how getVolume works, how getSurfaceArea works. All we’ve done is declare that these are the functionalities of our program. We need to look at our .cpp file to find out how they actually work.
      — This pragma once line instructs the compiler to only compile this code once. Even if multiple people use our class, we’ll only want the definition of our methods to be defined exactly once.
      — Note that you should always place the comments before each function.
    33. In the Solution Explorer window select (mouse double click) the implementation file you created (ImpL2Lab1.cpp). Inside the code editor window, you must add your method functionalities (cut them from the main file and paste here). And don’t forget to include the header file first:
    34. #include "HeaderL2Lab1.h"
      double getVolume(double length)
      {
      	return length * length * length;
      }
      double getSurfaceArea(double length) {
      	return 6 * length * length;
      }
      
      — We call this file the implementation file and it’s the code that contains all of the logic to implement our methods.
      — We have a pound (#) include that includes a reference to our header.
      — We have the implementation of our two functions that were defined in our .h file.
    35. Now, we can go ahead and clear up the parts of a code we don’t need anymore within the main function. So, this is what you have in your MainL2Lab1.cpp:
    36. #include <iostream>
      #include " HeaderL2Lab1.h"
      int main(){
      	double length;
      	std::cout << "please enter the cube side length: ";
      	std::cin >> length;
              //double volume = length * length * length;
      	//double surfaceArea = 6 * length * length;
      	double volume = getVolume(length);
      	double surfaceArea = getSurfaceArea(length);
      	std::cout << "Volume: " << volume << std::endl;
      	std::cout << "Surface area: " << surfaceArea << std::endl;
      	system("pause");
      	return 0;
      }
      
    37. Run the application and check the output. The results must be as they were.
    38. Three files must be uploaded to the moodle system: HeaderL2Lab1.h, ImpL2Lab1.cpp, MainL2Lab1.cpp.

    Notes on all tasks

  • To make the following tasks you’ll need 3 files: tasks.h, tasks.cpp, main.cpp. Download them and place them into the Lesson_2Lab1 folder.
  • When all the tasks you intended to do have been completed, upload those three files to the moodle.
  • [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 0:

    To do: Create a Sum() method that takes two integer arguments and sums them. The method returns the result of integer type.

    Note: You need to create the method declaration in the tasks.h file by yourself, and also the method implementation must be written in the tasks.cpp file. Call the function within the main.cpp. Don’t forget to use the comments to explain the purpose of the method.

    Expected output:

    Please, enter two numbers
    20 40 
    The sum of 20 and 40 is: 60
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 1:

    To do: Ask user to enter the lengths of the three sides of the triangle. Create a method named perimeter that calculates the perimeter of a triangle from the lengths of its three sides.

    Note: Three files must be used to complete the task. Check the code of the files and fill in the places marked as // TODO related to this task.

    Expected output:

    please enter three numbers for the triangle three sides: 3.0  4.1  5.0
    the perimeter is: 12.1
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 2:

    To do: Ask user to enter the lengths of the three sides of the triangle. Create a method named areaFromSides that calculates the area of a triangle by the lengths of its three sides using Heron’s formula:

    where p stands for semi-perimeter.

    Note 1: Three files must be used to complete the task. Check the code of the files and fill in the places marked as // TODO related to this task.

    Note 2: To calculate a square root the math libtary is needed to be included and sqrt() function:

    #include <cmath>

    Expected output:

    please enter three numbers for the triangle three sides: 
    2 4 5
    the area is: 
    6
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 3:

    To do: Ask user to enter the coordinates of triangle vertices ((x1,y1); (x2,y2); (x3,y3)). Create a method named areaFromPos that calculates the area of a triangle using the coordinates of its vertices.

    Note 1: Three files must be used to complete the task. Check the code of the files and fill in the places marked as // TODO related to this task.

    Note 2: The math libtary is needed:

    #include <cmath>

    Expected output:

    please enter six numbers for the coordinates of the triangle vertices:
    4 6 2 9 1 7
    the area is: 3
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 4:

    To do: Ask user to enter the coordinates of two points. Create a function named dist that calculates the distance between two points on the plane, using their coordinates. [sqrt].

    Note: Formula to calculate the distance between two points:

    Note: To check to see if your result is right you can calculate the distance in the wolframalpha service. For example, to find the distance between points (1, -2) and (4, 2), use command distance ({1, -2}, {4, 2}).

    Note: Three files must be used to complete the task. Check the code of the files and fill in the places marked as // TODO related to this task.

    Expected output:

    Please enter the coordinates of two points (four integers: x1, y1, x2, y2):
    1 -2  4  2
    The distance is: 5
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 5:

    To do: Create GetPow() method that takes two integer arguments, they are base number and power number. The method returns the result of taking a base number to power number.

    Note: Three files must be used to complete the task. Check the code of the files and fill in the places marked as // TODO related to this task.

    Expected output:

    Please enter two numbers – a base number and a power number:
    2  4 
    Base number 2 raised to the power number 4 = 16
    

    [Solution and Project name: Lesson_2Lab1, files’ names tasks.h, tasks.cpp, main.cpp]

    Task 6:

    To do: Define Mean(X, Y) function that calculates the arithmetic mean and geometric mean ((√X*Y)) of two positive decimal numbers X and Y. X and Y are input parameters. The function must not return any values, it has to print the results out to the console window.

    Note: You can use the standard function to calculate the square root of a number (sqrt()). But you need to include a math library:

    #include <cmath>

    Note: To print out the floating point number with 3 digits after the point, you should use the following function:

    printf("%.3f ",result)

    Expected output:

    please enter two numbers: 
    
    <<15.0  <<4.0
    arithmetic mean: 9.500
    geometric mean: 7.746
    

    [Solution and Project name: Lesson_2Task6, files’ names task6.h, task6.cpp, main6.cpp]

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