1381

How do I determine the size of my array in C?

That is, the number of elements the array can hold?

Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
Mark Harrison
  • 297,451
  • 125
  • 333
  • 465
  • 6
    For type-safety see [stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers](https://stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers) – T S Aug 25 '17 at 15:21
  • An answer is the subject of [a meta question](https://meta.stackoverflow.com/questions/420337/). – Peter Mortensen Sep 14 '22 at 21:52
  • If the answers don't make sense, remember that when C compiles to assembly, the size information of the array is lost. When you declare something like `int foo[5];` that 5 appears nowhere in your compiled executable. – puppydrum64 Dec 13 '22 at 18:24
  • 2
    ```sizeof(array)/sizeof(array[0])``` – Supergamer Jan 09 '23 at 06:48

25 Answers25

1682

Executive summary:

int a[17];
size_t n = sizeof(a)/sizeof(a[0]);

Full answer:

To determine the size of your array in bytes, you can use the sizeof operator:

int a[17];
size_t n = sizeof(a);

On my computer, ints are 4 bytes long, so n is 68.

To determine the number of elements in the array, we can divide the total size of the array by the size of the array element. You could do this with the type, like this:

int a[17];
size_t n = sizeof(a) / sizeof(int);

and get the proper answer (68 / 4 = 17), but if the type of a changed you would have a nasty bug if you forgot to change the sizeof(int) as well.

So the preferred divisor is sizeof(a[0]) or the equivalent sizeof(*a), the size of the first element of the array.

int a[17];
size_t n = sizeof(a) / sizeof(a[0]);

Another advantage is that you can now easily parameterize the array name in a macro and get:

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))

