Reading Complicated Types
So many MORE things in the mix for what can be part of a type, pointers, references, arrays, and
const
!!And reading and writing all those types is getting complicated…
It's not so bad if we just have some systematic rules.
In previous pages, we gave you a helpful right-to-left rule for reading types involving a pointer and const
. Now we'll expand on that rule so you can use it to read even more complex types!
(Simplified) Inside-Out Rule
(This version of the inside-out rule is sufficient for the types we see in this class. A more general version is given in a bonus section below.)
When reading the type of a variable…
- Read the name of the variable;
- Read to the right until you hit the end of the declaration (or any initialization);
- Jump back to the name of the variable; then,
- Read from right-to-left until you hit the beginning of the declaration.
Wait, what?
Let's do an example.
Consider the variable
int* a[5];
We read it as
int* a[5]; |
a is… |
(Read the variable name) |
int* a[5]; |
an array of five… | (Read to the right) |
int* a[5]; |
pointers to… | (Jump back to the name and then read right-to-left) |
int* a[5]; |
integers. |
So this line is declaring an array of five int
pointers.
Oh… okay. I see it. I was kind of already doing that.
Yes! For simple enough types, it's quite intuitive. But now that you know the rule, you can interpret unfamiliar types!
An Example
How about this one?
const int* const * b[3];
Aaaauuugggh!
Don't panic! Use the inside-out rule!
We read it as
const int* const * b[3]; |
b is… |
(Read the variable name) |
const int* const * b[3]; |
an array of three… | (Read to the right) |
const int* const * b[3]; |
pointers to… | (Jump back to the name and read right to left) |
const int* const * b[3]; |
const |
|
const int* const * b[3]; |
pointers | |
const int* const * b[3]; |
to integers | |
const int* const * b[3]; |
that are const . |
For example, such a variable could appear in a snippet like
int x = 1;
int y = 2;
int z = 3;
const int* a = &x;
const int* b = &y;
const int* c = &z;
const int* const * arr[3]{&a, &b, &c};
Hay! Did the stack start at s0 in that video?
It's true. Though we've usually started it at s1, some of the videos in this lesson will start the stack at s0. Sorry for the inconsistency!
That said, remember that this way of thinking about memory is just an abstraction. The key is that things have memory addresses, not what they specifically are.
A-a-a-a-anyway. How do you feel about it now?
Aaaauuugggh!
Well, that's understandable. It'll take time and practice to get comfortable with it.
The key thing is that, even when you are overwhelmed by a complicated type or you are not sure what type something should be, there is a step-by-step procedure you can follow!
Bonus Fun: The Generalized Inside-Out Rule for Complex Types
This is my thing! Heading deeper into the rabbit hole!
We won't test you on this stuff, but it might someday be helpful to know.
The inside-out rule we saw above is sufficient to read a type like
int* const x[10];
which reads as “x is an array of 10 const pointers to int”. But what if you wanted a single pointer to an array of ints? It turns out that would be written as
int (* const x)[10];
You can read this type with a revised version of the inside-out rule that handles parentheses.
- Start at the name of the variable.
- In some contexts, the name can be omitted. If it has been omitted, start where the name would have been if it hadn't been omitted.
- Read outwards, respecting parenthetical grouping (i.e., don't go beyond the parentheses you're inside).
- If you can read both to the right and to the left, read to the right first.
- If you're not done yet because you were inside parentheses, consider the parenthesized group as a new starting point and continue from step 2.
FWIW, pointers to functions are also allowed. Thus
double (*(*(* const x)[10])[20])(short *, string);
is a valid type that can be read as (each time we restarted at step 2, the description is indented with parts read to the right in dark orange and parts read to the left in blue), so
x
is aconst
pointer to- an array of ten pointers to
- an array of twenty pointers to
- a function that takes a pointer to
short
and astring
and returns a double.
- a function that takes a pointer to
- an array of twenty pointers to
- an array of ten pointers to
Sometimes though, just because you can do something, doesn't mean you should.
(When logged in, completion status appears here.)