Software Engineering

How to Create an Incrementer in C


The challenge

Given an input of an array of digits, return the array with each digit incremented by its position in the array: the first digit will be incremented by 1, the second digit by 2, etc. Make sure to start counting your positions from 1 ( and not 0 ).

Your result can only contain single digit numbers, so if adding a digit with its position gives you a multiple-digit number, only the last digit of the number should be returned.

Notes:

  • return an empty array if your array is empty
  • arrays will only contain numbers so don’t worry about checking that

Examples:

[1, 2, 3]  -->  [2, 4, 6]   #  [1+1, 2+2, 3+3]

[4, 6, 9, 1, 3]  -->  [5, 8, 2, 5, 8]  #  [4+1, 6+2, 9+3, 1+4, 3+5]
                                       #  9+3 = 12  -->  2

The solution in C

Option 1:

#include <stddef.h>

unsigned *incrementer(unsigned *dest, const unsigned *src, size_t n) {
  if (n == 0) return NULL;
  for (size_t i = 0; i < n; i++) {
    dest[i] = (src[i] + i + 1) % 10;
  }
  return dest;
}

Option 2:

#include <stddef.h>

unsigned *incrementer(unsigned *dest, const unsigned *src, size_t n) {
  if(!n) return NULL;
  for(size_t i = 0; i < n; i++) dest[i] = (src[i] + (i + 1)) % 10;
  return dest;
}

Option 3:

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

unsigned *incrementer(unsigned *dest, const unsigned *src, size_t n)
{
  if (n <= 0) return NULL;
  char str[100];
  for (unsigned i = 0; i < n; ++i) {
    sprintf(str, "%d", src[i] + (i+1));
    if (strlen(str) > 1) dest[i] = str[strlen(str)-1] - '0';
    else dest[i] = atoi(str);
    strcpy(str, "");
  }
  return dest;
}

Test cases to validate our solution

#include <criterion/criterion.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>

extern unsigned *incrementer(unsigned *dest, const unsigned *src, size_t n);

#define ARRLIM      0xF
#define FMT_UINT    (CHAR_BIT * sizeof(unsigned) / 3)
#define FMT_ALIGN   0x2
#define FMT_DESCR   0x40
#define FMT_ARR     ((FMT_UINT + FMT_ALIGN) * ARRLIM)
#define OUTPFLEN    (FMT_DESCR + FMT_UINT * 3)

typedef enum {
    ASSERT_PASS,
    ASSERT_FAIL
} assertop;

assertop assert_mem_eq(const void *actual, const void *expected, size_t n, size_t size)
{
    unsigned long i;
    if (!actual || !expected)
        return actual != expected ? ASSERT_FAIL : ASSERT_PASS;
    for (i = 0ul; n--; i += size)
        if (memcmp((char *)actual+i, (char *)expected+i, size))
            return ASSERT_FAIL;
    return ASSERT_PASS;
}

char *assert_fmt(char *outpf, const unsigned *actual, const unsigned *expected, const unsigned *arr, size_t n)
{
    const char *descr[] = { "*Actual*:", "\nExpected:", "\n   Array:" };
    const unsigned *params[] = { actual, expected, arr };
    //const unsigned *r;
    size_t pos, m, i;
    for (pos = m = 0ul; m < 3ul; ++m) {
        pos += sprintf(outpf+pos, "%s ", *(descr+m));
        if (!(arr = *(params+m))) {
            pos += sprintf(outpf+pos, "NULL");
            continue;
        }
        pos += sprintf(outpf+pos, "[ ");
        for (i = 0ul; i < n; ++i)
            pos += sprintf(outpf+pos, "%u, ", *(arr+i));
        if (i)
            pos -= FMT_ALIGN;
        pos += sprintf(outpf+pos, " ]");
    }
    pos += sprintf(outpf+pos, "\n    N: %lu\n", n);
    return outpf;
}

void assert_data(const unsigned *arr, size_t n, const unsigned *expected)
{
    char outpf[OUTPFLEN];
    unsigned dest[ARRLIM];
    unsigned *actual = incrementer(dest, arr, n);
    if (!actual) {
        if (expected)
            cr_assert_fail("%s", assert_fmt(outpf, actual, expected, arr, n));
        else
            cr_assert(1);
    }
    else if (assert_mem_eq(actual, expected, n, sizeof(unsigned)) == ASSERT_FAIL)
        cr_assert_fail("%s", assert_fmt(outpf, actual, expected, arr, n));
    else if (assert_mem_eq(dest, expected, n, sizeof(unsigned)) == ASSERT_FAIL)
        cr_assert_fail("Error: should not allocate memory!\n%s", assert_fmt(outpf, actual, expected, arr, n));
    else
        cr_assert(1);
}

Test(Sample_Test, should_return_the_incremented_array)
{
    assert_data((const unsigned[]){ 1,2,3 }, 3ul, (const unsigned[]){ 2,4,6 });
    assert_data((const unsigned[]){ 4,6,7,1,3 }, 5ul, (const unsigned[]){ 5,8,0,5,8 });
    assert_data((const unsigned[]){ 3,6,9,8,9 }, 5ul, (const unsigned[]){ 4,8,2,2,4 });
    assert_data((const unsigned[]){ 1,2,3,4,5,6,7,8,9,9,9,9,9,8 }, 14ul, (const unsigned[]){ 2,4,6,8,0,2,4,6,8,9,0,1,2,2 });
    assert_data((const unsigned[]){ 0 }, 0ul, NULL);
}