int a[17];
size_t n = NELEMS(a);
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Mark Harrison
  • 297,451
  • 125
  • 333
  • 465
  • But isn't `sizeof(int)` more performant than `sizeof(*int_arr)` in runtime? Or is the translated code identical? – Pacerier Sep 21 '13 at 05:43
  • 7
    The generated code will be identical, since the compiler knows the type of *int_arr at compile time (and therefore the value of sizeof(*int_arr)). It will be a constant, and the compiler can optimize accordingly. – Mark Harrison Sep 21 '13 at 19:58
  • Which compiler are you using? – Pacerier Sep 22 '13 at 05:01
  • 11
    It should be the case with all compilers, since the results of sizeof is defined as a compile-time constant. – Mark Harrison Sep 22 '13 at 05:39
  • 1
    It's interesting how this seems to work when the array is empty. – Raffi Khatchadourian Dec 09 '13 at 23:42
  • 648
    **Important**: Don't stop reading here, read the next answer! This only works for arrays on the _stack_, e.g. if you're using malloc() or accessing a function parameter, you're out of luck. See below. – Markus Jan 27 '14 at 14:21
  • @AlexMelbourne, I reverted your suggested edit as it produced incorrect results for the expression p+1. – Mark Harrison Feb 27 '14 at 05:55
  • 8
    For Windows API programming in C or C++, there is the `ARRAYSIZE` makro defined in `WinNT.h` (which gets pulled in by other headers). So WinAPI users don't need to define their own makro. – Lumi Apr 23 '14 at 08:24
  • 34
    @Markus it works for any variable which has an array type; this doesn't have to be "on the stack". E.g. `static int a[20];` . But your comment is useful to readers that may not realize the difference between an array and a pointer. – M.M Oct 06 '14 at 02:45
  • 2
    on many unix systems 'sys/param.h' defines 'nitems(x)' similarly. – John Meacham Jan 14 '15 at 12:49
  • any idea how to achieve this without using .length of array as required here http://www.geeksforgeeks.org/reorder-a-array-according-to-given-indexes/ – Key_coder Nov 02 '15 at 14:52
  • "But isn't sizeof(int) more performant than sizeof(*int_arr) in runtime?" -- of course not, since sizeof is a compile-time operation. `sizeof(function_that_takes_very_very_long_to_execute)` also doesn't take any extra time ... all that matters is the type that the function returns. – Jim Balter Dec 22 '15 at 23:59
  • 1
    If it is a multidimensional array like int a[2][3] , then sizeof will give 2*3*4 , the same as sizeof for int a[6] so take care with of not determining the array from its size! – Sourab Reddy Jan 26 '16 at 10:02
  • 3
    We should remove this as correct answer. Read @Markus comment. I wasted several hours because this answer does not work in malloc case. – Smart Home May 15 '16 at 22:51
  • 2
    Better to use `size_t n = sizeof(a) / sizeof(a[0]);` than `int n = sizeof(a) / sizeof(a[0]);` as `size_t` is the return type of `sizeof()`. – chux - Reinstate Monica May 20 '16 at 21:19
  • 1
    What about the Array of characters? – meditat Aug 28 '18 at 02:33
  • 1
    And what if the array is declared like `int a[];`? – preciousbetine Jan 30 '19 at 16:19
  • Is there a way to check in the macro that the array is really an array and not a pointer? – starblue Jan 09 '20 at 09:33
  • 2
    You do not need to use `sizeof(a) / sizeof(a[0])` if `a` is an array of either `char`, `unsigned char` or `signed char` - Quote from C18,6.5.3.4/4: *"When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1."* In this case you can simply do `sizeof(a)`, as pointed out in my dedicated [answer](https://stackoverflow.com/a/60565087/12139179). – RobertS supports Monica Cellio Mar 06 '20 at 13:41
  • @JohnMeacham Do you know which systems, and maybe some link pointing to that information? I checked my system (Debian with libbsd installed) and I don't have it. I would like to be able to use it if it already exists, instead of writing my own copy. – alx - recommends codidact Apr 22 '20 at 19:57
  • @starblue Yes there is. See the macro `must_be_array()` in my answer below. – alx - recommends codidact Jul 06 '20 at 07:46
  • @CacahueteFrito That assumes some gcc extensions. – starblue Jul 25 '20 at 10:39
  • @starblue Yes, that assumes some compiler extensions. In standard C I don't think it's possible. You will need something like [__builtin_types_compatible_p](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) and [typeof](https://gcc.gnu.org/onlinedocs/gcc/Typeof.html). GCC and Clang have these. In other compilers, however, you will need to find a replacement, or it may be impossible to achieve. – alx - recommends codidact Jul 25 '20 at 11:02
  • 1
    This worked for an array that its size was not initially specified eg `int coins[] = {25, 10, 5, 1}` – EdgeDev Apr 18 '21 at 09:08
  • what will be the approach if we pass the array into a function procedure and if we need to get the number of elements inside the function ? For example, within the find_missing(int *data_array) function, I need to get the number elements of data_array within the find_missing function. – Dig The Code Aug 21 '21 at 17:50
1081

The sizeof way is the right way iff you are dealing with arrays not received as parameters. An array sent as a parameter to a function is treated as a pointer, so sizeof will return the pointer's size, instead of the array's.

Thus, inside functions this method does not work. Instead, always pass an additional parameter size_t size indicating the number of elements in the array.

Test:

#include <stdio.h>
#include <stdlib.h>

void printSizeOf(int intArray[]);
void printLength(int intArray[]);

int main(int argc, char* argv[])
{
    int array[] = { 0, 1, 2, 3, 4, 5, 6 };

    printf("sizeof of array: %d\n", (int) sizeof(array));
    printSizeOf(array);

    printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
    printLength(array);
}

void printSizeOf(int intArray[])
{
    printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}

void printLength(int intArray[])
{
    printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}

Output (in a 64-bit Linux OS):

sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2

Output (in a 32-bit windows OS):

sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
Elideb
  • 11,660
  • 1
  • 16
  • 16
  • 1
    Out of curiosity does the compiler treat arrays the same as pointers when they are parameterized? – lukecampbell Jun 24 '13 at 17:46
  • 13
    why is `length of parameter:2` if only a pointer to the 1st array element is passed? – Bbvarghe Aug 05 '13 at 02:42
  • 23
    @Bbvarghe That's because pointers in 64bit systems are 8 bytes (sizeof(intArray)), but ints are still (usually) 4 bytes long (sizeof(intArray[0])). – Elideb Aug 28 '13 at 17:33
  • 1
    @Elideb, so what would be the correct code for the functions `printSizeOf` and `printLength`? – Pacerier Sep 21 '13 at 05:47
  • 23
    @Pacerier: There is no correct code - the usual solution is to pass the length along with the array as a separate argument. – Jean Hominal Oct 05 '13 at 13:58
  • 13
    Wait, so there's no way to access the array directly from a pointer and see its size? New to C here. – sudo Dec 01 '13 at 06:37
  • Why does this happen? I modified the above code to print the value of array as a pointer, and I see that it's the same in main and in the print() functions. I'm finding it very disturbing that calling the same function with the same arguments can return different results! – Nickolai Aug 08 '14 at 15:13
  • 5
    @Nickolai The main confusion here is that `sizeof` is not a function, but an operator in C/C++. If called from the same scope where the array was created, `sizeof` knows of its size. When you pass the array as a parameter, however, that size information is lost. Only a reference to the array position in memory is received by the function, so it is treated as a pointer, to all purposes. So `sizeof`, when called from inside the function, only sees a pointer, and returns the pointer's size. These rules do not apply to `sizeof` because it is not actually a function and the scope is kept. – Elideb Feb 22 '15 at 17:02
  • 4
    @Elideb Thanks for that. I think I read something like that elsewhere after I posted the comment. What ultimately helped me understand it is that when sizeof is called in the same scope that an array is declared, it sees its parameter as a parameter of type int[7] (using the example in the answer), but when called in another scope it sees its parameter as a parameter of type int *. Basically the same thing you said, just in my own words :) – Nickolai Feb 24 '15 at 16:09
  • Did C99 not get a new way for passing arrays? Something like: `void printSizeOf(int intArrayLen, int intArray[intArrayLen]);`. And should we not use that one? – Martin Apr 13 '15 at 07:25
  • 1
    The number of nono's / facepalms when coming from a higher level language is... over 9000? - having an operator that uses a function-like syntax (we are talking about a formal language right? the family of languages where ambiguity is not a good thing?) - the need to calculate the 'item' length of an array by using the memory size of the 'items' contained in that array: ```( sizeof(array) / sizeof(array[0])```. Oh, don't forget to ca- ```&&&LC^^%%LCLC^^^&---.L^%``` – Michahell Apr 18 '15 at 00:33
  • 7
    @Michael Trouw: you can use the operator syntax if is makes you feel better: `(sizeof array / sizeof *array)`. – chqrlie Apr 28 '15 at 17:00
  • 1
    @chqrlie I will try to evade these ancient programming rites for as long as I can. Your version does make me feel better, even though I know the situation is comparable to returning someone's bike with a nice paint while the original problem was that it had a leak tire. – Michahell Apr 28 '15 at 20:00
  • 1
    There is no such thing as "an array received as a parameter" in C. (Unless you count arrays inside structs/unions). So iff you are dealing with an array received as a parameter, then Obama's a pink hedgehog. – user253751 Oct 12 '15 at 01:10
  • 1
    I haven't used sizeof() in a long while, but shouldn't sizeof(a) mean sizeof(&a[0])? Now since address "&a[0]" would be 64 bits meaning 8 bytes wide, shouldn't "a" (which also means the same thing- address of base element) be worth 8 bytes also? Meaning sizeof(a) should be 8 bytes. If not, then what is the difference between sizeof(a) and sizeof(&a[0])? Pls remember, its been a very long time since i last used this function, so pls remind me how it functions. – rahulbsb Jun 15 '16 at 20:57
  • If the number of elements is known, why bother send to a function ? just compute it onspot by multiplying the sizeof(type) – Tony Tannous Aug 07 '17 at 10:18
  • @MichaelTrouw don't higher level languages suffer from the same ambiguity? i.e. inserting parens _when they aren't necessary_ to any unary operator "uses function-like syntax" as you say. you won't get complaints from the perl or python interpreters by adding parens around the operands to unary negation, addition, increment, decrement, etc. maybe the real problem is that it doesn't have a convenient, non-alphabetic symbol instead of the much-more-readable `sizeof` identifier – ardnew Dec 04 '17 at 00:08
  • @ardnew well, yes, but that is optional, not mandatory. And yes again, a dedicated symbol could help. Or just more helper functions, but that will probably be dismissed as typical higher order language mentality.. For example, a hypothetical `sizeofItem(IntArray)` would that be such a stupid idea? would you run into 10 other C specific problems? I don't know and tbh I don't care anymore. I don't have to work with C / C++ anymore which probably will extend my life with 1-10 years of joyful non C / C++ development. – Michahell Dec 06 '17 at 18:54
  • 3
    @MichaelTrouw but they aren't mandatory in C either as chqrlie demonstrated with your very own example. but yeah i digress, its silly to compare C to your HLLs, they have very different goals and intentions. also, being a professional developer in any language will unfortunately lessen your lifespan by 1-10 years, so you're only breaking even :( – ardnew Dec 08 '17 at 17:40
  • Is there a mecanism of align that can cause sizeof to return at minimum a bigger value even when there are less parameters? – Sandburg Jul 13 '18 at 14:03
  • 1
    The tradition is pass the length as another parameter in C, am I right? – igonejack Apr 07 '19 at 00:27
  • 1
    @sudo You *can* always pass a pointer to an array of specific length which keeps its pointee's size information. Like `int countElems(int (*arr)[42]) { return sizeof(*arr)/sizeof(**arr); }`. This is an obviously nonsensical demonstration, but there may be situations where you always have buffers of a given size (frame buffers, telegram data) and just want to break the code in handy chunks. Then you can use this more elegant way and avoid size arguments. This becomes *really* useful, of course, with C++ templates, when the size is an int template parameter (std::array is based on it). – Peter - Reinstate Monica Nov 14 '19 at 11:26
  • @Peter-ReinstateMonica I guess that you would use macros instead of magic numbers for real code. My concern here is the following: Let's say you create a function `int foo(int (*a)[FILENAME_MAX]);`, and `FILENAME_MAX` is 4096 when you compile the function. And later you use the function in a system where `FILENAME_MAX` is 2048. The compiler will not warn you, but you will have Undefined Behaviour. It's a bit dangerous; there's no perfect solution, and this might be unlikely, but it's very dangerous, and I wouldn't trust it very much. I would pass the size as an argument always. – alx - recommends codidact May 09 '20 at 21:49
  • Why do you caste the `sizeof` result to `int`. `printf()` has the format specifier `%zu` to print a `size_t` type. – 12431234123412341234123 Sep 25 '20 at 17:43
178

It is worth noting that sizeof doesn't help when dealing with an array value that has decayed to a pointer: even though it points to the start of an array, to the compiler it is the same as a pointer to a single element of that array. A pointer does not "remember" anything else about the array that was used to initialize it.

int a[10];
int* p = a;

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
Magnus Hoff
  • 21,529
  • 9
  • 63
  • 82
  • 2
    I remember that the CRAY had C with `char` of 32 bits. All the standard says is that integer values from 0 to 127 can be represented, and its range is at least either -127 to 127 (char is signed) or 0 to 255 (char is unsigned). – vonbrand Feb 01 '13 at 20:57
  • 1
    @ Magnus: The standard defines sizeof as yielding the number of bytes in the object and that sizeof (char) is always one. The number of bits in a byte is implementation specific. Edit: ANSI C++ standard section 5.3.3 Sizeof: "The sizeof operator yields the number of bytes in the object representation of its operand. [...] sizeof (char), sizeof (signed char) and sizeof (unsigned char) are 1; the result of sizeof applied to any other fundamental type is implementation-defined." – Skizz Sep 01 '08 at 08:34
  • 1
    Section 1.6 The C++ memory model: "The fundamental storage unit in the C++ memory model is the byte. A byte is at least large enough to contain any member of the basic execution character set and is composed of a contiguous sequence of bits, the number of which is implementation-defined." – Skizz Sep 01 '08 at 08:34
63

The sizeof "trick" is the best way I know, with one small but (to me, this being a major pet peeve) important change in the use of parenthesis.

As the Wikipedia entry makes clear, C's sizeof is not a function; it's an operator. Thus, it does not require parenthesis around its argument, unless the argument is a type name. This is easy to remember, since it makes the argument look like a cast expression, which also uses parenthesis.

So: If you have the following:

int myArray[10];

You can find the number of elements with code like this:

size_t n = sizeof myArray / sizeof *myArray;

That, to me, reads a lot easier than the alternative with parenthesis. I also favor use of the asterisk in the right-hand part of the division, since it's more concise than indexing.

Of course, this is all compile-time too, so there's no need to worry about the division affecting the performance of the program. So use this form wherever you can.

It is always best to use sizeof on an actual object when you have one, rather than on a type, since then you don't need to worry about making an error and stating the wrong type.

For instance, say you have a function that outputs some data as a stream of bytes, for instance across a network. Let's call the function send(), and make it take as arguments a pointer to the object to send, and the number of bytes in the object. So, the prototype becomes:

void send(const void *object, size_t size);

And then you need to send an integer, so you code it up like this:

int foo = 4711;
send(&foo, sizeof (int));

Now, you've introduced a subtle way of shooting yourself in the foot, by specifying the type of foo in two places. If one changes but the other doesn't, the code breaks. Thus, always do it like this:

send(&foo, sizeof foo);

Now you're protected. Sure, you duplicate the name of the variable, but that has a high probability of breaking in a way the compiler can detect, if you change it.

Neuron
  • 5,141
  • 5
  • 38
  • 59
unwind
  • 391,730
  • 64
  • 469
  • 606
  • Btw, are they identical instructions at the processor level? Does `sizeof(int)` require lesser instructions than `sizeof(foo)`? – Pacerier Sep 21 '13 at 06:53
  • @Pacerier: no, they are identical. Think of `int x = 1+1;` versus `int x = (1+1);`. Here, parentheses are purely absolutely just aesthetic. – quetzalcoatl Oct 05 '13 at 13:22
  • @Aidiakapi That's not true, consider C99 VLAs. – unwind Jan 13 '16 at 13:18
  • @unwind Thanks, I stand corrected. To correct my comment, `sizeof` will always be constant in C++ and C89. With C99's variable length arrays, it may be evaluated at runtime. – Aidiakapi Jan 13 '16 at 16:47
  • 5
    `sizeof` may be an operator but it should be treated as a function according to Linus Torvalds. I agree. Read his rational here: https://lkml.org/lkml/2012/7/11/103 – SO Stinks Mar 17 '20 at 14:55
  • @Dr.PersonPersonII Okay, I disagree and this is one case where I just won't fall for an argument from authority. One counter-argument is that I think making things look like something they are not, in code, is often a bad idea. – unwind Mar 20 '20 at 09:48
  • 1
    Why should omitting parens make it more readable? `sizeof myArray / sizeof *myArray;` could mean `sizeof(myArray / sizeof *myArray);` for example. I know it wouldn't make sense, but it's still better to be explicit IMHO. – Eric Duminil Nov 28 '20 at 12:24
  • Torvalds is by no means an authority of C programming (and could be taking lessons in mature communication from a teenage boy), but that aside it's a well-known best practice not to assume that everyone knows and remembers every little dirty detail of operator precedence rules, and therefore use extra parenthesis when precedence isn't obvious. A more authoritative source saying the same thing would be MISRA C:2012 rule 12.1. – Lundin Sep 13 '22 at 06:48
  • In case of the sizeof trick in this answer, the precedence _is_ quite obvious though - if it should at all be rewritten to clarify precedence (which I'm not sure that I agree with) then it would be `(sizeof myArray) / (sizeof *myArray)` before `sizeof(myArray) / sizeof (*myArray)`. – Lundin Sep 13 '22 at 06:49
42
int size = (&arr)[1] - arr;

Check out this link for explanation

Arjun Sreedharan
  • 11,003
  • 2
  • 26
  • 34
  • 9
    Small nitpick: the result of pointer subtraction has type `ptrdiff_t`. (Typically on 64-bit system, this will be a larger type than `int`). Even if you change `int` to `ptrdiff_t` in this code, it still has a bug if `arr` takes up more than half of the address space. – M.M Oct 06 '14 at 02:37
  • 2
    @M.M Another small nitpick: Depending on your system architecture, the address space is not nearly as large as the pointer size on most systems. Windows for example limits address space for 64-bit applications to 8TB or 44 bits. So even if you have an array larger than half of your address space 4.1TB for example, it'll not be a bug. Only if your address space exceeds 63-bits on those systems, it's possible to even encounter such bug. In general, don't worry about it. – Aidiakapi Jan 08 '16 at 17:00
  • 1
    @Aidiakapi on 32-bit x86 Linux or on Windows with `/3G` option you have 3G/1G user/kernel split, which allows you to have arrays size up to 75% of address space size. – Ruslan Jan 10 '18 at 12:26
  • 1
    Consider `foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];` as global variables. `buf3[]` declaration failes as `(&buf1)[1] - buf1` is not a constant. – chux - Reinstate Monica May 21 '18 at 16:01
  • 4
    This is technically undefined behaviour as the standard explicitly disallows dereferencing past the end of an array (even if you don't try to read the stored value) – M.M Feb 16 '20 at 10:57
  • @exnihilo I mean undefined behaviour but is likely to work on most systems – M.M Mar 09 '20 at 06:16
  • 1
    @M.M He does not dereference past the array, no UB. – 12431234123412341234123 Sep 25 '20 at 18:02
  • 1
    @12431234123412341234123 `x[y]` is defined to mean `*(x+y)` (6.5.2.1/2), so we have `*(&arr + 1)`. The pointer `&arr + 1` does not point to an object, and in 6.5.3.2/4 it defines the behaviour of `*` only for cases where the pointer points to an object. – M.M Sep 26 '20 at 02:32
  • 1
    @M.M It is valid for a pointer to point one element past the last object of an array. `(&arr)[1]` is a pointer to after the array `arr` which is completely valid. As long as he not dereferences the resulting pointer, which he does not do. – 12431234123412341234123 Sep 28 '20 at 13:54
  • 1
    @12431234123412341234123 `(&arr)[1]` is not a pointer . `(&arr + 1)` is a pointer past the end, and `*(&arr + 1)` applies the dereference operator to that pointer . Which he does do, because `(&arr)[1]` is by definition identical to `*(&arr + 1)`. – M.M Sep 29 '20 at 02:50
  • 1
    @12431234123412341234123 Comments are for clarification of the answer, not extended arguments like this. I have provided references to the Standard proving that `(&arr)[1]` is undefined behaviour, which you have ignored . If you want to waste time further on this then post a new question about the code, or read existing questions about this. Rather than continuing to post comments (I won't be responding further) – M.M Sep 29 '20 at 03:00
  • @M.M "`(&arr)[1]` is not a pointer " It is. "`(&arr + 1)` is a pointer" yes, a pointer to pointer (from a array to pointer decay). This is why `*(&arr + 1)` or `(&arr)[1]` is still a pointer. Otherwise `(&arr)[1] - arr` would give you an address and not an integer (difference of 2 pointer locations). – 12431234123412341234123 Sep 29 '20 at 15:03
  • in the article you mentionned there is a PS: **This works only for arrays, not when you take pointers*** – serge Nov 01 '20 at 21:54
42

I would advise to never use sizeof (even if it can be used) to get any of the two different sizes of an array, either in number of elements or in bytes, which are the last two cases I show here. For each of the two sizes, the macros shown below can be used to make it safer. The reason is to make obvious the intention of the code to maintainers, and difference sizeof(ptr) from sizeof(arr) at first glance (which written this way isn't obvious), so that bugs are then obvious for everyone reading the code.


TL;DR:

#define ARRAY_SIZE(arr)   (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_BYTES(arr)  (sizeof(arr) + must_be_array(arr))

must_be_array(arr) (defined below) IS needed as -Wsizeof-pointer-div is buggy (as of april/2020):

#define is_same_type(a, b)  __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr)       (!is_same_type((arr), &(arr)[0]))
#define must_be(e)                                                      \
(                                                                       \
        0 * (int)sizeof(                                                \
                struct {                                                \
                        static_assert(e);                               \
                        char ISO_C_forbids_a_struct_with_no_members__;  \
                }                                                       \
        )                                                               \
)
#define must_be_array(arr)  must_be(is_array(arr))

There have been important bugs regarding this topic: https://lkml.org/lkml/2015/9/3/428

I disagree with the solution that Linus provides, which is to never use array notation for parameters of functions.

I like array notation as documentation that a pointer is being used as an array. But that means that a fool-proof solution needs to be applied so that it is impossible to write buggy code.

From an array we have three sizes which we might want to know:

  • The size of the elements of the array
  • The number of elements in the array
  • The size in bytes that the array uses in memory

The size of the elements of the array

The first one is very simple, and it doesn't matter if we are dealing with an array or a pointer, because it's done the same way.

Example of usage:

void foo(size_t nmemb, int arr[nmemb])
{
        qsort(arr, nmemb, sizeof(arr[0]), cmp);
}

qsort() needs this value as its third argument.


For the other two sizes, which are the topic of the question, we want to make sure that we're dealing with an array, and break the compilation if not, because if we're dealing with a pointer, we will get wrong values. When the compilation is broken, we will be able to easily see that we weren't dealing with an array, but with a pointer instead, and we will just have to write the code with a variable or a macro that stores the size of the array behind the pointer.


The number of elements in the array

This one is the most common, and many answers have provided you with the typical macro ARRAY_SIZE:

#define ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]))

Recent versions of compilers, such as GCC 8, will warn you when you apply this macro to a pointer, so it is safe (there are other methods to make it safe with older compilers).

It works by dividing the size in bytes of the whole array by the size of each element.

Examples of usage:

void foo(size_t nmemb)
{
        char buf[nmemb];

        fgets(buf, ARRAY_SIZE(buf), stdin);
}

void bar(size_t nmemb)
{
        int arr[nmemb];

        for (size_t i = 0; i < ARRAY_SIZE(arr); i++)
                arr[i] = i;
}

If these functions didn't use arrays, but got them as parameters instead, the former code would not compile, so it would be impossible to have a bug (given that a recent compiler version is used, or that some other trick is used), and we need to replace the macro call by the value:

void foo(size_t nmemb, char buf[nmemb])
{
        fgets(buf, nmemb, stdin);
}

void bar(size_t nmemb, int arr[nmemb])
{
        for (size_t i = nmemb - 1; i < nmemb; i--)
                arr[i] = i;
}

The size in bytes that the array uses in memory

ARRAY_SIZE is commonly used as a solution to the previous case, but this case is rarely written safely, maybe because it's less common.

The common way to get this value is to use sizeof(arr). The problem: the same as with the previous one; if you have a pointer instead of an array, your program will go nuts.

The solution to the problem involves using the same macro as before, which we know to be safe (it breaks compilation if it is applied to a pointer):

#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

How it works is very simple: it undoes the division that ARRAY_SIZE does, so after mathematical cancellations you end up with just one sizeof(arr), but with the added safety of the ARRAY_SIZE construction.

Example of usage:

void foo(size_t nmemb)
{
        int arr[nmemb];

        memset(arr, 0, ARRAY_BYTES(arr));
}

memset() needs this value as its third argument.

As before, if the array is received as a parameter (a pointer), it won't compile, and we will have to replace the macro call by the value:

void foo(size_t nmemb, int arr[nmemb])
{
        memset(arr, 0, sizeof(arr[0]) * nmemb);
}

Update (23/apr/2020): -Wsizeof-pointer-div is buggy:

Today I found out that the new warning in GCC only works if the macro is defined in a header that is not a system header. If you define the macro in a header that is installed in your system (usually /usr/local/include/ or /usr/include/) (#include <foo.h>), the compiler will NOT emit a warning (I tried GCC 9.3.0).

So we have #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) and want to make it safe. We will need C2X static_assert() and some GCC extensions: Statements and Declarations in Expressions, __builtin_types_compatible_p:

#include <assert.h>


#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr)           (!is_same_type((arr), &(arr)[0]))
#define Static_assert_array(arr) static_assert(is_array(arr))

#define ARRAY_SIZE(arr)                                                 \
({                                                                      \
        Static_assert_array(arr);                                       \
        sizeof(arr) / sizeof((arr)[0]);                                 \
})

Now ARRAY_SIZE() is completely safe, and therefore all its derivatives will be safe.


Update: libbsd provides __arraycount():

Libbsd provides the macro __arraycount() in <sys/cdefs.h>, which is unsafe because it lacks a pair of parentheses, but we can add those parentheses ourselves, and therefore we don't even need to write the division in our header (why would we duplicate code that already exists?). That macro is defined in a system header, so if we use it we are forced to use the macros above.

#inlcude <assert.h>
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>


#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr)           (!is_same_type((arr), &(arr)[0]))
#define Static_assert_array(arr) static_assert(is_array(arr))

#define ARRAY_SIZE(arr)                                                 \
({                                                                      \
        Static_assert_array(arr);                                       \
        __arraycount((arr));                                            \
})

#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

Some systems provide nitems() in <sys/param.h> instead, and some systems provide both. You should check your system, and use the one you have, and maybe use some preprocessor conditionals for portability and support both.


Update: Allow the macro to be used at file scope:

Unfortunately, the ({}) gcc extension cannot be used at file scope. To be able to use the macro at file scope, the static assertion must be inside sizeof(struct {}). Then, multiply it by 0 to not affect the result. A cast to (int) might be good to simulate a function that returns (int)0 (in this case it is not necessary, but then it is reusable for other things).

Additionally, the definition of ARRAY_BYTES() can be simplified a bit.

#include <assert.h>
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>


#define is_same_type(a, b)     __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr)          (!is_same_type((arr), &(arr)[0]))
#define must_be(e)                                                      \
(                                                                       \
        0 * (int)sizeof(                                                \
                struct {                                                \
                        static_assert(e);                               \
                        char ISO_C_forbids_a_struct_with_no_members__;  \
                }                                                       \
        )                                                               \
)
#define must_be_array(arr)      must_be(is_array(arr))

#define ARRAY_SIZE(arr)         (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_BYTES(arr)        (sizeof(arr) + must_be_array(arr))

Notes:

This code makes use of the following extensions, which are completely necessary, and their presence is absolutely necessary to achieve safety. If your compiler doesn't have them, or some similar ones, then you can't achieve this level of safety.

I also make use of the following C2X feature. However, its absence by using an older standard can be overcome using some dirty tricks (see for example: What is “:-!!” in C code?) (in C11 you also have static_assert(), but it requires a message).

  • 3
    ARRAY_SIZE is common enough to be used freely, and ARRAY_BYTES is very explicit in its name, should be defined next to ARRAY_SIZE so a user can see both easily, and by its usage, I don't think anyone reading the code has doubts about what it does. What I meant is to not use a simple `sizeof`, but use this constructions instead; if you feel like writing these constructions every time, you will likely make a mistake (very common if you copy paste, and also very common if you write them each time because they have a lot of parentheses)... – alx - recommends codidact Aug 17 '19 at 15:39
  • 4
    ..., so I stand on the main conclusion: a single `sizeof` is clearly unsafe (reasons are in the answer), and not using macros but using the constructions I provided, each time, is even more unsafe, so the only way to go is macros. – alx - recommends codidact Aug 17 '19 at 15:40
  • 4
    I think you may be confused regarding the difference between arrays and pointers. This is a fundamental concept in C, and programmers should make sure they understand this difference as part of learning C. Trying to pretend that C is another language only leads to unhappiness. – Mark Harrison Aug 18 '19 at 06:24
  • 3
    @MarkHarrison I do know the difference between pointers and arrays. But there's been times I had a function which I later refactored into little functions, and what first was an array, later was a pointer, and that's one point where if you forget to change sizeof, you screw it, and it's easy to not see one of those. – alx - recommends codidact Aug 18 '19 at 09:11
  • 4
    Don't listen to this guy. If you populate my code base with these macro's I will fire you. – Byron Jul 09 '20 at 23:21
  • @Byron I can say that Linux has very similar macros (instead of the `_Static_assert()` they use a more ugly thing that works with old C), but the rest is very similar (however, they don't have `ARRAY_BYTES()` or a signed version `ARRAY_SSIZE()`). Glibc also uses something similar. Maybe I wouldn't want to work for you. But if you downvote my answer here, and say that people shouldn't listen to it, you could give some good reasons for that. – alx - recommends codidact Jul 10 '20 at 06:37
  • One does not need to do all this redundant work if they know contexts when an array is treated as a pointer. Those who do not may be safier with this, but I'd rather look through these contexts. – Kaiyaha Oct 21 '20 at 16:22
  • @Kaiyaha @Kaiyaha 1)First of all, this should be something you write once in your life, put it in a library, and never again look at it, so all the redundant work shouldn't be a problem. 2) There is a proposal to add a new keyword `_Lengthof` to the C language that does this same thing, so hopefully this won't be a problem in the future. 3) You may write some code in a context where you have an array, and many years later someone who took over your code may change the context so that it is then a pointer, and may forget to fix it accordingly, and... there you have a bug. – alx - recommends codidact Oct 21 '20 at 16:37
  • This answer is off-topic since it relies on non-standard compiler extensions. Nobody mentioned things like gcc or Linux in the question. – Lundin Sep 12 '22 at 06:23
  • @Lundin While I slightly agree that this is an answer to GNU C, the answer to the ISO C would be "you can't do it safely", I think it's interesting to know how to do it safely in dialects of C that support it, while acknowledging that it's impossible in portable ISO C. BTW, the bits that say it's impossible to do it portably are on-topic, IMO. I'd like to think that in a few years or a decade, _Lengthof() will come to ISO C and solve this long-standing issue. Maybe we can even use it to get the length of VLA function parameters through compiler magic! – alx - recommends codidact Sep 12 '22 at 12:23
  • Also, in platforms that don't support this, you can just define `must_be_array()` to return always `0`. – alx - recommends codidact Sep 12 '22 at 12:24
  • Well, it's complex for sure since there are statically allocated arrays, dynamically allocated and VLA. Or either of those passed through a pointer. Also, not storing the array size together with the data was one of the core language design decisions that Dennis Ritchie made back in the days and as such it permeates the language. I don't see that ever changing, though of course language keywords that can expand at compile-time to the known size of an array defined in the same translation unit would be possible, I suppose. – Lundin Sep 12 '22 at 12:39
31

You can use the sizeof operator, but it will not work for functions, because it will take the reference of a pointer. You can do the following to find the length of an array:

len = sizeof(arr)/sizeof(arr[0])

The code was originally found here:

C program to find the number of elements in an array

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mohd Shibli
  • 950
  • 10
  • 17
  • 1
    This question already has many answers. What does this answer add that the accepted answer does not have? – VLL Sep 13 '22 at 05:20
25

If you know the data type of the array, you can use something like:

int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};

int noofele = sizeof(arr)/sizeof(int);

Or if you don't know the data type of array, you can use something like:

noofele = sizeof(arr)/sizeof(arr[0]);

Note: This thing only works if the array is not defined at run time (like malloc) and the array is not passed in a function. In both cases, arr (array name) is a pointer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abhitesh khatri
  • 2,911
  • 3
  • 20
  • 29
  • 4
    `int noofele = sizeof(arr)/sizeof(int);` is only half-way better than coding `int noofele = 9;`. Using `sizeof(arr)` maintains flexibility should the array size change. Yet `sizeof(int)` needs an update should the type of `arr[]` change. Better to use `sizeof(arr)/sizeof(arr[0])` even if the type is well known. Unclear why using `int` for `noofele` vs. `size_t`, the type returned by `sizeof()`. – chux - Reinstate Monica May 20 '16 at 20:50
23

The macro ARRAYELEMENTCOUNT(x) that everyone is making use of evaluates incorrectly. This, realistically, is just a sensitive matter, because you can't have expressions that result in an 'array' type.

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))

ARRAYELEMENTCOUNT(p + 1);

Actually evaluates as:

(sizeof (p + 1) / sizeof (p + 1[0]));

Whereas

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])

ARRAYELEMENTCOUNT(p + 1);

It correctly evaluates to:

(sizeof (p + 1) / sizeof (p + 1)[0]);

This really doesn't have a lot to do with the size of arrays explicitly. I've just noticed a lot of errors from not truly observing how the C preprocessor works. You always wrap the macro parameter, not an expression in might be involved in.


This is correct; my example was a bad one. But that's actually exactly what should happen. As I previously mentioned p + 1 will end up as a pointer type and invalidate the entire macro (just like if you attempted to use the macro in a function with a pointer parameter).

At the end of the day, in this particular instance, the fault doesn't really matter (so I'm just wasting everyone's time; huzzah!), because you don't have expressions with a type of 'array'. But really the point about preprocessor evaluation subtles I think is an important one.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    Thanks for the explanation. The original version results in a compile-time error. Clang reports "subscripted value is not an array, pointer, or vector". This seems preferable behavior in this instance, although your comments about evaluation order in macros is well taken. – Mark Harrison Feb 28 '14 at 02:30
  • 1
    I hadn't thought about the compiler complaint as an automatic notification of an incorrect type. Thank-you! –  Feb 28 '14 at 02:46
  • 3
    Is there a reason not to use `(sizeof (x) / sizeof (*x))`? – seriousdev Mar 28 '17 at 13:40
19

For multidimensional arrays it is a tad more complicated. Oftenly people define explicit macro constants, i.e.

#define g_rgDialogRows   2
#define g_rgDialogCols   7

static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
    { " ",  " ",    " ",    " 494", " 210", " Generic Sample Dialog", " " },
    { " 1", " 330", " 174", " 88",  " ",    " OK",        " " },
};

