Element count of an array in C++
Asked Answered
W

14

33

Let's say I have an array arr. When would the following not give the number of elements of the array: sizeof(arr) / sizeof(arr[0])?

I can thing of only one case: the array contains elements that are of different derived types of the type of the array.

Am I right and are there (I am almost positive there must be) other such cases?

Sorry for the trivial question, I am a Java dev and I am rather new to C++.

Thanks!

Weatherboarding answered 29/1, 2011 at 21:42 Comment(3)
Be aware that all obejcts in the array will always have the same type. If you put objects of a sub-class in there, you will experience slicing.Flong
Go with an STL container, like std::vector.Asseveration
Both the answer by GManNickG and Nawaz are correct. @Nawaz has mentioned the case where the array is passed to a function and then the count is calculated inside that called function.Sadick
P
39

Let's say I have an array arr. When would the following not give the number of elements of the array: sizeof(arr) / sizeof(arr[0])?

One thing I've often seen new programmers doing this:

void f(Sample *arr)
{
   int count = sizeof(arr)/sizeof(arr[0]); //what would be count? 10?
}

Sample arr[10];
f(arr);

So new programmers think the value of count will be 10. But that's wrong.

Even this is wrong:

void g(Sample arr[]) //even more deceptive form!
{
   int count = sizeof(arr)/sizeof(arr[0]); //count would not be 10  
}

It's all because once you pass an array to any of these functions, it becomes pointer type, and so sizeof(arr) would give the size of pointer, not array!


EDIT:

The following is an elegant way you can pass an array to a function, without letting it to decay into pointer type:

template<size_t N>
void h(Sample (&arr)[N])
{
    size_t count = N; //N is 10, so would be count!
    //you can even do this now:
    //size_t count = sizeof(arr)/sizeof(arr[0]);  it'll return 10!
}
Sample arr[10];
h(arr); //pass : same as before!
Pneumatograph answered 29/1, 2011 at 21:49 Comment(12)
Nawaz is correct here, new programmers sometimes do this in error because they do not understand that while arr in f() can be used as an array, the function f() only knows that arr is a pointer (thus sizeof(arr) == sizeof(Sample *)). This is improper use of a construct that is valid and useful when used correctly.Gunny
Thanks! So in this case, one would need to supply the number of elements of the array?Weatherboarding
@Albus Dumbledore: see the edit in my answer. It explains you a nice solution!Pneumatograph
@Albus: Typically, if your function works over a range then you design it to work with iterators (or your favorite generic range method), and not a particular container.Gimp
Thanks a lot! Just to clarify: all this template magic is done at compile time, so if the number of elements of arr wasn't a constant it wouldn't have worked as it would have required a dynamic array, i.e. a pointer. Am I talking nonsense?!Weatherboarding
@Albus: If it's an array, then this function template would work, because size of arrays in C++ is known at compile time. If it's dynamically allocated pointer (you call it dynamic array), then this would not work. You better work with std::vector.Pneumatograph
@GMan, I am not too deep into the with the STL, but what you say sounds reasonable even for a Java dev.Weatherboarding
Thanks Nawaz. All cleared now. I'll continue reading my nice little book then. :-)Weatherboarding
@AlbusDumbledore: Arrays, if they have a size, have a compile-time constant size.Blare
@Fred: I don't find that qualification useful. In C++, incomplete types have no size, so when speaking about the size of things we already know we're not talking about incomplete types. (And yes, I know you already know that. That is, yes we agree, but I think your objections were barred out-right when the discussion was about sizes.)Gimp
@GMan: I think you're right in that it probably seems I'm emphasizing it more than it warrants, especially from a POV other than of a language lawyer.Blare
Gosh, @GMan, I didn't understand a word of it!Weatherboarding
M
13

Since C++17 you can also use the standardized free function: std::size(container) which will return the amount of elements in that container.

example:

std::vector<int> vec = { 1, 2, 3, 4, 8 };
std::cout << std::size(vec) << "\n\n";    // 5

int A[] = {40,10,20};
std::cout << std::size(A) << '\n';      // 3
Macaulay answered 17/9, 2020 at 9:7 Comment(1)
This is very awesomeGerber
D
9

Arrays in C++ are very different from those in Java in that they are completely unmanaged. The compiler or run-time have no idea whatsoever what size the array is.

The information is only known at compile-time if the size is defined in the declaration:

char array[256];

In this case, sizeof(array) gives you the proper size.

If you use a pointer as an array however, the "array" will just be a pointer, and sizeof will not give you any information about the actual size of the array.

STL offers a lot of templates that allow you to have arrays, some of them with size information, some of them with variable sizes, and most of them with good accessors and bounds checking.

Decretive answered 29/1, 2011 at 21:46 Comment(2)
+1. And that not only goed for arrays. A lot is not managed in C++ that is in Java. You'll need to remember to do a lot of cleaning up (releasing previously allocated variables and memory). :)Raviv
@GolezTrol: You don't have to remember anything, you use smart pointers.Gimp
G
9

