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?

Maxpm
  • 24,113
  • 33
  • 111
  • 170
Ashish Ashu
  • 14,169
  • 37
  • 86
  • 117
  • Yes, Even I do the same way, Like you, I am waiting to see whether there are any other ways of it. – Narendra N Jul 14 '09 at 10:25
  • Renaming this Question to "Length of an array in C" might be a good idea. – Brock Woolf Jul 14 '09 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. – unwind Jul 14 '09 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. – unwind Jul 14 '09 at 10:47
  • Brook Woolf, you probably meant "Length of a C-style array in C++". – avakar Jul 14 '09 at 10:58

10 Answers10

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.

avakar
  • 32,009
  • 9
  • 68
  • 103
  • 3
    +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. – Michael Burr Jul 14 '09 at 17:09
17

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

int iLength = sizeof(carray)/sizeof(carray[0]);
Timbo
  • 27,472
  • 11
  • 50
  • 75
  • 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) – Michael Burr Jul 14 '09 at 17:45
  • 1
    You probably meant `sizeof(array)/sizeof(0[array])`. :) Intriguing idea. – avakar Jul 14 '09 at 19:06
  • 1
    For little dramatization use `sizeof(array)/sizeof(*array)`. Easy to remember too ! – Saradhi Sep 02 '13 at 10:37
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 
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    @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. – David Rodríguez - dribeas Jul 14 '09 at 12:08
  • 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 Jul 14 '09 at 13:31
  • 1
    @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. – David Rodríguez - dribeas Jul 14 '09 at 21:38
  • 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. – avakar Jul 15 '09 at 08:34
  • 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. – David Rodríguez - dribeas Jul 15 '09 at 20:21
  • I stand corrected. I was referring to paragraph 3.2/3, section 3.2 is named One Definition Rule and that got me confused. Nevertheless, I stand by my first comment. As far as the standard is concerned, your program is in all respects equivalent to a program, in which the `inline` keyword was removed. This is also true of modern compilers, which usually no longer consider `inline` an optimization hint (or at least allow this behavior to be set from command line). – avakar Jul 19 '09 at 15:14
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).

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
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.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
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

xtofl
  • 40,723
  • 12
  • 105
  • 192
  • 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 – Ashish Ashu Jul 14 '09 at 10:28
  • 1
    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. – graham.reeds Jul 14 '09 at 10:56
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.

Glenn
  • 5,334
  • 4
  • 28
  • 31
  • 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 – Ashish Ashu Jul 14 '09 at 10:31
  • 1
    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. – Konrad Rudolph Jul 14 '09 at 10:39
  • Not sure why I was modded down, but here's some basics on arrays: http://www.cplusplus.com/doc/tutorial/arrays/ – Glenn Jul 14 '09 at 10:47
  • 3
    +1 There is nothing wrong with your answer. sizeof is a compile-time construct, so better remember the size than calculate it! – Abhay Jul 14 '09 at 10:52
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.

Abhay
  • 7,092
  • 3
  • 36
  • 50
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)

Diaa Sami
  • 3,249
  • 24
  • 31
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.

Saradhi
  • 477
  • 6
  • 13