You aren’t actually subtracting the array. You are subtracting the pointer address of the beginning of the array.
This is because upper_bound() does not take an array as argument, so the compiler “decays” the array type to a pointer type, with the value pointing to the first element of the array.
This conveniently works, since upper_bound() expects an iterator, and a pointer is an iterator. (Iterators were designed to pretend to be pointers, so using an iterator and using a pointer is very much the same kind of code.)
After that everything is pointer (iterator) arithmetic.