CS 70

Reading Complicated Types

  • Pig speaking

    So many MORE things in the mix for what can be part of a type, pointers, references, arrays, and const!!

  • Hedgehog speaking

    And reading and writing all those types is getting complicated…

  • LHS Cow speaking

    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…

  1. Read the name of the variable;
  2. Read to the right until you hit the end of the declaration (or any initialization);
  3. Jump back to the name of the variable; then,
  4. Read from right-to-left until you hit the beginning of the declaration.
  • Hedgehog speaking

    Wait, what?

  • LHS Cow speaking

    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.

  • Hedgehog speaking

    Oh… okay. I see it. I was kind of already doing that.

  • LHS Cow speaking

    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];
  • Hedgehog speaking

    Aaaauuugggh!

  • LHS Cow speaking

    Don't panic! Use the inside-out rule!

What is the Type of b?

b is…

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};

Draw a diagram of that snippet (careful with your consts!) and then determine which of the following lines would cause a compiler error if added to the end.

  • Horse speaking

    Hay! Did the stack start at s0 in that video?

  • LHS Cow speaking

    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!

  • RHS Cow speaking

    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.

  • LHS Cow speaking

    A-a-a-a-anyway. How do you feel about it now?

  • Hedgehog speaking

    Aaaauuugggh!

  • LHS Cow speaking

    Well, that's understandable. It'll take time and practice to get comfortable with it.

  • RHS Cow speaking

    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

  • Rabbit speaking

    This is my thing! Heading deeper into the rabbit hole!

  • LHS Cow speaking

    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.

  1. 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.
  2. 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.
  3. 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 a const pointer to
    • an array of ten pointers to
      • an array of twenty pointers to
        • a function that takes a pointer to short and a string and returns a double.
  • RHS Cow speaking

    Sometimes though, just because you can do something, doesn't mean you should.

(When logged in, completion status appears here.)