Quick Start to Little Turtle C++ Day 7

Video 33 - Dynamic Memory Allocation

Static memory

The memory space used to complete its tasks is fixed and can not be dynamically increased or reduced during the running of the program.

Dynamic memory

Dynamic memory consists of nameless, address-only memory blocks that are dynamically allocated during program execution [the main difference from static memory]. They come from a large pool managed by a standard C++ library for you (the term "memory pool"). Requesting some memory from the pool requires a new statement, which allocates a suitable size of memory according to the type of data you provide.

When using dynamic memory, the most important principle is that every new statement must have a delete statement that matches it, otherwise it will lead to memory leaks.

The delete statement only releases the memory block pointed to by the given pointer variable without affecting the pointer. After executing the delete statement, the memory block is released, but the pointer variable still exists. So for general insurance, i = NULL needs to be set

#include <iostream>
using namespace std;
#include <string>

//// Base Class
class Company
{
public:
    //constructor
    Company(string theName);
    //Method
    virtual void printInfor();//Print information

protected:
    string name;
};
//Base Class Constructor Implementation
Company::Company(string theName)
{
    name = theName;
}
//Base Class Method Implementation
void Company::printInfor()
{
    cout << "The company's name is:" << name << endl;
}
//// Subclass
class TechCompany:public Company
{
public:
    //constructor
    TechCompany(string theName, string product);
    //Method
    void printInfor();//Print information
private:
    string product;
};
//Constructor implementation
TechCompany::TechCompany(string theName, string product):
            Company(theName)
{
    this->product = product;
}
//Method Realization
void TechCompany::printInfor()
{
    cout << name << "The company produced it." << product << "\n\n";
}


int main()
{
    Company *company = new Company("Apple");
    company->printInfor();

    delete company;//Delete pointer address
    company = NULL;//Empty the address pointed to by the pointer

    company = new TechCompany("APPLE", "IPHONE");
    company->printInfor();
    delete company;//Delete pointer address

    return 0;
}

Video 34 - Dynamic Array

Although the basic types and objects are allocated memory at runtime with new as mentioned earlier, their sizes are determined at compile time - because the data types we apply for memory for are clearly defined in the program and have a clear unit length; sometimes, they have to wait until the program runs. How much memory should be applied for, and even more memory should be applied according to the operation of the program. For example: int *x = new int[10];//x denotes the array name of an integer array

Delete dynamic arrays

#include <iostream>
#include <string>
using namespace std;

int main()
{
    unsigned int count = 0;

    cout << "Enter the number of elements in the array:" << '\n';
    cin >> count;
    //The application is made only when the program is running, not when it is compiled, so it is called dynamic.
    //Apply in the stack, not in the stack.
    int *x = new int[count];
    //Array assignment
    for(int i = 0; i< count; i++)
    {
        x[i] = i;
    }
    //Output Printing
    for(int i = 0; i< count; i++)
    {
        cout << "x[" << i << "] = " << x[i] << endl;
    }

    return 0;
}

PS: (1) Dynamic arrays: applications are made when the program is running, not when it is compiled, so they are called dynamic; applications are made in the heap, not in the stack [general local variables are applied in the stack].

Video 35 - Return memory from functions or methods

Basic idea: Call the new statement in the function to allocate a memory for an object or a basic data type, and return the address of that memory to the main code of the program. The main code will use that memory and release delete immediately after the operation is completed.

#include <iostream>
using namespace std;

int *newInt(int value)
{
    int *myInt = new int;
    *myInt = value;

    return myInt;
}

int main()
{
    int *x = newInt(20);
    cout << *x;

    delete x;
    x = NULL;

    return 0;
}
#include <iostream>
using namespace std;

void swap(int *x,int *y)
{
//Never be executed; if you want to execute, change 0 to 1
#if 0
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
#endif
    //^ XOR operator
    *x ^= *y;
    *y ^= *x;
    *x ^= *y;
}

int main()
{
    int a,b;
    a = 3;
    b = 5;

    swap(&a,&b);

    cout << "a = " << a
         << ", b = " << b << endl;

    return 0;
}

PS:"#if 0........................ # endif statement function and "/*.............................." */” Same.

Function Pointer-Pointer Function

Function pointer: A pointer variable that points to the first address of a function is called a function pointer.

Pointer function: A function can bring back the value of an integer data, the value of a character type and the value of a real type, and the data of a pointer type to point to an address unit.

/**< Function pointer */
#include <stdio.h>

int fun(int x,int y)
{
    int z;

    z = (x > y)? x:y;
    return z;
}

int main()
{
    int i,a,b;
    //Declare function pointers
    //How a function declares parameters [type, number], then the function pointer should declare parameters, otherwise it will make mistakes.
    int (*p)(int,int);
    p = fun;//Assign a function pointer p to function fun

    printf("Please enter 10 numbers:\n");

    scanf("%d", &a);
    for(i = 0; i< 9; i++)
    {
        scanf("%d", &b);
        a = (*p)(a,b);//Call pointer function fun through pointer p
    }
    printf("The Max number is %d.", a);

    return 0;
}

PS: How a parameter variable of a function pointer is declared depends on how the corresponding function parameter variable is declared, including the type and number of parameter variables. eg: In the above program, the function is declared as int fun(int x,int y); then the function pointer is declared as int (*p)(int,int); not int (*p)();