There are no cases where, given an array arr, that the value of sizeof(arr) / sizeof(arr[0]) is not the count of elements, by the definition of array and sizeof.

In fact, it's even directly mentioned (§5.3.3/2):

.... When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element.

Emphasis mine. Divide by the size of an element, sizeof(arr[0]), to obtain n.

Gimp answered 29/1, 2011 at 21:46 Comment(3)
Would it be true to say that this expression is a constant determined at compile time, because any other implementation is done on pointers?Atalya
@Daniel: It's a constant expression, yes, but I'm afraid I don't understand the second half of your question.Gimp
Upon returning back to it, I don't understand it either. Thanks for the reply.Atalya
G
4

No that would still produce the right value because you must define the array to be either all elements of a single type or pointers to a type. In either case the array size is known at compile time so sizeof(arr) / sizeof(arr[0]) always returns the element count.

Here is an example of how to use this correctly:

int nonDynamicArray[ 4 ];

#define nonDynamicArrayElementCount ( sizeof(nonDynamicArray) / sizeof(nonDynamicArray[ 0 ]) )

I'll go one further here to show when to use this properly. You won't use it very often. It is primarily useful when you want to define an array specifically so you can add elements to it without changing a lot of code later. It is a construct that is primarily useful for maintenance. The canonical example (when I think about it anyway ;-) is building a table of commands for some program that you intend to add more commands to later. In this example to maintain/improve your program all you need to do is add another command to the array and then add the command handler:

char        *commands[] = {  // <--- note intentional lack of explicit array size
    "open",
    "close",
    "abort",
    "crash"
};

#define kCommandsCount  ( sizeof(commands) / sizeof(commands[ 0 ]) )

void processCommand( char *command ) {
    int i;

    for ( i = 0; i < kCommandsCount; ++i ) {
        // if command == commands[ i ] do something (be sure to compare full string)
    }
}
Gunny answered 29/1, 2011 at 21:46 Comment(7)
This is not true. Or, it is only true for fixes size arrays.Raviv
@GolezTrol: It's always true. Arrays are, by definition, fixed in size.Gimp
It is always true for arrays defined at compile time. If you define an array as a pointer-to-type then use dynamic allocation (new) then this construct doesn't work.Gunny
@Fred: Fair, but I meant in the context of getting the size of an array with sizeof.Gimp
Could be that the OP is using the other kind, right... I mean, in the context of the question being that sizeof is not working. :)Raviv
@GolezTrol: I don't see that anywhere in the question.Gimp
@GolezTrol: Your comment was technically right only with the right interpretation of "fixed size arrays". If you mean using pointers, then you are wrong in "this is not true" because pointers are not arrays in the first place. And incomplete array types (as I showed in my example) are very rarely used for objects.Blare
H
2

_countof(my_array) in MSVC

I can thing of only one case: the array contains elements that are of different derived types of the type of the array.

Elements of an array in C++ are objects, not pointers, so you cannot have derived type object as an element.

And like mentioned above, sizeof(my_array) (like _countof() as well) will work just in the scope of array definition.

Hydrous answered 15/7, 2016 at 11:13 Comment(0)
K
1

First off, you can circumvent that problem by using std::vector instead of an array. Second, if you put objects of a derived class into an array of a super class, you will experience slicing, but the good news is, your formula will work. Polymorphic collections in C++ are achieved using pointers. There are three major options here:

Kirst answered 29/1, 2011 at 21:46 Comment(10)
Polymorphic collections in C++ are achieved using pointers - aha!Weatherboarding
@Albus: Just to make this totally clear. There is no reason to prefer an array over a vector, unless you use some API that requires it. Use vectors and use shared_ptr s.Flong
@Space: I disagree. If I know I need n elements at compile-time, and n is small, I don't see why I'd waste my time using a std::vector.Gimp
@GMan: That is true, I exaggerated there to save a migrating Java programmer some pain. I may have gone over the top.Flong
Thanks to both of you. Well, I am also concerned with performance, i.e. working with large arrays for instance (e.g. pixels from a 10Megapixel image). Every detail of the usage of the language is of importance to me.Weatherboarding
@Albus: Vectors are guaranteed to use a continuous block of memory to store the elements, hence it is just as fast as an array.Flong
@Albus: Test instead of assume. Vectors do require at least one allocation that (non-dynamic-)arrays don't, but I strongly doubt this will be significant for a 10MP image.Blare
I would definitely use an array rather than a vector when implementing, say, a struct representing a pixel. You have to be able to justify these kinds of things with actual numbers, though. And even in the cases where the overhead of std::vector is unacceptable, you should be using boost::array (std::array in 0x) which is zero-overhead and adds object-like behaviour to arrays.Portrait
@Albus, Polymorphic collections in Java are also acheived using pointers - they're just ones that the runtime manages for you automatically. That's why NullPointerExceptions have the name they do. :) This is how reference semantics for variables are achieved.Portrait
@GMan: Yeah, apparently they give out those URLs to just anyone.Blare
P
1

