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!

3
  • 7
    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. Commented Jan 29, 2011 at 21:55
  • Go with an STL container, like std::vector. Commented Jan 30, 2011 at 16:07
  • 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. Commented Jan 13, 2019 at 8:18

15 Answers 15

41

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!
Sign up to request clarification or add additional context in comments.

12 Comments

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.
Thanks! So in this case, one would need to supply the number of elements of the array?
@Albus Dumbledore: see the edit in my answer. It explains you a nice solution!
@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.
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?!
|
14

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

1 Comment

This is very awesome
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.

2 Comments

+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). :)
@GolezTrol: You don't have to remember anything, you use smart pointers.
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.

3 Comments

Would it be true to say that this expression is a constant determined at compile time, because any other implementation is done on pointers?
@Daniel: It's a constant expression, yes, but I'm afraid I don't understand the second half of your question.
Upon returning back to it, I don't understand it either. Thanks for the reply.
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)
    }
}

7 Comments

This is not true. Or, it is only true for fixes size arrays.
@GolezTrol: It's always true. Arrays are, by definition, fixed in size.
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.
@Fred: Fair, but I meant in the context of getting the size of an array with sizeof.
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. :)
|
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.

Comments

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:

10 Comments

Polymorphic collections in C++ are achieved using pointers - aha!
@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.
@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.
@Albus: Vectors are guaranteed to use a continuous block of memory to store the elements, hence it is just as fast as an array.
@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.
|
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.)

Comments

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

Comments

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

Comments

1

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

Comments

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

Comments

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;
}

Comments

0
struct DXGINames
{
    char name[64];
    int number;
};

DXGINames DXGINamesArray[] =
{
"DXGI_FORMAT_UNKNOWN", 0,
"DXGI_FORMAT_R32G32B32A32_TYPELESS", 1,
"DXGI_FORMAT_R32G32B32A32_FLOAT", 2,
"DXGI_FORMAT_R32G32B32A32_UINT", 3,
"DXGI_FORMAT_R32G32B32A32_SINT", 4,
"DXGI_FORMAT_R32G32B32_TYPELESS", 5,
"DXGI_FORMAT_R32G32B32_FLOAT", 6,
"DXGI_FORMAT_R32G32B32_UINT", 7,
"DXGI_FORMAT_R32G32B32_SINT", 8,
"DXGI_FORMAT_R16G16B16A16_TYPELESS", 9
};

m_DXGINames = DXGINamesArray;

int count = sizeof(DXGINamesArray) / sizeof(DXGINames);

OR

#define countArray(a, b) (sizeof(a) / sizeof(b))

int c = countArray(DXGINamesArray, DXGINames);

Comments

-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.

2 Comments

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.
What is array is an array of pointers, some of which may be NULL?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.