Dynamic memory allocation

In the previous lessons, when we declared an array, we did it statically (e.g., int a[10];). We must have known the size of this array at the beginning because if we determined its size with a variable received from an input (int a[n];), we could have overriden something in the memory. It is because, when we do it statically, it is checked during compilation if a certain address is free, and when using data from an input, the program is already compiled. We can reserve memory dynamically using this method (we will be sure nothing gets overriden):


int a = 10;
{ // everything between those braces is local (it isn't accessible outside of them)
    int *pointer = new int; // if we don't have enough memory, the returned address will be NULL
    *pointer = 20;
    cout << *pointer << endl;
    
    delete pointer; // releasing the memory pointed to by the pointer (it will be free again)
    pointer = NULL; // so as not to point on something that doesn't exist
    
    int *p = new int;
    cout << p << endl;
    cout << pointer << endl;

    delete p;
}
                                    

If we use the delete operator on pointer, p will have the same address as previously pointer because it has been released. Because of this, after releasing memory, we have to immediately assign another value to it. This value can be NULL, which means an absence of a value. We don't have to do this if delete is the last statement in braces (everything will disappear anyway). We do all this to prevent errors.

When displaying the values of pointers, we don't always know if it won't be NULL, so it's safer to write: if(pointer != NULL) cout << *pointer << endl;.

To set the pointer's value as NULL, it is better to use nullptr instead of NULL.

When using dynamic memory allocation, we can safely input the size of an array from the user. To release the memory after using this type of array, we have to add square brackets after delete.


int x;
cin >> x;
int *a = new int[x];
a[0] = 10;
a[1] = 20;

cout << a[0] << endl;
cout << *(a) << endl;
cout << *(a + 1) << endl;

delete[] a;
                                    

We must be careful when incrementing pointers used for allocating dynamic memory because by doing so, we replace the first index. It is a mistake because the delete operator clears a given number of addresses from the first index, which has now changed. To prevent this mistake, we should set a pointer as a constant and create a new pointer to manipulate the first one. Then, the array will always keep its original first address, and we will be able to release the memory correctly. All pointers used to dynamically allocate memory should be constants.


char * const text = new char[10];
char * pointer = text;
text[0] = 'a';
text[1] = 'b';
text[2] = 'c';
text[3] = '\0';
cout << text << endl;

while(*pointer)
    cout << *pointer++;

delete[] text;
pointer = NULL;
                                    

Strings and chars - more about pointers

Every character in a string is a char, which means a string is an array of chars, and because of this, strings can be indexed, e.g., text[2]. We can create an array of chars like this: char a[] = "abcdefg";. The \0 symbol means the end of a string. We can edit strings just like we edit arrays: a[2] = 'z';.


string text = "abcdefg"; // a b c d e f h \0
string text2 = "abcd\0efg"; // a b c d
                                    

The c_str() method turns a string into a string of a type that appears in the C language (literally an array of chars).


string text = "abcdefg";
const char *pointer = text.c_str();
cout << pointer << endl;
while (*pointer) // it will execute till encountering \0
    cout << *pointer++ << endl;
                                    

Of course, we can create dynamic string or char arrays (e.g., char *text = new char[20];) and normal ones, too (string texts[10];). When working with string arrays, we can reference the individual string's indexes just like we reference objects in multidimensional arrays: texts[0][3] (this will get us to the fourth letter of the first string).