B Kazimy
B Kazimy

Reputation: 55

How to check if a char is present two times in an array of char in c?

I wanted to check if one char is present in an array of char twice, but strchr() will return the position of the first occurring char.

I was thinking of slicing the array like Python does arr[3:], considered from the 3rd element onward. Does C have such a capability?

if not, what is the best solution for this problem?

Shall I make it myself with for loop, if else, and global variables?

Upvotes: 0

Views: 140

Answers (4)

Andreas Wenzel
Andreas Wenzel

Reputation: 25396

NOTE: This is an answer to revision 2 of the question, which asked how to determine whether any character in a string occurs more than once. Meanwhile, the question has been reverted back to revision 1, which asked how to determine whether a single character occurs more than once. See my other answer for an answer to that question.

A simple, but inefficient way to solve the problem is to

  • load the first character, and compare that character with all characters that come after that character in the string, and then
  • load the second character and compare that character with all characters that come after that character in the string, and then
  • load the third character and do the same, and then
  • keep repeating until you reach the end of the array.

Here is an example:

// This function will return `true` if any duplicates were found,
// otherwise false.
bool check_for_duplicates_inefficiently( const char *str )
{
    int length = strlen( str );

    for ( int i = 0; i < length; i++ )
    {
        for ( int j = i + 1; j < length; j++ )
        {
            if ( str[i] == str[j] )
                return true;
        }
    }

    return false;
}

A more efficient solution is to create an array arr of 26 bool elements (one for every character of the English alphabet) and to initialize them to false. The element arr[0] will specify whether 'a' was encountered, arr[1] will specify whether 'b' was encountered and arr[25] will specify whether 'z' was encountered.

You can then loop over all characters of the string and then set the array elements accordingly.

If an array element was already true when you try to set it, then you know that you have a duplicate character. After looping over all characters, you can verify that all elements are true.

Here is an example:

// This function will return `true` if any duplicates were found,
// otherwise false.
bool check_for_duplicates_efficiently( const char *str )
{
    // initialize array elements to 0/false
    bool letters[26] = {0};

    int length = strlen( str );

    for ( int i = 0; i < length; i++ )
    {
        int c = (unsigned char)str[i];

        if ( isalpha( c ) )
        {
            c = toupper( c );

            int offset = c - 'A';

            if ( letters[offset] )
                return true;

            letters[offset] = true;
        }
    }

    return false;
}

Note that this answer is assuming that all characters in the string are English alphabetical letters, and that the default locale is being used.

Also note that this solution only works in character sets in which the characters A to Z are contiguous. This is the case with ASCII, and most character sets are ASCII-compatible. However, it is not the case with some uncommon character sets, such as EBCDIC.

Here is a test function of both funtions:

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

// This function will return `true` if any duplicates were found,
// otherwise false.
bool check_for_duplicates_inefficiently( const char *str )
{
    int length = strlen( str );

    for ( int i = 0; i < length; i++ )
    {
        for ( int j = i + 1; j < length; j++ )
        {
            if ( str[i] == str[j] )
                return true;
        }
    }

    return false;
}

// This function will return `true` if any duplicates were found,
// otherwise false.
bool check_for_duplicates_efficiently( const char *str )
{
    // initialize array elements to 0/false
    bool letters[26] = {0};

    int length = strlen( str );

    for ( int i = 0; i < length; i++ )
    {
        int c = (unsigned char)str[i];

        if ( isalpha( c ) )
        {
            c = toupper( c );

            int offset = c - 'A';

            if ( letters[offset] )
                return true;

            letters[offset] = true;
        }
    }

    return false;
}

void perform_check_and_print_result( const char *str, int spacing )
{
    bool results[2];

    results[0] = check_for_duplicates_inefficiently( str );
    results[1] = check_for_duplicates_efficiently( str );

    spacing = spacing - strlen( str ) + 1;
    if ( spacing < 0 )
    spacing = 0;

    if ( results[0] != results[1] )
    {
        printf(
            "Both functions disagree on whether the string %*c%s\" "
            "contains duplicates.\n",
            spacing,
            '\"',
            str
        );
    }
    else
    {
        printf(
            "Both functions agree that the string %*c%s\" DOES "
            "%s contain duplicate characters.\n",
            spacing,
            '\"',
            str,
            results[0] ? "   " : "NOT"
        );
    }
}


int main( void )
{
    perform_check_and_print_result( "ab"  , 4 );
    perform_check_and_print_result( "aba" , 4 );
    perform_check_and_print_result( "abc" , 4 );
    perform_check_and_print_result( "abca", 4 );
    perform_check_and_print_result( "abcb", 4 );
    perform_check_and_print_result( "abcc", 4 );
    perform_check_and_print_result( "abcd", 4 );
}

