1

I need to specify the length of an array of char pointers as an input to a function in C. I don't think it is possible to know this in C without some trick (like iterating until a certain sentinel string is found), but I'm wondering if perhaps gcc has some function that would extract this for me?

const char *names[] = {"string1","next_string","test"};

//Later in code
int n_fields = <magic>(names);

In this case I would be looking for n_fields to be 3.

My current alternative is to manually count and specify the length, but this means I need to ensure that these two values stay linked manually.

Edit regarding duplicate question: Unlike arrays of integers it was not obvious to me what the two sizeof parameters in other examples would be measuring for an array of char pointers. Specifically I thought the denominator might be measuring string length, when in reality it was measuring the size of a pointer. Pretty much every example online is for an array of ints, not char pointers.

Jimbo
  • 2,886
  • 2
  • 29
  • 45

1 Answers1

1

Sure thing:

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

#include <stdio.h>
const char *names[] = {"string1","next_string","test"};

//Later in code
int n_fields = ARRAY_SIZE(names);

int main()
{
    printf("%d\n", n_fields); //prints 3
}

Keep in mind that you need to make sure you're applying ARRAY_SIZE to a real array, not a pointer.

void f (const char *names[])
{
    //!WRONG: names is actually a pointer here
    printf("%d\n", (int)ARRAY_SIZE(names));
}

To protect yourself, you can beef up ARRAY_SIZE with some gcc/clang/tcc extensions so that the erroneous code in the snippet above no longer compiles but the example with a real array continues to:

#define ARRAY_SIZE(X) (  0*sizeof(char [ \
   __builtin_types_compatible_p(__typeof(X),__typeof((X)+0))  ?-1:1 ] )  \
    +sizeof(X)/sizeof((X)[0]) )

Once the array decays to a pointer, the original size can no longer be recovered through standards means, which is why functions taking array parameters (really pointer parameters) where the array isn't terminated with a sentinel usually also accept an array size parameter.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 2
    Warning: this will not work for a function argument. Without a sentinel, you must explicitly pass the array length too. – Weather Vane Sep 16 '18 at 18:35
  • Should be worth nothing that once the array is passed as a parameter to any function, the ARRAY_SIZE macro won't work. – selbie Sep 16 '18 at 18:35
  • @WeatherVane,selbie Thanks, guys. Note added and ARRAY_SIZE expanded to protect against the error. – Petr Skocik Sep 16 '18 at 18:40
  • @PSkocik I really didn't expect that to work but I guess it does because `sizeof(names[0])` is computing the size of a pointer, not the length of the string. Thanks. – Jimbo Sep 16 '18 at 18:49
  • @Jimbo `sizeof(array)` is the bytesize of the array. `sizeof` doesn't decay its argument. `sizeof(array)` != `sizeof(&array[0])`. Inside of `sizeof` is like one of two places in C where arrays are distinguishable from pointers (inside the parentheses of `_Alignof` being the second place). – Petr Skocik Sep 16 '18 at 18:52