1 2
|
int * bobby
bobby = int[5]
|
This should not compile.
Let's start with the basics: do you know what a pointer is?
1 2 3
|
int *bobby; // bobby is a pointer to int
char *charlie; // charlie is a pointer to char
void *veronica; // veronica is a pointer to... anything
|
A pointer is a variable that stores a memory address.
bobby is a pointer that can store the memory address of an
int.
You see, memory addresses are basically all the same: they are numbers.
But the data types are different: for example an
int needs 4 bytes of memory, and a
char needs 1 byte.
By giving the pointer a "type" you give a hint as to what kind of data the pointer is pointing to.
If you use a void pointer, you give no such hint. Which is why if you want to access what's stored in memory at the memory address contained by
veronica, you must cast it.
You don't need to cast
bobby or
charlie because you already hinted what kind of data they're pointing at:
int and
char.
1 2 3
|
// cast examples
reinterpret_cast<char *> (veronica);
reinterpret_cast<int *> (veronica);
|
Now to "dynamic" memory. In your program there are basically three kinds of data: static, automatic and dynamic.
Global variables, and variables marked as
static are static.
They live in their memory chunk from the beginning to the end of the program.
Automatic variables are the simple local variables found in functions.
They live on the stack.
The stack is a memory chunk used for functions. When a new function is called, it receives stack space to use for its local variables. When the function ends, it returns the stack space, and its variables can be overwritten by those of another function.
Dynamic variables live on the heap.
They are not automatic, because you manually manage their life, with
new and
delete. By the way, in C++, every
new must have its corresponding
delete, otherwise you will waste memory in what's called a "memory leak".
Dynamic memory allocation is used because the stack is much smaller than the heap, and also because you can decide the size of a dynamically allocated array at runtime (as rmxhaha pointed out in his example).
Now, the thing with dynamic memory allocation is that you need pointers to use it.
new returns a pointer to newly allocated memory.
delete accepts a pointer to the memory that needs to be released.
new[] and
delete[] are similar to
new and
delete, with the difference that they don't allocate memory for a single element, but for more elements, so the final result looks like an array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
int global; // variable in static memory
void f()
{
int ia[20]; // int array on the stack
char c; // char on the stack
// the pointer "hello" is on the stack,
// but the string literal "Hello, World!" is in static memory
const char *hello = "Hello, World!";
static int i; // this isn't on the stack
int *p = new int[20]; // p is on the stack
// but its contents, the memory address returned by new int[20]
// is valid for use until delete[] is called on it, because it points to the heap,
// and the heap isn't affected by when this function ends, unlike the stack
delete[] p;
}
|
I invite more knowledgeable members of this forum to offer better explanations. I don't think my "static memory" explanation is very technically accurate.