The challenge

You will be given a string and your task will be to return a list of ints detailing the count of uppercase letters, lowercase, numbers and special characters, as follows.

Solve("*'&ABCDabcde12345") = [4,5,5,3]. 
--the order is: uppercase letters, lowercase, numbers and special characters.

The solution in C

Option 1:

void count_char_types (const char *string, unsigned counts[4])
{
  char c;
  counts[0] = counts[1] = counts[2] = counts[3] = 0;
  while((c = *string++))
    if(c >= 'A' && c <= 'Z') counts[0]++;
    else if(c >= 'a' && c <= 'z') counts[1]++;
    else if(c >= '0' && c <= '9') counts[2]++;
    else counts[3]++;
}

Option 2:

#include <ctype.h>

void count_char_types (const char *string, unsigned counts[4])
{
  counts[0] = counts[1] = counts[2] = counts[3] = 0;
  for(const char* p = string; *p; p++){
    if(isupper(*p))       counts[0]++;
    else if(islower(*p))  counts[1]++;
    else if(isdigit(*p))  counts[2]++;
    else                  counts[3]++;
  }
}

Option 3:

#include <string.h>
#include <ctype.h>

void count_char_types (const char *string, unsigned counts[4])
{
  memset(counts, 0, 4 * sizeof(unsigned));
  char c;
  while((c = *string++)){
    if (isupper(c)) ++counts[0];
    else if (islower(c)) ++counts[1];
    else if (isdigit(c)) ++counts[2];
    else ++counts[3];
  }
}

Test cases to validate our solution

#include <criterion/criterion.h>

extern void do_test (const char *string, const unsigned expected[4]);

#define ARRAY (const unsigned[4])

Test(tests_suite, sample_tests)
{
	do_test("bgA5<1d-tOwUZTS8yQ",                     ARRAY {7, 6, 3, 2});
	do_test("P*K4%>[email protected]",      ARRAY {9, 9, 6, 9});
	do_test("RYT'>s&gO-.CM9AKeH?,5317tWGpS<*x2ukXZD", ARRAY {15, 8, 6, 9});
	do_test("$Cnl)Sr<7bBW-&qLHI!mY41ODe",             ARRAY {10, 7, 3, 6});
	do_test("@mw>0=QD-iAx!rp9TaG?o&M%l$34L.nbft",     ARRAY {7, 13, 4, 10});
	do_test("",                                       ARRAY {0, 0, 0, 0});
}