Let's say I have an array arr. When would the following not give the number of elements of the array: sizeof(arr) / sizeof(arr[0])?

In contexts where arr is not actually the array (but instead a pointer to the initial element). Other answers explain how this happens.

I can thing of only one case: the array contains elements that are of different derived types of the type of the array.

This cannot happen (for, fundamentally, the same reason that Java arrays don't play nicely with generics). The array is statically typed; it reserves "slots" of memory that are sized for a specific type (the base type).

Sorry for the trivial question, I am a Java dev and I am rather new to C++.

C++ arrays are not first-class objects. You can use boost::array to make them behave more like Java arrays, but keep in mind that you will still have value semantics rather than reference semantics, just like with everything else. (In particular, this means that you cannot really declare a variable of type analogous to Foo[] in Java, nor replace an array with another one of a different size; the array size is a part of the type.) Use .size() with this class where you would use .length in Java. (It also supplies iterators that provide the usual interface for C++ iterators.)

Portrait answered 30/1, 2011 at 0:2 Comment(0)
F
1

Use the Microsoft "_countof(array)" Macro. This link to the Microsoft Developer Network explains it and offers an example that demonstrates the difference between "sizeof(array)" and the "_countof(array)" macro.

Microsoft and the "_countof(array)" Macro

Fantast answered 21/7, 2016 at 21:27 Comment(0)
G
1

It seems that if you know the type of elements in the array you can also use that to your advantage with sizeof.

int numList[] = { 0, 1, 2, 3, 4 };

cout << sizeof(numList) / sizeof(int);

// => 5
Gerber answered 9/11, 2019 at 20:28 Comment(0)
K
0

If you can not use C++17, which allows to use std::size(container), you can easily implement your own generic sizeofArray template function as a one-liner:

#include <cstddef>
#include <cstdio>

template< typename T, std::size_t N >
inline constexpr std::size_t sizeofArray( const T(&)[N] ) noexcept { return N; }

int x[10];
void* y[100]; 
long z[1000];
struct {int x; char y; long z;} s[123];

static_assert( sizeofArray(x) == 10, "error" );
static_assert( sizeofArray(y) == 100, "error" );
static_assert( sizeofArray(z) == 1000, "error" );
static_assert( sizeofArray(s) == 123, "error" );

int main() {
    puts( "ok" );
}

test it here: http://cpp.sh/8tio3

Krystin answered 17/6, 2021 at 16:24 Comment(0)
M
0

It will work if and only if arr is a C-Array (type[size]; except for function parameters!), a reference to a C-Array (type(&)[size]) or a pointer to a C-Array (type(*)[size]).

Note you should use std::size or std::ssize instead with current C++-Standards!

In C++17 you can use std::size:

int arr[] = {1, 2, 3};
auto count = std::size(arr); // type std::size_t, value == 3

In C++20 you can additionally get a signed value by using std::ssize:

int arr[] = {1, 2, 3};
auto count = std::ssize(arr); // type std::ptrdiff_t, value == 3

Also note that C++ unfortunately inherited from C that C-Arrays are never passed by value (deep copy) to functions.

void f(int a[3]);

is the same as

void f(int* a);

so you loose the information that a is an array and with this, how much elements it had. The 3 is completely ignored by the compiler!

If you want to preserve the datatype (including the array element count), you can use a pointer or a reference to an C-Array:

void f(int (&a)[3]); // reference to C-Array with 3 elements
void f(int (*a)[3]); // pointer to C-Array with 3 elements
void f(int a[3]);    // pointer to int
void f(int* a);      // pointer to int

If you want to call functions with Arrays call-by-value, you can use C++-Arrays (std::array) from the C++ standard library:

f(std::array<int, 3> a);

std::array<int, 3> arr = {1, 2, 3};
f(arr); // deep copy
Mathildamathilde answered 31/8, 2021 at 15:4 Comment(0)
P
0

Determine how many numbers are in your array.

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n[10]  ;

    int l = sizeof(n)/sizeof(n[0]);

    cout << l;

    return 0;
}
Petrinapetrine answered 23/12, 2021 at 8:35 Comment(0)
A
-2

I know is old topic but what about simple solution like while loop?

int function count(array[]) {

    int i = 0;

    while(array[i] != NULL) {

        i++;

    }

    return i;

}

I know that is slower than sizeof() but this is another example of array count.

Arbalest answered 2/11, 2015 at 8:56 Comment(2)
Because you're assuming that array[i] will equal null when it reaches the end of the array, but you've got no idea what's in that bit of memory since its over the bounds of the memory allocated for the array.Tantara
What is array is an array of pointers, some of which may be NULL?Shipentine

© 2022 - 2024 — McMap. All rights reserved.