/**< Pointer function */
#include<iostrem>
using namespace std;

//Declare a pointer function and return an address
int  *newInt(int value)
{
    int *myInt = new int;
    *myInt = value;
    
    return myInt;
}


int main()
{
    //Create a new integer variable space and point the x pointer to it
    int  *x = newInt(20);
    
    cout << *x;
    delete x;
    x = NULL;

    return 0;
}

Video 36 - Copy Constructor

We can assign an object to a variable of the same type, and the compiler will generate the necessary code to assign the values of the attributes of the "source" object to the corresponding members of the "target" object. This assignment behavior is called bit-by-bit replication. (But if some member variables are pointers, the result of object member-by-object replication is that you will have two identical instances in which the same name pointer points to the same address.)

/**< Equivalent overloading with pointer variables */
#include <iostream>
using namespace std;

class MyClass
{
public:
    //constructor
    MyClass(int *p);
    //Destructor
    ~MyClass();

    //Operator "=" Overload
    MyClass &operator = (const MyClass &rhs);
    void print();

private:
    int *ptr;
};
//Constructor implementation
MyClass::MyClass(int *p)
{
    ptr = p;
}
//Destructor implementation
MyClass::~MyClass()
{
    delete ptr;
}
//Operator (=) overloads implementation, rhs is another object
MyClass &MyClass::operator=(const MyClass &rhs)
{//When obj1 is not equal to obj2, this pointer refers to the object generated by the current class (in this case, the first MyClass)
    if(this != &rhs)
    {
        delete ptr;//Delete the address ptr and release the memory of obj1

        ptr = new int;//Create new memory for pointer ptr
        *ptr = *rhs.ptr;//Dereference, assigning the value of obj2 to obj1
    }
    else
    {
        cout << "Assignment number is the same object on both sides, do not deal with it!\n";//When obj1 = obj2
    }
    return *this;//Returns the first MyClass object
}
void MyClass::print()
{
    cout << *ptr << endl;
}

int main()
{
    MyClass obj1(new int(1));//Create object obj1
    MyClass obj2(new int(2));//Create object obj2

    obj1.print();//Storage value of address pointed by pointer in print object obj1
    obj2.print();//Storage value of address pointed by pointer in print object obj2

    obj2 = obj1;//obj1 is reloaded to obj2 by equal sign

    obj1.print();//Storage value of address pointed by pointer in print object obj1
    obj2.print();//Storage value of address pointed by pointer in print object obj2

    return 0;
}
/**< Replica constructor */
#include <iostream>
using namespace std;

class MyClass
{
public:
    //Main constructor [no return type is required]
    MyClass(int *p);
    //Replica constructor
    MyClass(const MyClass &rhs);
    //Destructor
    ~MyClass();

    //Operator (=) overload, object replication, brackets declare that the object calls the replica constructor
    MyClass &operator = (const MyClass &rhs);
    void print();

private:
    int *ptr;
};
//Main Constructor Implementation
MyClass::MyClass(int *p)
{
    cout << "Enter the main constructor\n";
    ptr = p;
    cout << "Leave the main constructor\n";
}
//Implementation of replica constructor
MyClass::MyClass(const MyClass &rhs)
{
    cout << "Enter replica constructor\n";
    *this = rhs; //Equivalent assignment overload
    cout << "Leave the copy constructor\n";
}
//Destructor implementation
MyClass::~MyClass()
{
    cout << "Enter the destructor\n";
    delete ptr;
    cout << "Leave the destructor\n";
}
//Operator (=) overloads implementation, rhs is another object
MyClass &MyClass::operator=(const MyClass &rhs)
{
    cout << "Enter assignment statement overload\n";
    //When obj1 is not equal to obj2, this pointer refers to the object generated by the current class (in this case, the first MyClass)
    if(this != &rhs)
    {
        delete ptr;//Delete the address ptr and release the memory of obj1

        ptr = new int;//Create new memory for pointer ptr
        *ptr = *rhs.ptr;//Dereference, assigning the value of obj2 to obj1
    }
    else//When obj1 and obj2 are the same object
    {
        cout << "Assignment number is the same object on both sides, do not deal with it!\n";//When obj1 = obj2
    }
    cout << "Leave the assignment statement overloaded\n";
    return *this;//Returns the first MyClass object
}
void MyClass::print()
{
    cout << *ptr << endl;
}

int main()
{
    MyClass obj1(new int(1));//Create object obj1
    MyClass obj2(new int(2));//Create object obj2
    obj2 = obj1;//obj1 is reloaded to obj2 by equal sign
    obj1.print();//Storage value of address pointed by pointer in print object obj1
    obj2.print();//Storage value of address pointed by pointer in print object obj2
    cout << "---------------------------------------------\n";


    MyClass obj3(new int(3));//Create object obj3
    MyClass obj4 = obj3;
    obj3.print();//Storage value of address pointed by pointer in print object obj3
    obj4.print();//Storage value of address pointed by pointer in print object obj4
    cout << "---------------------------------------------\n";

    MyClass obj5(new int(5));//Create object obj5
    obj5 = obj5;
    obj5.print();//Storage value of address pointed by pointer in print object obj5
    cout << "---------------------------------------------\n";

    return 0;
}

Running result of program

Added by vasse on Sat, 07 Sep 2019 08:28:41 +0300