For a number of reasons.
Firstly, the stack is small. Objects you make like this (i.e. without using
new, or
malloc if you've reverted to C):
go on the stack. The stack is a section of memory. It's small. Much much smaller than the heap. Sometimes just a few megabytes. So if you want to use more memory than just a few megabytes, you need to put your objects on the heap, and to use the heap you have to use
new, and
new gives you back a memory address. You
can't "access it directly".
Additionally, the compiler needs to know the size of things that will go on the stack at compile time. If you don't know how big something is going to be (like an array which might hold 5 items and might hold 50, depending on something the user does) it can't go on the stack. I will say that C99 allowed unknown size arrays on the stack, but it's an easy way to cause trouble. Don't know the size of something at compile time? Put it on the heap. It's what it's for.
Secondly, and not something everyone runs into, real-world hardware at the low-level works on memory addresses. The hardware manual tells programmers which memory address to put their data into so that the hardware can find it, and which memory addresses to read when the hardware has data for them. When all you have is a memory address, all you can use is a pointer.
Thirdly, it allows you to pass a parameter by pointer. You can pass a function the memory address of a variable, and it can then work directly on that variable, and changes it made to the variable persist after the function returns. Like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
void some_function(int* i, int* j, int* k)
{
// increment them all
*i = *i + 1;
*j = *j + 2;
*k = *k + 3;
}
int main()
{
int i=0, j=0, k=0;
some_function(&i, &j, &k); // &i is the memory address (so a pointer to) i
// here, i=1 and j=2 and k=3. If we didn't pass pointers to the variables,
// the changes would have happened to copies instead of the originals
}
|
In C++, we would prefer to do this with references rather than pointers, but there are a couple of things we can do with a pointer that we can't do with a reference.
Forth, it allows polymorphism. I can talk more about that if the first few are clear, because that one is a bit more complicated.