5

I have a C++ array declared as mentioned below:

CString carray[] =
{
        "A",
        "B",
        "C",
        "D",
        "E"
}

I want to determine the length of carray at runtime. I am doing:

int iLength = sizeof(carray)/sizeof(CString);

Is this correct?

5
  • Yes, Even I do the same way, Like you, I am waiting to see whether there are any other ways of it. Commented Jul 14, 2009 at 10:25
  • Renaming this Question to "Length of an array in C" might be a good idea. Commented Jul 14, 2009 at 10:43
  • 4
    This is not "determining" the length at run-time; the length is a compile-time constant, and the given expression is constant so the compiler can simply evaluate it during compilation and substitute the proper value. Also, consider dropping the parenthesis; sizeof is not a function. Commented Jul 14, 2009 at 10:43
  • @Brock: I did ... I don't get your comment. Timbo's code is just as compile-time constant as the one version in the question. Sure, it's better since it avoids repeating the type, and there's nothing majorly wrong with it, this is how it's done. I was just pointing out that it's not a run-time computation. Commented Jul 14, 2009 at 10:47
  • Brook Woolf, you probably meant "Length of a C-style array in C++". Commented Jul 14, 2009 at 10:58

10 Answers 10

24

You can use the following function template. If you're using Boost, you can call boost::size.

template <typename T, std::size_t N>
std::size_t size(T (&)[N])
{
    return N;
}

int iLength = size(carray);

As others have already stated, however, you should prefer std::vector to C-style arrays.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 - to make it clear, it should be pointed out that the reason this should be used in C++ (obviously it won't work in C) is that it'll generate a compile-time error if you accidentally try to use a pointer, while the sizeof(ptr)/sizeof(ptr[0]) method will happily and silently give the wrong result.
17

Yes. In case the declared element type ever changes, you could also write

int iLength = sizeof(carray)/sizeof(carray[0]);

3 Comments

This works well for C, but for C++ see avakar's answer for an improved alternative. Also, consider using the non idiomatic ordering of the array index to prevent getting potentially incorrect information from types that overload operator[]: sizeof(array)/sizeof([0]array)
You probably meant sizeof(array)/sizeof(0[array]). :) Intriguing idea.
For little dramatization use sizeof(array)/sizeof(*array). Easy to remember too !
6

That is correct, as it is using metaprogramming as this:

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

You must know that this works when the compiler is seeing the array definition, but not after it has been passed to a function (where it decays into a pointer):

void f( int array[] )
{
   //std::cout << array_size( array ) << std::endl; // fails, at this point array is a pointer
   std::cout << sizeof(array)/sizeof(array[0]) << std::endl; // fails: sizeof(int*)/sizeof(int)
}
int main()
{
   int array[] = { 1, 2, 3, 4, 5 };
   f( array );
   std::cout << array_size( array ) << std::endl; // 5
   std::cout << sizeof(array)/sizeof(array[0]) << std::endl; // 5 
}

6 Comments

@avakar: as in most places, inline can be either unneeded or ignored, at the end it is just a suggestion to the compiler. But it is not redundant, a compiler could decide no generate the function for each call in its own right (with or without the inline, for what matters), even if most current compilers will inline such a small function.
It is redundant, because a function template is inline by default. Also note that inline keyword has very little to do with code inlining these days. It merely marks the function so that the linker will accept multiple (but same) definitions.
@avakar: I have gone back to the standard and did not find anywhere that function templates are inline by default. The only cross references with template and inline state that function templates (and function template methods) can be either inline or not, but there is no info about them being inline by default.
My bad, you're right, I've checked the standard and they indeed aren't inline by default. But they do not have to obey the one-definition rule and as such the inline modifier is meaningless.
With templates the symbol can be defined in more than one compilation unit that get linked into a library or executable without that multiple definition generating a linker error, but templates must obey the One Definition Rule nonetheless. A common error is using a template in one compilation unit and then using a specialization of the same template in another compilation unit. When that happens the best that you can get is a segmentation fault (at least you notice there is something wrong) and the worst unexpected behavior.
|
5

This code is correct but in most circumstances there are better ways to handle arrays in C++. Especially since this method won't work with dynamically sized arrays.

For such cases, use the standard library class std::vector that represents an array of dynamic size (i.e. you can insert and remove entries).

1 Comment

And boost::array for statically sized ones.
1

Yes, this is the correct way to do it, but it will only work in this situation where the size of array is known at compile time and is seen at the site of the sizeof( array ) statement. It will not work with dynamically sized arrays - you will need other methods for them like using a container like stl::vector or passing/storing the number of elements as a separate parameter.

Comments

0

That's not runtime, it's compile time. The way you're using is correct. Note that Visual Studio defines a _countof function that does the same.

At runtime, the length cannot be determined. You either keep a length yourself, or use std::vector

2 Comments

The existing code already keeps the length of the array. But when array changes ( any element is removed from the array ) , I have modify the lengh of the array.. I can't use std:vector because I have to modify it at many places
A vector doesn't resize when you remove an element from it. Also when allocating an vector it is possible it isn't the size you specified.
0

If you have a dynamic array, you should probably use something like an STL vector. http://www.cppreference.com/wiki/stl/vector/start

Normal arrays in C++ are fixed size and you need to manually allocate memory to expand dynamic ones.

If you know your array size at compile time, use a constant rather than a calculation.

4 Comments

I am using the constant, but the array may change at runtime( any element can be removed or added ). If the array changes , I have to remodify the constant value. I can't use the std:vector becuase this array is used at many places..please suggest some workaround for this
Why can't you use a vector? Having to use it in many places is no reason. In fact, the same would apply for a C-style array.
Not sure why I was modded down, but here's some basics on arrays: cplusplus.com/doc/tutorial/arrays
+1 There is nothing wrong with your answer. sizeof is a compile-time construct, so better remember the size than calculate it!
0

Read this article by Ivan J. Johnson in Dr. Dobbs Journal. I think it covers most of the solutions presented here. It also outlines the merits and demerits of each approach very nicely.

Comments

0

Windows SDK (i.e. windows.h header) offers the macro ARRAYSIZE which implements this functionality in a safe manner(i.e. doesn't work with non-static arrays)

Comments

0

The best way is to use a macro and use that where ever you want the size.

#define MAX_ROWS 1048
int array[MAX_ROWS];

This way you can use the MAX_ROWS even in a function where the array is passed as an argument.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.