This program has the following output:

Both functions agree that the string   "ab" DOES NOT contain duplicate characters.
Both functions agree that the string  "aba" DOES     contain duplicate characters.
Both functions agree that the string  "abc" DOES NOT contain duplicate characters.
Both functions agree that the string "abca" DOES     contain duplicate characters.
Both functions agree that the string "abcb" DOES     contain duplicate characters.
Both functions agree that the string "abcc" DOES     contain duplicate characters.
Both functions agree that the string "abcd" DOES NOT contain duplicate characters.

Upvotes: 2

Andreas Wenzel
Andreas Wenzel

Reputation: 25396

NOTE: This is an answer to revision 1 of the question, which asked how to determine whether a single character occurrs more than once. Meanwhile, the question has been changed to ask how to determine whether any character occurs more than once. I have therefore answered the latest version of the question in a separate answer. EDIT: At the time of this writing, the question has reverted back to revision 1.

but strchr() will return the position of the first occurring char.

You can call strchr twice. The second call will find the second character, if it exists. Here is an example:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool does_char_exist_twice( const char *str, char c )
{
    const char *p;

    // try to find first occurrence of character, returning
    // false on failure
    p = strchr( str, c );
    if ( p == NULL )
        return false;

    // make p point one past the first occurrence
    p++;

    // try to find second occurrence of character
    p = strchr( p, c );

    // return true if second occurrence found, otherwise false
    return p != NULL;
}

void perform_check_and_print_result( const char *str, char c )
{
    // call the function "does_char_exist_twice" and print the result
    printf(
        "The character '%c' DOES %s exist at least twice in \"%s\".\n",
        c,
        does_char_exist_twice(str, c) ? "   " : "NOT",
        str
    );
}

int main( void )
{
    perform_check_and_print_result( "ab"  , 'a');
    perform_check_and_print_result( "aba" , 'a');
    perform_check_and_print_result( "abc" , 'a');
    perform_check_and_print_result( "abca", 'a');
}

This program prints the following output:

The character 'a' DOES NOT exist at least twice in "ab".
The character 'a' DOES     exist at least twice in "aba".
The character 'a' DOES NOT exist at least twice in "abc".
The character 'a' DOES     exist at least twice in "abca".

Upvotes: 3

Schwern
Schwern

Reputation: 165546

I have to take input from users of all English alphabet, and I should make sure the user did not type any character twice. (case-insensitively)

strchr will only find one character at a time. You're looking for many characters. You could repeatedly call strchr, but this is inefficient as it has to rescan the string for each character.

Instead, scan the string once and keep a count of how many times each character is seen. In Python you'd use a dict, but C doesn't have those. Instead, use an array wide enough to store every letter.

#include <ctype.h>

int first_repeat_letter(const char *string)
{
    // Initialize the count array to all zeros.
    int char_counts[26] = {0};
    for (int i = 0; string[i] != '\0'; i++)
    {
        // Ignore case.
        int c = tolower(string[i]);

        // Ignore non-letters.
        if (!isalpha(c))
        {
            continue;
        }

        // This converts the letters to a number between 0 and 25.
        // 'a' - 'a' = 0, 'b' - 'a' = 1, 'z' - 'a' = 25.
        int idx = c - 'a';
        char_counts[idx]++;

        // Return the index where the duplicate was found.
        if (char_counts[idx] >= 2)
        {
            return i;
        }
    }

    return -1;
}

By returning the index the caller can find the duplicate letter.

#include <stdio.h>

char string[] = "abcdef1123";
int i = first_repeat_letter(string);
if (i < 0)
{
    printf("No repeats found in '%s'\n", string);
}
else
{
    printf("Repeat char found in '%s': '%c' at %d\n", string, string[i], i);
}

Demonstration.

Actually I want all characters of the English alphabet to be there once, and I'm checking if any are repeated.

This can easily be adapted to that as well. Iterate through char_count and verify each element is 1.

Upvotes: -1

alex01011
alex01011

Reputation: 1702

A simple solution would be to combine strchr and strrchr:

  • strchr will return a pointer to the first occurrence of the character
  • strrchr will return a pointer to the last occurrence of the character

Shall the pointers be equal, then either the character doesn't exist (both calls returned null) or it only exists once (both pointers point to the same character).

#include <string.h>

int char_exists_twice(const char *s, char c) {
    // probably a good idea to check if s is null as well
    const char *first = strchr(s, c);
    const char *last  = strrchr(s, c);

    return first != last;
}

Upvotes: 1

Related Questions