Home > Enterprise >  exercism Isogram challenge in C track - running locally but not in exercism
exercism Isogram challenge in C track - running locally but not in exercism

Time:10-08

So I recently started with C at exercism page. I currently facing a rather simple challenge.

Determine if a word or phrase is an isogram. An isogram (also known as a "non-pattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. Examples of isograms: lumberjacks background downstream six-year-old The word isograms, however, is not an isogram, because the s repeats.

There are 15 tests in total, of which one specific is not passed: test_isogram_with_duplicated_hyphen

I guess test number 15 also passes because of some error I don't see Here's the testing code:

    #include "test-framework/unity.h"
#include "isogram.h"
#include <stdlib.h>
void setUp(void)
{
}
void tearDown(void)
{
}
static void test_empty_string(void)
{
   TEST_ASSERT_TRUE(is_isogram(""));
}
static void test_null(void)
{
   TEST_IGNORE();   // delete this line to run test
   TEST_ASSERT_FALSE(is_isogram(NULL));
}
static void test_isogram_with_only_lower_case_characters(void)
{
   TEST_IGNORE();
   TEST_ASSERT_TRUE(is_isogram("isogram"));
}
static void test_word_with_one_duplicated_character(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("eleven"));
}
static void test_word_with_one_duplicated_character_from_end_of_alphabet(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("zzyzx"));
}
static void test_longest_reported_english_isogram(void)
{
   TEST_IGNORE();
   TEST_ASSERT_TRUE(is_isogram("subdermatoglyphic"));
}
static void test_word_with_duplicated_letter_in_mixed_case(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("Alphabet"));
}
static void test_word_with_duplicated_letter_in_mixed_case_lowercase_first(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("alphAbet"));
}
static void test_hypothetical_isogrammic_word_with_hyphen(void)
{
   TEST_IGNORE();
   TEST_ASSERT_TRUE(is_isogram("thumbscrew-japingly"));
}
static void
test_hypothetical_word_with_duplicated_character_following_hyphen(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("thumbscrew-jappingly"));
}
static void test_isogram_with_duplicated_hyphen(void)
{
   TEST_IGNORE();
   TEST_ASSERT_TRUE(is_isogram("six-year-old"));
}
static void test_made_up_name_that_is_an_isogram(void)
{
   TEST_IGNORE();
   TEST_ASSERT_TRUE(is_isogram("Emily Jung Schwartzkopf"));
}
static void test_duplicated_character_in_the_middle(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("accentor"));
}
static void test_same_first_and_last_characters(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("angola"));
}
static void test_word_with_duplicated_character_and_with_two_hyphens(void)
{
   TEST_IGNORE();
   TEST_ASSERT_FALSE(is_isogram("up-to-date"));
}
int main(void)
{
   UnityBegin("test_isogram.c");
   RUN_TEST(test_empty_string);
   RUN_TEST(test_null);
   RUN_TEST(test_isogram_with_only_lower_case_characters);
   RUN_TEST(test_word_with_one_duplicated_character);
   RUN_TEST(test_word_with_one_duplicated_character_from_end_of_alphabet);
   RUN_TEST(test_longest_reported_english_isogram);
   RUN_TEST(test_word_with_duplicated_letter_in_mixed_case);
   RUN_TEST(test_word_with_duplicated_letter_in_mixed_case_lowercase_first);
   RUN_TEST(test_hypothetical_isogrammic_word_with_hyphen);
   RUN_TEST(test_hypothetical_word_with_duplicated_character_following_hyphen);
   RUN_TEST(test_isogram_with_duplicated_hyphen);
   RUN_TEST(test_made_up_name_that_is_an_isogram);
   RUN_TEST(test_duplicated_character_in_the_middle);
   RUN_TEST(test_same_first_and_last_characters);
   RUN_TEST(test_word_with_duplicated_character_and_with_two_hyphens);
   return UnityEnd();
}

This is my code:

    #include "isogram.h"

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

/* gives new char array from input, only small letters */
char* clean_words(char* ptr_input)
{
    // new container; everything bigger than 27 is impossible to be an isogram
    static char cleaned[27] = {"00000000000000000000000000"};
    int i = 0, j = 0, k = 0;
    for (int i = 0; ptr_input[i] != '\000'; i  )
    {
        k  ;
    }
    for (i=0; i <= k; i  , j  )
    {
        if (ptr_input[i] > 64 && ptr_input[i] < 91)
        {
            cleaned[j] = ptr_input[i]   32;
        }
        else if (ptr_input[i] > 96 && ptr_input[i] < 123)
        {
            cleaned[j] = ptr_input[i];
        }
        else
        {
            j--;
        }
    }
    char* ptr_output = &cleaned[0];
    return ptr_output;
}

bool is_isogram(char phrase[])
{
    if(phrase == NULL) 
        { return false; }
    char* ptr_a = clean_words(phrase);
    char ca_empty[27] = {"00000000000000000000000000"};

    for(int i = 0; i <= 27; i  , ptr_a  ){
        // first element is always copied
        if(i == 0){
                ca_empty[i] = *ptr_a;
                continue;
        }
        // '0' is sentinel, meaning the input word is finished => exit loop.
        if(*ptr_a == '0' || *ptr_a == '\000') 
            { break; }
        // following elements only copied if different than current input char
        int j = 0;
            // loop copied for doubles, exit when found
        for(;j<i;j  )
        {
            if(ca_empty[j] == *ptr_a){
                return false;
            }
        }
        // if none was found, copy new letter
        ca_empty[i] = *ptr_a;
    }
    return true;
}

So basically I solve this in 2 steps. First, I will reduce any input to small letters only. Second, I copy letter by letter to a new container and test doubles before every copy process.

Yes, there are certainly fancier solutions, but I'd like to know if anyone can spot why I get FAILED on "six-year-old". Especially, when it is working locally. Thanks! :-)

CodePudding user response:

So I figured it out by myself:

The problem is the helper function clean_words. The char array cleaned is declared as static. That means it will keep its value even after the current block is finished. When the tests run through, cleaned will still contain remaining letters of the input from other tests. The solution would be removing the static keywird or implementing a way to clean up the container, like

memset(cleaned, '0', 26);

From https://en.cppreference.com/w/c/language/storage_duration static storage duration. The storage duration is the entire execution of the program, and the value stored in the object is initialized only once, prior to main function. All objects declared static and all objects with either internal or external linkage that aren't declared _Thread_local (since C11) have this storage duration.

  • Related