Don't like this style? Click here to change it! blue.css
Be C++, Task 1: If you were trying to create your own C++ and compiler, what would happen when a variable gets declared? How about an array?
I want this question to guide your thinking today. C was written as a language that would allow you to implement an operating system. So they allowed us access to these powerful methods of grabbing, referencing, and manipulating whole chunks of system memory. That is a great power, but a great responsibility. Many developers never use this power, but those that do understand our electronic world much better.
We'll begin our journey with two characters that have four meanings. One meaning in declarations and a different meaning in expressions:
type *variable_name
declares variable_name
as a pointer to a type
(int,
char, string, etc). A pointer is literally the address of some data stored in memory. The address is a huge
number, which encodes everything the CPU needs to find that location.*pointer_name
is replaced by the value read from the address stored in
pointer_name
. This is sometimes called the dereference operator, because it
converts from address/reference to a value.type &variable_name
declares a reference
to a type
. A reference acts like a copy (call it an alias really) of what it refers to, but the data is not
copied to a new location. This lets you have multiple variables poking and prodding the same data in memory.&variable_name
will be evaluated as the memory address where variable_name
is
stored.Let's not rush the following 3 tasks they are fundamental for the rest of this course.
Understanding-Task 2: Look at the following repl.it snippet (our longest). Before you run it, try to predict which values will be identical. Then run it and decide what you are looking at.
Understanding-Task 3: How far apart are the "addresses" in your best estimation?
Mini-Task 4: Create a new program. Declare a string. Now make a pointer to that string which stores the address of the string. Display both the string and the address.
These things are tools. When it comes to using a tool you have to know what it is used for. By working with variables we can make somewhat "generic" code that runs on a variety of inputs. By using the addresses of variables we can do some other cool things:
Group-Task 5: Can you imagine a real-world problem in which any of these benefits might come in handy?
First let's make a function that "passes by reference". This is the main case for using references (aliases).
Explain-Task 6: Explain to your groupmates why
double_pass_by_reference
would have an impact while double_pass_by_value
would not?
So one of the odd things of C/C++ is that you can take a pointer and just add an integer. Any guesses what you get? To help let me first tell you that an array is a contiguous chunk of values. That means one value after the other, no wasted bits, and we can jump to whichever spot we want. (We'll talk much more about this fact.)
Mini-Task 7: Review the above code. Make an array of 10 long
s, name it l_arr
.
Predict what you think will be the value of l_arr + 3
when displayed. Test your prediction.
So you've figured out that the name of an array is actually a pointer to the first object. (Perhaps you've also figured out that the index is not so different than adding to the pointer…) There is (yet another) subtle thing here, you can't assign one array to another array. Go ahead try it:
There are two ways of asking for memory from C++.
The old-school way (my personal preference) called malloc
(and its partner free
). And
the new-school way (safer for developers) called new
(and its partner delete
).
The idea is this: when you want memory you can ask C++ to look around and find you a contiguous block of unclaimed memory to use. It will give you back a pointer to your new home.
Here is an extremely contrived example of new
and delete
(we don't yet have classes or structs to make these things really sing):
Interpret Task 8: What is stored in beatleHomes
? Where are the Beatles? (If you've never heard "The Beatles" then please go listen to "The White Album".)
Every time you allocate memory you must deallocate that memory otherwise you create a memory leak which can cost millions! Here is a story which points at a memory leak. Notice the number of days before the bug appears. With great power comes great responsibility!
Malloc/Free: So malloc is a bit more raw than new. In malloc you ask C++ for as much memory as you like and tell it what you plan to keep there (but you can change your mind later). The space acts just like an array. Take a look at this example:
But you can reinterpret the way you see the data whenever you would like. This allows you to go making trouble:
Interpret Task 9: What is happening in this code? If you can't figure it out, which parts do you not understand (I predict a couple). It might help if I tell you that my intention was to write what I wanted into the first 24 bits of the space I requested and see those bits.
Mini-Task 10: Use malloc to request enough space for 4 strings. Print the address that it returns. Free the memory.
We are going to explore data structures called heaps and other ones called stacks before we are through. But
this "heap" and "stack" are actually two places that C++ might
ask for space to store your data. The stack is where all of your short term variables will come from, and the
heap is where anything you ask for with malloc
or new
will come from. Take a look at how
different the following addresses look:
The stack is typically smaller and storable in RAM for performance, but it is limited. (Stack Overflow is not just the name of a website!) The heap is usually slower and the OS running your compiler can take space from anywhere so it is effectively unlimited. This is a stack overflow:
&variable_name
.int *pointer_to_int
*pointer_to_int = 12
.int func_name(int &x)
int *big_array = (int *) malloc(sizeof(int)*1000)
.malloc
you must release it with free
new
and delete
.