CS 70

Read-Only Access

Our normalize function modified the array to normalize the data, but suppose we wanted to write a max_value function that just reads the array to work out its maximum value. Here's the code.

float max_value(float* firstValPtr, float* pastEndPtr) {
    float maxval = *firstValPtr;
    for (float* p = firstValPtr; p < pastEndPtr; ++p) {
        if (*p > maxval) {
            maxval = *p;
        }
    }

    return maxval;
}

Do you have any concerns?

Are we allowed to call this function on an array of const floats (i.e., read-only floats)?

The Solution: const

  • Duck speaking

    I think I know how to fix it! Declare it as a const float*.

  • Cat speaking

    Just like we did with references.

  • LHS Cow speaking

    That's right. It's the same idea.

If we know our function won't modify the array and we want to make it clear in the interface, we can write it as:

float max_value(const float* firstValPtr, const float* pastEndPtr) {
    float maxval = *firstValPtr;
    for (float* p = firstValPtr; p < pastEndPtr; ++p) {
        if (*p > maxval) {
            maxval = *p;
        }
    }

    return maxval;
}
  • Hedgehog speaking

    How do I read const float* firstValPtr in English?

  • LHS Cow speaking

    You read it from right-to-left as usual: firstValPtr is a pointer to a float that's const (i.e., read-only).

  • Hedgehog speaking

    And it's the float that's const, not the pointer.

  • LHS Cow speaking

    Yes.

  • Dog speaking

    Can we have the pointer itself be const instead?

  • LHS Cow speaking

    Yes. And if you remember we read types from right-to-left, you might be able to figure out how.

Where we put the const matters:

  • const float* firstValPtr says the float that the pointer points to can't change—it's a pointer to const float.
  • float* const firstValPtr says the pointer itself can't change.
  • const float* const firstValPtr says both—that the pointer itself can't change, and the float it points to can't change.

Working on Part of An Array

  • Horse speaking

    Hay, wait a minute. Could I use this kind of begin…end style to work out the max_value of just part of an array? Like maxval(vals+2, maxval+5)?

  • LHS Cow speaking

    Totally. Since we specify the start pointer and the past-the-end pointer, we can choose.

The range style for passing array data makes it easy to work with only part of an array.

Empty Ranges

  • Duck speaking

    What if I did maxval(vals,vals)?

  • LHS Cow speaking

    That would be an empty range. The starting point is already past the end.

  • Duck speaking

    I think I've found a bug in our max_value function, then. The code says

    float maxval = *firstValPtr;
    

    Doesn't that mean that we'll read the “past-the-end” point? Are we allowed to do that?

  • LHS Cow speaking

    You have indeed found a bug. Our code was designed for arrays with at least one element.

  • RHS Cow speaking

    And no, if some position is supposed to be “past-the-end”, you shouldn't read it.

  • Bjarne speaking

    You could fix the code to start out with -∞, like this:

    float maxval = -std::numeric_limits<float>::infinity;
    
  • LHS Cow speaking

    Yes, sure, if we knew how to do that kind of thing. Or we could just document that the function doesn't work on an empty range. After all, it's fair to say that if there isn't any data, it doesn't have a maximum value and so you shouldn't try to ask what it is.

  • Duck speaking

    But it is kinda cool to know we can represent ∞ in C++!

  • LHS Cow speaking

    Okay, that's some good progress so far! Let's head up to the parent page to see how far we've come and maybe take a break.

(When logged in, completion status appears here.)