How to Find the Capitals in C


The challenge

Instructions

Write a function that takes a single string (word) as argument. The function must return an ordered list containing the indexes of all capital letters in the string.

Example

Test.assertSimilar( capitals('CodEStAr'), [0,3,4,6] );

The solution in C

Option 1:

#include <stddef.h>
#include <string.h>
#include <stdlib.h>

size_t *find_capitals(const char *word, size_t *nb_uppercase)
{
    size_t n = strlen(word);
    size_t *arr = (size_t *) calloc(n, sizeof(size_t));
    size_t j = 0;
    for(size_t i=0; i<n; i++) {
        if(word[i] >='A' && word[i] <='Z') {
            arr[j++] = i;
        }
    }
    *nb_uppercase = j;
    return realloc(arr, j * sizeof(size_t));
}

Option 2:

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

size_t *find_capitals (const char *word, size_t *nb_uppercase)
{
  if (!word || !*word) {
    *nb_uppercase = 0;
    return 0;
  }
  *nb_uppercase = 0;
  for (char const *itr = word; *itr; itr++)
    if (*itr >= 'A' && *itr <= 'Z')
      (*nb_uppercase)++;
  
  size_t * const buffer = malloc(*nb_uppercase * sizeof(size_t));
  for (size_t i = 0, j = 0; word[i]; i++)
    if (word[i] >= 'A' && word[i] <= 'Z')
      buffer[j++] = i;
  return buffer;
}

Option 3:

#include <stddef.h>

size_t *find_capitals (const char *word, size_t *nb_uppercase)
{
  size_t* arr = malloc(50 * sizeof(int));
  int i = 0;
  int a = 0;
  while(word[i] != '\0'){
    if(word[i] >= 'A' && word[i] <= 'Z'){
      arr[a] = i;
      a++;
    }
    i++;
  }
  *nb_uppercase = a;
  return arr;
  return NULL;
}

Test cases to validate our solution

#include <time.h>
#include <stdlib.h>
#include <criterion/criterion.h>

extern void do_test (const char *word, size_t exp_len, const size_t expected[exp_len]);

#define ARR_LEN(array) (sizeof(array) / sizeof *(array))

#define sample_test(word, expected) do_test(word, ARR_LEN(expected), expected)

Test(tests_suite, sample_tests)
{
  do_test("", 0, NULL);
  do_test("4ysdf4", 0, NULL);
  sample_test("CodEStAr", ((const size_t[]){0, 3, 4, 6}));
  sample_test("aAbB",     ((const size_t[]){1, 3}));
  sample_test("ABCDEF",   ((const size_t[]){0, 1, 2, 3, 4, 5}));
}

enum { MAX_LEN = 40 };

#define take_char(str) ((str)[rand() % (sizeof(str) - 1)])

// generates a random word, fill the indexes[] array, return the number of uppercase letters
static size_t random_word (char *word, size_t uppercase_indexes[])
{
  size_t length = 1 + (rand() % MAX_LEN);

  size_t idx_caps = 0;

  for (size_t i = 0; i < length; i++) {
    switch (rand() % 3) {
    case 0:
      word[i] = take_char("abcdefghijklmnopqrstuvwxyz");
      break;
    case 1:
      word[i] = take_char("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      uppercase_indexes[idx_caps++] = i;
      break;
    default:
      word[i] = take_char("@&~#0123456789-*/=,;:!.");
      break;
    }
  }
  word[length] = '\0';
  return idx_caps;
}

Test(tests_suite, random_tests)
{
  srand(time(NULL));

  size_t expected[MAX_LEN];
  char word[MAX_LEN + 1];

  for (int i = 0; i < 100; i++) {
    size_t exp_len = random_word(word, expected);
    do_test(word, exp_len, expected);
  }
}