If you're going to write C++, write C++. You're starting from one of C's more questionable decisions, and then trying to force C++ to do the same thing. To twist Nike's phrase, "Just don't do it!"
std::array<char const *, 3> options {"Option1", "Option2", "Option3"};
std::array<char const *, 2> options2 {"Option1", "Option2"};
This makes it easy to retrieve the size of the array in question--and the size is part of the type, so all the work happens at compile time, so it imposes no runtime overhead. For example, if you do something like this:
template <class Array>
void showSize(Array const &a) {
std::cout << a.size() << "\n";
}
int main() {
showsize(options);
showSize(options2);
}
...what you'll find is that the compiler just generates code to write out the literal 3 or 2:
mov esi, 3 // or `mov esi, 2`, in the second case
call std::operator<<(std::ostream &, unsigned long)
[I've done a bit of editing to demangle the name there, but that's what the code works out to.]
Here's the un-edited version, in case you care.
If you really insist, you can side-step using an std::array as well:
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
template <class T, size_t N>
void showSize(T (&array)[N]) {
std::cout << N << '\n';
}
int main() {
showSize(options);
showSize(options2);
}
This doesn't actually use a pointer though--it passes the array by reference, which retains its type information, so the instantiated function template "just knows" the size of the array over which it was instantiated.
20 years ago, I'd have said this was a good way to do things. 10 years ago, I'd have preferred std::array, but realized it was new enough some compilers didn't include it yet. Nowadays, unless you really need to use an ancient (Pre-C++ 11) compiler, I'd use std::array.
sizeof(options)bysizeof(p)doesn't make sense. It's a different pointer type from*options. Sure, it may give the desired result, but it's extremely misleading. Usesizeof(options) / sizeof(*options). As for usingpto get the size, you can't.pis just a pointer. Its size doesn't depend on its value.sizeof(p)/sizeof(p[0])is going to besizeof(char **)/sizeof(char *), which is a constant, and is going to be1on any normal architecture.optionsandoptions2are statically declared arrays, butpis declared simply as a pointer and stores no information about the memory it is pointing to, andsizeof(p)just returns the size of an integer.