See Last line of code: Trying to get number of elements from a array depending on a condition. How do i get the number of elements in an array when using an array like shown below:
using namespace std;
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
const char **p;
if (true) {
p = options;
} else {
p = options2;
}
printf("%ld\n", sizeof(options)); // returns 24
printf("%ld\n", sizeof(options2)); // Returnns 16
printf("%ld\n", sizeof(options) / sizeof(p)); // returns 3
printf("%ld\n", sizeof(options2) / sizeof(p)); // returns 2
// How to use only pointer p to get the number of elements
printf("%ld\n", sizeof(p) / sizeof(p[0])); // returns 1 and not 3
return 0;
}
CodePudding user response:
Sorry, but it is simply not possible to get an array's size from just a raw pointer to an array element.
One option is to store the array size in a separate variable alongside the array pointer, eg:
#include <iostream>
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
const char **p;
size_t p_size;
if (some condition is true) {
p = options;
p_size = sizeof(options) / sizeof(options[0]); // or better: std::size(options) in C 17 and later
} else {
p = options2;
p_size = sizeof(options2) / sizeof(options2[0]); // or better: std::size(options2)
}
std::cout << sizeof(options) << "\n"; // returns 24
std::cout << sizeof(options2) << "\n"; // returns 16
std::cout << p_size << "\n"; // returns 3 or 2, based on condition
return 0;
}
In C 20 and later, you can use std::span
instead (in C 14 and C 17, you can use gsl::span
from the GSL library), eg:
#include <iostream>
#include <span>
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
std::span<const char*> p;
if (some condition is true) {
p = options;
} else {
p = options2;
}
std::cout << sizeof(options) << "\n"; // returns 24
std::cout << sizeof(options2) << "\n"; // returns 16
std::cout << p.size() << "\n"; // returns 3 or 2, based on condition
return 0;
}
CodePudding user response:
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
.