An operating system (OS) can run several programs at once. A running program is called a process. Each process has been granted some memory by the OS, and the OS keeps careful track of just which parts of memory each process owns. The OS does not allow a process to look at or store anything into memory that it does not own. No process can interfere with any other process.
It is useful to think of different parts of the memory of a process as as having one of a few possible ownerships within the process.
The heap manager is part of a process. It asks for memory from the OS as needed, and can return memory to the OS. Typically, it requests or gives back fairly large chunks of memory.
The heap manager keeps its own table concerning the memory in the heap. As far as the heap manager is concerned, there are two kinds of memory in the heap.
Some of the memory in the heap has been allocated by the heap manager to the running program, and the program is free to do whatever it chooses with that memory.
Other parts of the heap are marked as belonging to the heap manager. That memory still belongs to the process, but should not be used by the program. The OS does not know about the heap manager's concept of ownership of memory in the heap. As far as the OS knows, it is all owned by the process.
Some of a process's memory is used for the run-time stack. The OS keeps track of the boundary of the run-time stack, and does not allow a program to use memory that has not been allocated as part of a frame.
Memory in the run-time stack is allocated and deallocated by the OS in small chunks that correspond to frames.
A memory fault occurs when a process either uses memory in an incorrect way or uses memory that does not belong to it, according to the OS. When a memory fault occurs, the OS terminates the process immediately.
On a Linux system, a memory fault is called a segmentation fault.
Memory faults are usually caused by one of three errors: (1) using dangling pointers, (2) using null pointers and (3) trying to modify read-only memory. Let's look at those in more detail.
Memory address 0 is called the null pointer. Your program is never allowed to look at or store anything into memory address 0, and attempting to do that will cause a memory fault. The null pointer is a way of saying "a pointer to nothing". We will encounter uses of it later. Write a null pointer as NULL in your program. For example, char* p = NULL;creates a pointer variable p and makes it hold memory address 0. We will draw a null pointer as an X; Note that NULL is not the same as the null character; do not confuse the two. The null pointer is a pointer. The null character is a character. (NULL is not really part of C++. It is added using the preprocessor by defining it in header files including in <cstdio>, <iostream>. #Include one of those to get NULL defined.) |
A dangling pointer
is a pointer to memory that your
program should not use. Using dangling pointers
is a common mistake among beginners. Read this and
pay attention. What you ignore can
lead to long hours of debugging.
There are a few forms that a dangling pointer can have.
|
Read-only memory
Recall
that some memory is marked read-only. If your program
tries to change something in read-only memory, it will get a memory
fault. For example, a string constant is stored in read-only
memory. We will see that string constants can be treated as
arrays. Performing
char* str = "a string constant"; str[0] = 'b';leads to a memory fault, since it tries to alter the memory where "a string constant" is stored. Do not use a string constant as a substitute for allocating memory using new. |
Memory faults due to running out of memory
If your program runs out of memory, either in the run-time stack or the heap, it will probably get a memory fault. That is only likely to happen if the program runs amok and starts allocating huge amounts of memory. |
Using a dangling pointer can cause very strange errors. If something happens that appears to be impossible, then you should suspect that you are using a dangling pointer.
If you get a memory fault, use a debugger to track down exactly where the fault occurs. Just run the program in the debugger. When the memory fault occurs, the program will stop. Look at the values of pointers and array indices at that point. If you are not sure whether a pointer p is valid, try to show the value of *p.
Pointers are shown in hexadecimal notation (base 16). In a Linux system, a null pointer is shown as either 0x0 or (null); a pointer into the heap is a relatively small number such as 0x6a003c; and a pointer into the run-time stack is a very large number, such as 0xffffffffffff2004.
A dangling pointer is a pointer to memory that your program does not own or should not use. Just having a dangling pointer is not a huge problem. But beware of using dangling pointer. It can derail your software in awful ways. The source of the error can be very difficult to isolate during debugging.
If your program gets a memory fault, try running a debugger. It will stop the program at the memory fault and show you just where the program is. Print the values of some relevant variables. If you are lucky, you will see some peculiarities that suggest how to fix the problem.
What is a dangling pointer? Answer
What is a memory fault? Answer
If you delete memory and immediately try to use it, do you always get a memory fault? Answer
int* p = new int; int* q = p; *p = 50; *q = 100; delete p; printf("*q = %i\n", *q); delete q;Comment on what happens when this is run. Answer
int* p; *p = 50; printf("*p = %i\n", *p);Comment on what happens when this is run. Answer
What are the consequences of using a dangling pointer? Answer