Search code examples
cfor-loopstrlen

Why does strlen function not work in this for loop condition?


I am learning C and I have question. In this exercise I have to program a game called double dutch where you learn to practice with strings. The problem I ran into is that the program stops executing because of the for loop condition (in the first for loop). The strlen() function works well in main and in the ayInFrontOfConsonant function at first when I print the length of the string but I don't get why the program stops working. In Xcode I get the message: Thread 1: EXC_BAD_ACCESS. Any help is very much appreciated.

void ayInFrontOfConsonant(char *str) 
{
    char consonants[42] = { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 
'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', 'B', 
'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 
'T', 'V', 'W', 'X', 'Y', 'Z'};


    int a=(int)strlen(str);

    printf("\n Length of str in ay function:   %d\n",a);

    int i=0,j=0;
    for(i=0;i<strlen(str);i++)      //problem is here
    {
        for(j=0;j<strlen(consonants);j++)
        {
            if(str[i]==consonants[j])
            {
                //insertChar(str, 'a', i);

            }
        }
    }
}

int main()
{
    int a=0;
    printf("** Welcome to the Double Dutch game **\n");
    char myString[36];
    printf("Please enter a string: ");
    scanf("%[^\n]s", myString);

    a=strlen(myString);
    printf("Length of string in main: %d\n",a);

    ayInFrontOfConsonant(myString);


    printf("Double dutch traslation: %s\n",myString);


    return 0;

}


Solution

  • Your array has no null terminator.

    Instead of that, use sizeof consonants / sizeof *consonants — or in this particular case since sizeof *consonants is surely 1, then just sizeof consonants.

    You should not use strlen() in the condition of a for loop, because it traverses the string every time, until it finds the null terminator which is missing in your

    char consonants[42] = { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 
        'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', 'B', 
        'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 
        'T', 'V', 'W', 'X', 'Y', 'Z'};
    

    If you use

    const char *consonant = "bcdf ...";
    

    instead, the compiler will add the '\0' terminator, you can also add it explicitly

    char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 
            'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', 'B', 
            'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 
            'T', 'V', 'W', 'X', 'Y', 'Z', '\0'};
    

    A programmer would probably write this instead,

    #include <stdlib.h>
    
    void ayInFrontOfConsonant(char *str) 
    {
        char consonants[] = {
            'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 
            'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', 'B', 
            'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 
            'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'
        };
    
        for (size_t i = 0; str[i] != '\0'; i++) {
            for (size_t j = 0; j < sizeof consonants; ++j) {
                if (str[i] == consonants[j]) {
                    // Do here whatever you wanted to do
                }
            }
        }
    }
    

    But not really, because there is no need to scan the whole array of consonants since they can be sorted and you can use binary search which would improve the algorithm a lot.