But these constants can be evaluated at compile-time too with sizeof:

#define rows_of_array(name)       \
    (sizeof(name   ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name)    \
    (sizeof(name[0]) / sizeof(name[0][0]))

static char* g_rgDialog[][7] = { /* ... */ };

assert(   rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);

Note that this code works in C and C++. For arrays with more than two dimensions use

sizeof(name[0][0][0])
sizeof(name[0][0][0][0])

etc., ad infinitum.

Andreas Spindler
  • 7,568
  • 4
  • 43
  • 34
18

Size of an array in C:

int a[10];
size_t size_of_array = sizeof(a);      // Size of array a
int n = sizeof (a) / sizeof (a[0]);    // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a                                          
                                       // Size of each element = size of type
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yogeesh H T
  • 2,777
  • 21
  • 18
  • 4
    Curious that code used `size_t size_of_element` yet `int` with `int n = sizeof (a) / sizeof (a[0]); ` and not `size_t n = sizeof (a) / sizeof (a[0]);` – chux - Reinstate Monica May 20 '16 at 21:02
  • 1
    Hi @Yogeesh H T, can you please answer the doubt of chux . I am also very curious to know how int n=sizeof(a)/sizeof(a[0]) is giving the length of array and why we are not using size_t for the length of array. Can anyone answer it? – Pallav Raj Jul 21 '17 at 19:55
  • 1
    @Brain sizeof(a) gives sizeof of all elements present in array a sizeof(a[0]) gives sizeof of 1st elements. Suppose a = {1,2,3,4,5}; sizeof(a) = 20bytes (if sizeof(int)= 4bytes multiply 5), sizeof(a[0]) = 4bytes, so 20/4 = 5 i.e no of elements – Yogeesh H T Jul 24 '17 at 11:28
  • 3
    @YogeeshHT For very large arrays like `char a[INT_MAX + 1u];`, `int n` as used in `int n = sizeof (a) / sizeof (a[0]);` is insufficient (it is UB). Using `size_t n = sizeof (a) / sizeof (a[0]);` does not incur this problem. – chux - Reinstate Monica May 21 '18 at 16:10
16
sizeof(array) / sizeof(array[0])
T Percival
  • 8,526
  • 3
  • 43
  • 43
  • Dependent upon the type `array` has, you do not need to use `sizeof(array) / sizeof(array[0])` if `array` is an array of either `char`, `unsigned char` or `signed char` - Quote from C18,6.5.3.4/4: *"When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1."* In this case you can simply do `sizeof(array)` as explained in my dedicated [answer](https://stackoverflow.com/a/60565087/12139179). – RobertS supports Monica Cellio Mar 06 '20 at 13:52
12
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Andy Nugent
  • 859
  • 7
  • 21
6

If you really want to do this to pass around your array I suggest implementing a structure to store a pointer to the type you want an array of and an integer representing the size of the array. Then you can pass that around to your functions. Just assign the array variable value (pointer to first element) to that pointer. Then you can go Array.arr[i] to get the i-th element and use Array.size to get the number of elements in the array.

I included some code for you. It's not very useful but you could extend it with more features. To be honest though, if these are the things you want you should stop using C and use another language with these features built in.

/* Absolutely no one should use this...
   By the time you're done implementing it you'll wish you just passed around
   an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and 
   cut out the array in main by using the stdlib memory allocation methods,
   but it will work much slower since it will store your array on the heap */

#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h 
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
   int age;
   char name[20];
} MyType;
typedef struct MyTypeArray
{
   int size;
   MyType *arr;
} MyTypeArray;

MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */

/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
   MyType d;
   d.age = age;
   strcpy(d.name, name);
   return d;
}

