# Advanced Introduction to C++, Scientific Computing and Machine Learning

Claudius Gros, WS 2021/22

Institut für theoretische Physik
Goethe-University Frankfurt a.M.

# C++ : Pointers & Memory

• pointers point to the (start of the) memory address of an object
• &variable : assessing the pointer of the variable (reference)
• int* intPointer : creates a pointer intPointer to an integer
*intPointer : assesses the value of the memory location
the type (size) of adressed memory cell
• int** intPointPointer : a pointer pointing to an integer-pointer
:: a two-dimensional int-array
• int intArray[] :
intArray is a pointer, pointing to the first element intArray[0]
• main(int argLength, char* argValues[])
argValues[] is an array of pointers
• using pointer explicitly invites bugs to the party;
modern languages like JAVA do not allow it

#include <iostream>

using namespace std;

int main ()
{
int var1   = 20;
int var2[] = {1,2,3};

cout << endl;
cout << "address of var1: " << &var1 << endl;
cout << "address of var2: " <<  var2 << endl;
cout << "address of var2: " << &var2 << endl;

int* ip;         // pointer variable
ip = &var1;      // store address of var1 in pointer variable ip

cout << endl;
cout << "value of var1: " << var1 << endl;
cout << "value of   ip: " <<   ip << endl;
cout << "value of  *ip: " <<  *ip << endl;

ip = var2;       // not &var2 (!), since arrays are already pointers
for (int i=0; i<3; i++)
{
cout << endl;
cout << "address of var2[" << i << "] = "
<< ip << " "
<< &(*ip) << " "
<< &var2[i] << endl;

cout << "  value of var2[" << i << "] = "
<< *ip << " "
<< *(&(*ip)) << " "
<< *(&var2[i]) << endl;

ip++;          // point to the next location (errors likely)
}

return 0;
}


# dynamic memory

• int array_0[5]  : when size of array is known a compiling time
• int array_1[var1]  : not standard, but possibly a
compiler extension:  g++  is o.k. with it (standard from  C++14  and on)
puts the object onto the stack (the stack of locally declared variables)
• int *array_2 = new int[var2]  : when size of array,
viz the value of  var2, is not known a compiling time;
program aborts badly when allocation fails (out of memory);
puts the object onto the heap (dynamically allocated memory)
• int *array_3 = new(nothrow) int[var3]  : idem, but continuing
with a null pointer when allocation fails
• more options for new(..) available for programming experiments
• delete  everything on the heap when not needed anymore
for an explicit garbarge collection (avoiding such a memory leak)
• modern programming languares like JAVA collect their garbage automatically
#include <iostream>      // standard IO
#include <cstdlib>       // for atof

using namespace std;

int main(int argLength, char* argValues[])   // parsing command line arguments
{
if (argLength==1)
{
cout << "please run with an long integer argument\n";
return 0;
}
long int dynamicArraySize = atof(argValues[1]);  // casting string to long
long int gigaByte = 1073741824;
//
cout << endl;
cout << "trying to construct integer arrays of size : "
<< dynamicArraySize << endl;
cout << "using  "
<< dynamicArraySize*sizeof(int)*1.0/gigaByte
<< "  Gigabytes of memory " << endl << endl;
//
int array_1[dynamicArraySize];            // not all compilers like that
cout << "sizeof(array_1)  : "
<<  sizeof(array_1) << endl;
//
int *array_2 = new int[dynamicArraySize]; // arrays are pointers
cout << "sizeof(array_2)  : "
<<  sizeof(array_2) << endl;

int *array_3 = new(nothrow) int[dynamicArraySize];
//
if (array_3 == 0)                         // controlled exit for null pointer
{
cout << "I am out of memory" << endl;
return 0;                                // program failed
}
cout << "sizeof(*array_3) : "
<<  sizeof(*array_3) << endl;
//
cout << "sizeof(int)      : "
<<  sizeof(int) << endl;
//
delete[] array_2;      // deletes the whole array
delete array_3;        // deletes only the first element
//
return 1;
}


# memory usage

• control the usage of your memory with the
Linux shell command top
• size_t, an unsigned integer type which can store
the maximum size of a theoretically possible object of any type
• all CPUs today are 64 bit processors (32 bit CPS had the 4GB memory limit)
#include <iostream>      // standard IO
#include <stdio.h>       // for printf
#include <cstdlib>       // for atof
#include <math.h>        // for the math
#include <time.h>        // ('clock()' measures time in nanoseconds)

using namespace std;

const long int oneGigaByte = 1073741824;   // one Giga Byte

/* **************************************** */
/* *****      time in seconds       ******* */
/* **************************************** */

double timeInSeconds()
{
const double oneSecond = 1.0 / CLOCKS_PER_SEC;
static long int lastTime = clock();
long int actual_time = clock();
long int elapsed_time = actual_time - lastTime;
lastTime = actual_time;
return elapsed_time * oneSecond;     // time passed since last call
}

/* **************************************** */
/* *****            main            ******* */
/* **************************************** */

int main(int argLength, char* argValues[])  // parsing command line arguments
{
if (argLength==1)
{
cout << "please run with a double argument (memory in GB)\n";
return 0;
}
long int dynamicArraySize = (long)(atof(argValues[1])*oneGigaByte*1.0/sizeof(int));
timeInSeconds();                           // initialized

int onePerCent = (int)(dynamicArraySize/100);
//
int *aa = new int[dynamicArraySize];
/*
for (int i=0;i<dynamicArraySize;i++)
for (long int i=0;i<dynamicArraySize;i++)
*/
for (size_t i=0;i<dynamicArraySize;i++)
{
aa[i] = i;
if ((i%onePerCent)==0)
printf("(main) %5.2f GB indices allocated, %5.2f seconds used\n",
i*1.0/oneGigaByte, timeInSeconds());
}
//
printf("\n");
printf("(main) starting infinite loop\n\n");
//
while (true)                   // infinite loop
double a = log(34545.3454);
//
return 1;
}


# aliasing

• int* aPointer an int pointer: *aPointer for value
int& alias an alias (different name)
#include <iostream>       // standard IO
using namespace std;

int main()
{
double  a = 10.0;
double& b = a;          // an alias

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

double *pA = &a;
double *pB = &b;

b = 6.0;

cout << "*pA = " << *pA << endl;
cout << "*pB = " << *pB << endl;

return 1;
}