Hello, I’m Liang Tang.
This is part 16 of the EasyC++ series, where we continue to talk about Pointers in C++.
If you want a better reading experience, you can visit the Github repository.
A Preliminary Study on Pointers (II)
Dangerous case
Because Pointers can manipulate memory, they can easily cause unexpected errors if not used carefully.
C++ Primer gives an example like this:
int *ptr;
*ptr = 2333;
Copy the code
In this code we declare a pointer to int and point it to 2333. There is a problem, however, that we did not initialize the pointer when we declared it. An uninitialized pointer is not null, but points to an unknown place. If it refers to an address with a constant 1200, and we set it equal to 2333, then every time we use 1200, we get 2333.
What’s even scarier is that the whole process is very hidden and difficult to detect. Debug can be maddening.
So never modify a value that an uninitialized pointer points to.
Pointers and numbers
There is another example in C++ Primer where when we output a pointer, we get a string of hexadecimal numbers. Can we instead assign a hexadecimal number to a pointer?
int *p;
p = 0xB8000000;
Copy the code
The answer is no, because the types are inconsistent. Although we print a pointer that looks like a hexadecimal number, its type is actually a pointer, not an integer. So we can’t assign an integer to a pointer. If we do, we have to cast it.
int *p;
p = (int*) 0xB8000000;
Copy the code
Do we know where the address 0xB8000000 points to? I don’t know, of course, but I don’t know what’s going to happen if I change the value here.
So while it’s possible, it’s strongly not recommended.
New operation
One of the great benefits of using Pointers is that you can dynamically allocate memory while your program is running. In fact, there is a similar function in C language, you can use malloc to allocate memory. But in C++ there is a better operator called new.
For example, if we want to create a variable of type int dynamically, we can write:
int *ptr = new int;
Copy the code
The new operator determines the size of memory required based on the subsequent type, and when it finds such memory, returns the address. The value received by the pointer is the memory address, so this assignment can be done.
The above code could also be written like this:
int a;
int *ptr = a;
Copy the code
What’s the difference between the two? On the surface, there is no difference, both create a variable of type int. However, the second version can use the variable name a to access the int in addition to the pointer PTR.
However, the internal implementation of the two is completely different. Variables created directly by variable names are stored in stack memory, while objects created by new are stored in heap memory. Stack memory is allocated automatically by the system, while heap memory is requested by the programmer. The two memory models are completely different, and we’ll discuss this in more detail in a future article. In simple terms, heap memory is more flexible and has more space to store more data.
The delete operation
With dynamic creation, there is also dynamic deletion, so there is a delete operation corresponding to new in C++.
The DELETE operator returns memory to the memory pool at the end of variable use. Because many variables in a program are disposable or have a life cycle, when the life cycle ends, the mission is completed and there is no need to continue to occupy resources. After all, the memory resources in the system are limited, especially in some large projects or embedded systems, memory resources are very tight.
The delete operator is followed by a pointer that frees the memory to which the pointer points.
int *ptr = new int;
delete ptr;
Copy the code
There are many potholes in it. Be careful. If you create a memory using new, remember to delete it. Otherwise, the memory will be permanently occupied and cannot be freed. This is called a memory leak. In addition, we cannot delete a pointer that has already been deleted, which would also cause serious errors. ‘anything can happen,’ C++ Primer describes it. It is also not possible to use a pointer that has already been deleted, which would cause a null pointer error.
Pointers are a double-edged sword for C++, and in other languages like Java, Python, and Go, memory reclamation is done automatically by the system. For example, Java JVM virtual machine design strict GC (garbage collection) mechanism, programmers do not need to care about the problem of memory collection, all handed over to the program automatic completion.
In C++, this process is done manually by the programmer, which is great in a way, because the programmer has a lot of authority and flexibility. But it is also a pitfall, especially in complex systems, where it is difficult to determine exactly when a DELETE will be executed. This can cause serious problems such as memory leaks, wild Pointers flying around…