Tie koodariksi

C++ Programming

Chapter 11: Working with Memory

Variables in memory

Each variable has a specific place in the computer's memory. We can find out the memory address of the variable using the & operator.
int a = 5;
cout << &a << "\ n";
For example, the code might print out something like the following:
0x7ffcb35f5724
This is the memory address (in hexidecimal format) where the contents of the variable are stored.

Pointers

A pointer is a variable that points to a memory address. The pointer is defined by its * character before its name. Then we can set the pointer to point to a variable and manipulate the variable through the * operator.

For example, the following code creates a pointer p and puts the address of the a variable in it. It is then possible to change the value of the variable through the pointer.

int a = 5;
int *p;
p = &a;
*p = 8;
cout << a << "\n"; // 8
If the pointer does not point to anything, it is equal to nullptr (null pointer):
int *p;
p = nullptr;
An value with the same meaning in the C programming language is NULL.

Pointer vs. reference

C++ has two similar concepts: pointer and reference. In the following code, in the test function the parameter is a pointer to ensure changes are forwarded to the function caller.
void test (int *x) {
    *x = 5;
}

int main () {
    int x = 2;
    test(&x);
    cout << x << "\ n"; // 5
}
The following code uses a reference to achieve the same effect:
void test (int &x) {
    x = 5;
}

int main () {
    int x = 2;
    test(x);
    cout << x << "\ n"; // 5
}
You can think of a reference as a pointer whose use is restricted. The pointer can be set to point to another variable, but the reference never changes after it is created. It's easier to use a reference, so it is worth using one if there is no need for pointer properties.

Arrays in memory

All elements in an array are sequentially stored in a solid area. We get the memory address of the first element in the array through the array name because t has the same meaning as &t[0].

We can change the pointer's position in memory by adding and subtracting. For example, the ++ and -- operators move the pointer one element forward and backward.

The following code creates a pointer p that initially refers to the beginning of an array. Then the code prints the pointer position and the corresponding value, moves the pointer one step forward and repeats printing.

int t[5] = {1,2,3,4,5};
int *p = t;
cout << p << "" << *p << "\ n";
p++;
cout << p << "" << *p << "\ n";
The code prints something like the following (memory addresses will likely be different on your system):
0x7ffd17c1e070 1
0x7ffd17c1e074 2
Note that since int is 4 bytes in size, the memory address increases by 4.

Static memory allocation

Static memory allocation means that the variable is allocated memory at the beginning of the program and the memory remains occupied throughout the execution of the program. The most common example of this is a global variable, defined at the main level of the program. For example, in the following code x is a global variable:
int x; // initial value 0

void test() {
    x ++;
    cout << x << "\n";
}

int main() {
    test(); // print 1
    test(); // print 2
}
You can also declare a static variable inside a function with the static keyword. Such a variable is only available within the function, but it is allocated a fixed amount of memory at the start of the program. So the value of the variable is kept between calls to the function.
void test() {
    static int x; // initial value 0
    x++;
    cout << x << "\n";
}

int main() {
    test(); // print 1
    test(); // print 2
}

Dynamic memory allocation from the stack

The stack is a memory area that allocates space to perform a function. The stack allocates space for function parameters and other function-call-related information as well as local variables created inside the function. When the function completes, the space reserved for it is freed from the stack.

Let's consider the following program as an example:

void test(int a) {
    int b = 2 * a;
    cout << b << "\n";
}

int main() {
    test(1);
    test(3);
}
As the program runs, the contents of the stack change approximately as follows: Thanks to the stack the same memory can be reused when a function is called several times.

Note that the maximum stack size is often quite small by default. For example, in Linux, the maximum stack size might be 8 MB. Therefore, it is not a good idea to allocate a large array in a function like this:

int main() {
    int t[10000000];
}
The array may not fit in the stack and the program will end with an error. However, the program works fine, for example, when a corresponding table is created globally (above the main() function).

Dynamic memory allocation from the heap

The program can also allocate memory dynamically from a memory area called heap. The new command allocates the desired amount of memory and the delete command will free up previously allocated memory.

For example, the following code allocates memory for an int and then frees the memory:

int *x = new int;
*x = 5;
delete x;
You can allocate memory for an array in quite the same way. For example, the following program allocates memory for a 10-element array and then frees the memory.
int *x = new int[10];
x[3] = 5;
delete [] x;
The advantage of allocating memory dynamically with new is that you have complete control over when memory is allocated and released. In addition, unlike the stack, we can allocate much larger amounts of memory from the heap, making it possible to allocate large amounts of memory inside a function (for arrays, for example). However, reserving memory from the heap comes at a cost, so it shouldn't be used unnecessarily. Care must also be taken to eventually free allocated memory (with delete), to avoid memory leaks. C++ data structures such as string, internally reserve memory from the heap.

Datatähti 2027 – peruskoulun ja lukion ohjelmointikilpailu käynnissä 26.10.–8.11.2026