MyTypeArray new_MyTypeArray(int size, MyType *first)
{
   MyTypeArray d;
   d.size = size;
   d.arr = first;
   return d;
}
/* End MyTypeArray.c */


void print_MyType_names(MyTypeArray d)
{
   int i;
   for (i = 0; i < d.size; i++)
   {
      printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
   }
}

int main()
{
   /* First create an array on the stack to store our elements in.
      Note we could create an empty array with a size instead and
      set the elements later. */
   MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
   /* Now create a "MyTypeArray" which will use the array we just
      created internally. Really it will just store the value of the pointer
      "arr". Here we are manually setting the size. You can use the sizeof
      trick here instead if you're sure it will work with your compiler. */
   MyTypeArray array = new_MyTypeArray(2, arr);
   /* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
   print_MyType_names(array);
   return 0;
}
bartimar
  • 3,374
  • 3
  • 30
  • 51
Joel Dentici
  • 206
  • 2
  • 5
6

The best way is you save this information, for example, in a structure:

typedef struct {
     int *array;
     int elements;
} list_s;

Implement all necessary functions such as create, destroy, check equality, and everything else you need. It is easier to pass as a parameter.

Paulo Pinheiro
  • 118
  • 1
  • 4
6

The function sizeof returns the number of bytes which is used by your array in the memory. If you want to calculate the number of elements in your array, you should divide that number with the sizeof variable type of the array. Let's say int array[10];, if variable type integer in your computer is 32 bit (or 4 bytes), in order to get the size of your array, you should do the following:

int array[10];
size_t sizeOfArray = sizeof(array)/sizeof(int);
Keivan
  • 1,300
  • 1
  • 16
  • 29
3

You can use the & operator. Here is the source code:

#include<stdio.h>
#include<stdlib.h>
int main(){

    int a[10];

    int *p; 

    printf("%p\n", (void *)a); 
    printf("%p\n", (void *)(&a+1));
    printf("---- diff----\n");
    printf("%zu\n", sizeof(a[0]));
    printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));


    return 0;
};

Here is the sample output

1549216672
1549216712
---- diff----
4
The size of array a is 10
M.M
  • 138,810
  • 21
  • 208
  • 365
Shih-En Chou
  • 4,007
  • 6
  • 20
  • 27
  • 9
    I did not downvote, but this is like hitting a nail with a brick because you didn't notice a hammer lying next to you. Also, people tend to frown on using uninitialized variables... but here i guess it serves your purpose well enough. – Dmitri Sep 11 '14 at 21:18
  • 2
    @Dmitri no uninitialized variables are accessed here – M.M Oct 06 '14 at 02:39
  • 1
    Hmmm. Pointer subtraction leads to `ptrdiff_t`. `sizeof()` results in `size_t`. C does _not_ define which is wider or higher/same rank. So the type of the quotient `((char *)(&a+1)-(char *)a)/(sizeof(a[0]))` is not certainly `size_t` and thus printing with `z` can lead to UB. Simply using `printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);` is sufficient. – chux - Reinstate Monica May 20 '16 at 21:10
  • 1
    `(char *)(&a+1)-(char *)a` is not a constant and may be calculated at run-time, even with a fixed sized `a[10]`. `sizeof(a)/sizeof(a[0])` is constant done at compile time in this case. – chux - Reinstate Monica May 21 '18 at 16:17
3

A more elegant solution will be

size_t size = sizeof(a) / sizeof(*a);
reflex0810
  • 908
  • 12
  • 13
2

The simplest answer:

#include <stdio.h>

int main(void) {

    int a[] = {2,3,4,5,4,5,6,78,9,91,435,4,5,76,7,34}; // For example only
    int size;

    size = sizeof(a)/sizeof(a[0]); // Method

    printf("size = %d", size);
    return 0;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jency
  • 269
  • 1
  • 13
  • 1
    An explanation would be in order. E.g., in what way is it the simplest? What is the idea/gist? How is it different from previous answers? What is the result of running it? From [the Help Center](https://stackoverflow.com/help/promotion): *"...always explain why the solution you're presenting is appropriate and how it works"*. Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/57408735/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Sep 12 '22 at 19:33
0
#ifndef __cplusplus
   /* C version */
#  define ARRAY_LEN_UNSAFE(X) (sizeof(X)/sizeof(*(X)))
#  define ARRAY_LEN(X) (ARRAY_LEN_UNSAFE(X) + 0 * sizeof((typeof(*(X))(*[1])[ARRAY_LEN_UNSAFE(X)]){0} - (typeof(X)**)0))
#else
   /* C++ version */
   template <unsigned int N> class __array_len_aux    { public: template <typename T, unsigned int M> static const char (&match_only_array(T(&)[M]))[M]; };
   template <>               class __array_len_aux<0> { public: template <typename T>                 static const char (&match_only_array(T(&)))[0]; };
#  define ARRAY_LEN(X) sizeof(__array_len_aux<sizeof(X)>::match_only_array(X))
#endif


/* below are verifying codes */
#include <assert.h>

void * a0[0];
void * a1[9];
void * aa0[0];
void * aa1[5][10];
void *p;
struct tt {
    char x[10];
    char *p;
} t;

static_assert(ARRAY_LEN(a0) == 0, "verify [0]");
static_assert(ARRAY_LEN(aa0) == 0, "verify [0][N]");
static_assert(ARRAY_LEN(a1) == 9, "verify [N]");
static_assert(ARRAY_LEN(aa1) == 5, "verify [N][M]");
static_assert(ARRAY_LEN(aa1[0]) == 10, "verify inner array of [N][M]");
static_assert(ARRAY_LEN(t.x) == 10, "verify array in struct");
//static_assert(ARRAY_LEN(p) == 0, "should parse error");
//static_assert(ARRAY_LEN(t.p) == 0, "should parse error");

The following C version ARRAY_LEN only depends on typeof(). The C++ and C versions have same behaviour, accept only arrays (including 0-length or multi dimension arrays), but reject any pointer type.

James Z.M. Gao
  • 516
  • 1
  • 8
  • 13
-1

"you've introduced a subtle way of shooting yourself in the foot"

C 'native' arrays do not store their size. It is therefore recommended to save the length of the array in a separate variable/const, and pass it whenever you pass the array, that is:

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

If you are writing C++, you SHOULD always avoid native arrays anyway (unless you can't, in which case, mind your foot). If you are writing C++, use the STL's 'vector' container. "Compared to arrays, they provide almost the same performance", and they are far more useful!

// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;  

// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
    numbers.push_back(i);

// Determine the size of the array
cout << numbers.size();

See: http://www.cplusplus.com/reference/stl/vector/

Josiah Yoder
  • 3,321
  • 4
  • 40
  • 58
Ohad
  • 2,752
  • 17
  • 15
  • 21
    The question is about C, not C++. So no STL. – alx - recommends codidact Apr 23 '20 at 09:26
  • 12
    This answer is blatantly off-topic and should be deleted. – Lundin Sep 12 '22 at 06:24
  • 15
    This answer is being [discussed on meta](https://meta.stackoverflow.com/questions/420337). – cigien Sep 12 '22 at 13:44
  • 3
    `std::array` is a drop-in replacement for a plain array. Only use `std::vector` if you actually want its size to be a runtime variable. `std::array` doesn't *store* the size anywhere in memory, but it associates a size as part of the type, giving you all the efficiency with none of the maintenance danger. – Peter Cordes Sep 12 '22 at 18:53
  • 2
    What alternative to "native arrays" is there in C, which is the language the question asks about? I know of none — there are static arrays, local arrays and dynamically allocated arrays, but they're all "native" AFAICT. – Jonathan Leffler Sep 13 '22 at 16:19
-2

Beside the answers already provided, I want to point out a special case by the use of

sizeof(a) / sizeof (a[0])

If a is either an array of char, unsigned char or signed char you do not need to use sizeof twice since a sizeof expression with one operand of these types do always result to 1.

Quote from C18,6.5.3.4/4:

"When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1."

Thus, sizeof(a) / sizeof (a[0]) would be equivalent to NUMBER OF ARRAY ELEMENTS / 1 if a is an array of type char, unsigned char or signed char. The division through 1 is redundant.

In this case, you can simply abbreviate and do:

sizeof(a)

For example:

char a[10];
size_t length = sizeof(a);

If you want a proof, here is a link to GodBolt.


Nonetheless, the division maintains safety, if the type significantly changes (although these cases are rare).

  • 2
    You probably prefer to still apply a macro with the division, because the type may change in the future (although maybe unlikely), and the division is known at compile time, so the compiler will optimize it away (if it doesn't please change your compiler). – alx - recommends codidact Apr 23 '20 at 09:09
  • 1
    @CacahueteFrito Yes, I´ve thought about that in the meantime, too. I took it as a side note into the answer. Thank you. – RobertS supports Monica Cellio Apr 23 '20 at 09:22
  • 2
    I would advise to never be that sneaky. It doesn't even add any performance improvements, as the division is done at compile time. – alx - recommends codidact Jul 20 '20 at 14:07
  • 4
    I would still recommend adding the `/ sizeof (a[0])`. Best programming practices typically aim to make code robust, even when parts of the code are modified down the line. If someone ever changes the contents of your array so that it doesn't contain `char`, `unsigned char`, or `signed char`, you may find yourself faced with a hard to find bug. – Tyrel Kostyk Apr 16 '21 at 17:06
-3

To know the size of a fixed array declared explicitly in code and referenced by its variable, you can use sizeof, for example:

int a[10];
int len = sizeof(a)/sizeof(int);

But this is usually useless, because you already know the answer.

But if you have a pointer you can’t use sizeof, its a matter of principle.

But...Since arrays are presented as linear memory for the user, you can calculate the size if you know the last element address and if you know the size of the type, then you can count how many elements it have. For example:

#include <stdio.h>

int main(){
    int a[10];
    printf("%d\n", sizeof(a)/sizeof(int));
    int *first = a;
    int *last = &(a[9]);
    printf("%d\n", (last-first) + 1);
}

Output:

10
10

Also if you can't take advantage of compile time you can:

#include <stdio.h>

int main(){
    int a[10];
    printf("%d\n", sizeof(a)/sizeof(int));
    void *first = a;
    void *last = &(a[9]);
    printf("%d\n", (last-first)/sizeof(int) + 1);
}
Punisher
  • 30
  • 6
  • While this answer attempts to explain the pitfall of an array being converted to a pointer, it does not state it clearly enough. There should be example code for the wrong behavior. – Roland Illig Sep 10 '22 at 17:45
  • This question already has many answers. What does this answer add that the existing answers do not have? – VLL Sep 13 '22 at 05:22
  • I'm not sure it counts as "determining the size" of an array if you start from a pointer to (or past) the last element. (Nor can you subtract `void*`s portably.) – Davis Herring Sep 13 '22 at 06:50
  • This answer should be very clear for advanced C programmers, no one stated this before. – Punisher Sep 14 '22 at 04:32
-4

Note: This one can give you undefined behaviour as pointed out by M.M in the comment.

int a[10];
int size = (*(&a+1)-a);

For more details, see here and also here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pygirl
  • 12,969
  • 5
  • 30
  • 43
  • 2
    This is technically undefined behaviour; the `*` operator may not be applied to a past-the-end pointer – M.M Aug 28 '18 at 00:45
  • 3
    "undefined behaviour" means the C Standard does not define the behaviour. If you try it in your program then anything can happen – M.M Aug 28 '18 at 22:09
  • @M.M are you saying `*(&a+1) - a;` is different from `(&a)[1] - a;` above, don't both `*(&a+1)` and `(&a)[1]` count as 1 past the end? – QuentinUK Feb 16 '20 at 01:58
  • @QuentinUK your two expressions are both the same, `x[y]` is defined as `*(x + (y))` – M.M Feb 16 '20 at 02:00
  • @M.M I thought so. But the other answer, by Arjun Sreedharan, has 38 up arrows and this has -1. And Arjun Sreedharan 's answer has no mention of undefined behaviour. – QuentinUK Feb 16 '20 at 09:30
  • @QuentinUK I didn't see that answer before; have added a comment now . – M.M Feb 16 '20 at 10:58
-5

For a predefined array:

 int a[] = {1, 2, 3, 4, 5, 6};

Calculating number of elements in the array:

 element _count = sizeof(a) / sizeof(a[0]);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mano S
  • 809
  • 3
  • 2
  • 2
    This question already has many answers. What does this answer add that the accepted answer does not have? – VLL Sep 13 '22 at 05:22