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

2,727,722

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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.

Solution 5

int size = (&arr)[1] - arr;

Check out this link for explanation

Share:
2,727,722
Mark Harrison
Author by

Mark Harrison

I'm a Software Engineer at Google where I work on machine learning planning systems. From 2001-2015 I was the Pixar Tech Lead of the Data Management Group. My 50-year charter was to store and catalog all data and metadata related to the Studio's feature films. This system ("Templar") is in use to this day. From 1997 to 2001 I lived in Beijing, China and was the Chief Software Architect at AsiaInfo, the company that built China's Internet. While there my software was used to grow the China Internet from 200K to 65M users. The last I heard they were at 350M+ users. I studied computer science and worked in Texas for many years. I wrote a couple of computer books... the best one was in print for 20 years. Feel free to drop me a line! [email protected]

Updated on July 24, 2022

Comments

  • Mark Harrison
    Mark Harrison almost 2 years

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

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

  • Skizz
    Skizz over 15 years
    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
    Skizz over 15 years
    @ 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."
  • vonbrand
    vonbrand over 11 years
    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).
  • lukecampbell
    lukecampbell almost 11 years
    Out of curiosity does the compiler treat arrays the same as pointers when they are parameterized?
  • Raffi Khatchadourian
    Raffi Khatchadourian almost 11 years
    I've read that the proper way to declare integer constants in C is to use an enum declaration.
  • Bbvarghe
    Bbvarghe almost 11 years
    why is length of parameter:2 if only a pointer to the 1st array element is passed?
  • Elideb
    Elideb almost 11 years
    @Bbvarghe That's because pointers in 64bit systems are 8 bytes (sizeof(intArray)), but ints are still (usually) 4 bytes long (sizeof(intArray[0])).
  • Pacerier
    Pacerier over 10 years
    But isn't sizeof(int) more performant than sizeof(*int_arr) in runtime? Or is the translated code identical?
  • Pacerier
    Pacerier over 10 years
    @Elideb, so what would be the correct code for the functions printSizeOf and printLength?
  • Pacerier
    Pacerier over 10 years
    Btw, are they identical instructions at the processor level? Does sizeof(int) require lesser instructions than sizeof(foo)?
  • Mark Harrison
    Mark Harrison over 10 years
    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.
  • Pacerier
    Pacerier over 10 years
    Which compiler are you using?
  • Mark Harrison
    Mark Harrison over 10 years
    It should be the case with all compilers, since the results of sizeof is defined as a compile-time constant.
  • quetzalcoatl
    quetzalcoatl over 10 years
    @Pacerier: no, they are identical. Think of int x = 1+1; versus int x = (1+1);. Here, parentheses are purely absolutely just aesthetic.
  • Jean Hominal
    Jean Hominal over 10 years
    @Pacerier: There is no correct code - the usual solution is to pass the length along with the array as a separate argument.
  • sudo
    sudo over 10 years
    Wait, so there's no way to access the array directly from a pointer and see its size? New to C here.
  • Raffi Khatchadourian
    Raffi Khatchadourian over 10 years
    It's interesting how this seems to work when the array is empty.
  • Markus
    Markus over 10 years
    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.
  • Mark Harrison
    Mark Harrison over 10 years
    @AlexMelbourne, I reverted your suggested edit as it produced incorrect results for the expression p+1.
  • Lumi
    Lumi about 10 years
    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.
  • Nickolai
    Nickolai almost 10 years
    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!
  • Dmitri
    Dmitri over 9 years
    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.
  • M.M
    M.M over 9 years
    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
    M.M over 9 years
    @Dmitri no uninitialized variables are accessed here
  • M.M
    M.M over 9 years
    @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.
  • John Meacham
    John Meacham over 9 years
    on many unix systems 'sys/param.h' defines 'nitems(x)' similarly.
  • Elideb
    Elideb over 9 years
    @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.
  • Nickolai
    Nickolai over 9 years
    @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 :)
  • Martin
    Martin about 9 years
    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?
  • Michael Trouw
    Michael Trouw about 9 years
    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^%
  • chqrlie
    chqrlie about 9 years
    @Michael Trouw: you can use the operator syntax if is makes you feel better: (sizeof array / sizeof *array).
  • Michael Trouw
    Michael Trouw about 9 years
    @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.
  • Javad
    Javad almost 9 years
    This is an excellent response. I want to comment that all of above assertions are evaluated to TRUE.
  • Daan
    Daan over 8 years
    This answer should be merged with the next answer
  • user253751
    user253751 over 8 years
    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.
  • Key_coder
    Key_coder over 8 years
    any idea how to achieve this without using .length of array as required here geeksforgeeks.org/reorder-a-array-according-to-given-indexes
  • Jim Balter
    Jim Balter over 8 years
    "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.
  • Aidiakapi
    Aidiakapi over 8 years
    @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.
  • unwind
    unwind over 8 years
    @Aidiakapi That's not true, consider C99 VLAs.
  • Aidiakapi
    Aidiakapi over 8 years
    @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.
  • Sourab Reddy
    Sourab Reddy over 8 years
    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!
  • Smart Home
    Smart Home about 8 years
    We should remove this as correct answer. Read @Markus comment. I wasted several hours because this answer does not work in malloc case.
  • chux - Reinstate Monica
    chux - Reinstate Monica about 8 years
    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
    chux - Reinstate Monica about 8 years
    Cannot upvote code that does strcpy(d.name, name); with no handling of overflow.
  • chux - Reinstate Monica
    chux - Reinstate Monica about 8 years
    Any reason for int elements vs. size_t elements?
  • chux - Reinstate Monica
    chux - Reinstate Monica about 8 years
    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
    chux - Reinstate Monica about 8 years
    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
    chux - Reinstate Monica about 8 years
    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().
  • rahulbsb
    rahulbsb almost 8 years
    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.
  • David Schwartz
    David Schwartz over 7 years
    Note that this only works for actual arrays, not pointers that happen to point to arrays.
  • Pallav Raj
    Pallav Raj almost 7 years
    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?
  • Yogeesh H T
    Yogeesh H T almost 7 years
    @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
  • Tony Tannous
    Tony Tannous almost 7 years
    If the number of elements is known, why bother send to a function ? just compute it onspot by multiplying the sizeof(type)
  • ardnew
    ardnew over 6 years
    @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
  • Michael Trouw
    Michael Trouw over 6 years
    @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.
  • ardnew
    ardnew over 6 years
    @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 :(
  • Ruslan
    Ruslan over 6 years
    @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.
  • chux - Reinstate Monica
    chux - Reinstate Monica about 6 years
    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
    chux - Reinstate Monica about 6 years
    @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
    chux - Reinstate Monica about 6 years
    (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.
  • Sandburg
    Sandburg almost 6 years
    Is there a mecanism of align that can cause sizeof to return at minimum a bigger value even when there are less parameters?
  • M.M
    M.M almost 6 years
    This is technically undefined behaviour; the * operator may not be applied to a past-the-end pointer
  • meditat
    meditat almost 6 years
    What about the Array of characters?
  • M.M
    M.M almost 6 years
    "undefined behaviour" means the C Standard does not define the behaviour. If you try it in your program then anything can happen
  • preciousbetine
    preciousbetine over 5 years
    And what if the array is declared like int a[];?
  • igonejack
    igonejack about 5 years
    The tradition is pass the length as another parameter in C, am I right?
  • alx
    alx almost 5 years
    Would you mind to explain why the downvote? This shows a solution to an unsafe and common construction (sizeof(arr)) that isn't shown elsewhere: ARRAY_BYTES(arr).
  • alx
    alx almost 5 years
    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
    alx almost 5 years
    ..., 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.
  • Mark Harrison
    Mark Harrison almost 5 years
    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.
  • alx
    alx almost 5 years
    @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
    alx almost 5 years
    @hyde Also that I know the difference doesn't mean everyone knows the difference, and why not use something that basically removes 100% of those bugs? That bug almost made it into Linux; it arrived to Linus, which means it passed a lot of scrutiny, and which also means there's the possibility that the same bug has made it into Linux in another part of the kernel, as he says.
  • alx
    alx almost 5 years
    BTW, I removed the capital letters, if that was it
  • alx
    alx almost 5 years
    @hyde Fair enough
  • Peter - Reinstate Monica
    Peter - Reinstate Monica over 4 years
    @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).
  • starblue
    starblue over 4 years
    Is there a way to check in the macro that the array is really an array and not a pointer?
  • QuentinUK
    QuentinUK over 4 years
    @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?
  • M.M
    M.M over 4 years
    @QuentinUK your two expressions are both the same, x[y] is defined as *(x + (y))
  • QuentinUK
    QuentinUK over 4 years
    @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.
  • M.M
    M.M over 4 years
    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
    M.M over 4 years
    @QuentinUK I didn't see that answer before; have added a comment now .
  • RobertS supports Monica Cellio
    RobertS supports Monica Cellio about 4 years
    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.
  • RobertS supports Monica Cellio
    RobertS supports Monica Cellio about 4 years
    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.
  • ad absurdum
    ad absurdum about 4 years
    @M.M -- I am not sure that I understand the difference between "technically undefined behavior" and undefined behavior....
  • M.M
    M.M about 4 years
    @exnihilo I mean undefined behaviour but is likely to work on most systems
  • SO Stinks
    SO Stinks about 4 years
    sizeof may be an operator but it should be treated as a function according to Linus Torvalds. I agree. Read his rational here: lkml.org/lkml/2012/7/11/103
  • unwind
    unwind about 4 years
    @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.
  • alx
    alx about 4 years
    @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
    alx about 4 years
    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).
  • RobertS supports Monica Cellio
    RobertS supports Monica Cellio about 4 years
    @CacahueteFrito Yes, I´ve thought about that in the meantime, too. I took it as a side note into the answer. Thank you.
  • alx
    alx about 4 years
    The question is about C, not C++. So no STL.
  • alx
    alx about 4 years
    @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
    alx almost 4 years
    @starblue Yes there is. See the macro must_be_array() in my answer below.
  • Byron
    Byron almost 4 years
    Don't listen to this guy. If you populate my code base with these macro's I will fire you.
  • alx
    alx almost 4 years
    @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
    alx almost 4 years
    I would advise to never be that sneaky. It doesn't even add any performance improvements, as the division is done at compile time.
  • starblue
    starblue almost 4 years
    @CacahueteFrito That assumes some gcc extensions.
  • alx
    alx almost 4 years
    @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 and typeof. GCC and Clang have these. In other compilers, however, you will need to find a replacement, or it may be impossible to achieve.
  • 12431234123412341234123
    12431234123412341234123 over 3 years
    Why do you caste the sizeof result to int. printf() has the format specifier %zu to print a size_t type.
  • 12431234123412341234123
    12431234123412341234123 over 3 years
    @M.M He does not dereference past the array, no UB.
  • M.M
    M.M over 3 years
    @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.
  • 12431234123412341234123
    12431234123412341234123 over 3 years
    @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.
  • M.M
    M.M over 3 years
    @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
    M.M over 3 years
    @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)
  • 12431234123412341234123
    12431234123412341234123 over 3 years
    @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).
  • Kaiyaha
    Kaiyaha over 3 years
    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.
  • alx
    alx over 3 years
    @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.
  • serge
    serge over 3 years
    in the article you mentionned there is a PS: This works only for arrays, not when you take pointers*
  • Eric Duminil
    Eric Duminil over 3 years
    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.
  • Tyrel Kostyk
    Tyrel Kostyk about 3 years
    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.
  • EdgeDev
    EdgeDev about 3 years
    This worked for an array that its size was not initially specified eg int coins[] = {25, 10, 5, 1}
  • Dig The Code
    Dig The Code almost 3 years
    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.