-1

In this exercise I put two words then I do a function to check if they are anagram, but there is an error in the output knowing that the outpout is true of which there is the same length of the two words

Example of words Anagram:

bob - obb

users - resus

can you help me...

bool Anagram(int l, int k, char T1[l],char T2[k])
{
    int i = 0;

    while (i < l)
    {
        for (int j = 0; j < k; j++)
        {
             if (T1[i] != T2[j])
             {
                 return 0;
             }
        }

        i++;
    }

    return 1;
}

int main()
{
    char T1[100], T2[100];

    printf("Give the first word :");
    gets(T1);

    int k = strlen(T1);//k is the length of the first word

    printf("Give the second word :");
    gets(T2);

    int l = strlen(T2);//l is the length of the second word
    
    if (l != k)
    {
        printf("\nThe two words are not Anagrams !\n");
        return 0;
    }
    else
    {
        if (Anagram(l, k, T2, T1) == true)
        {
            printf("\nThe two words are Anagrams !\n");
        }
        else
        {
            printf("\nThe two words are not Anagrams !\n");
        }
    }
}
MED LDN
  • 684
  • 1
  • 5
  • 10
  • So what did you do after you found the code didn't work? The normal thing to do is to debug it. Run your code in a debugger and step thru it line by line, examining the state as it runs. Debugging should allow you to tell us much more about where things start going wrong. [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – kaylum Nov 21 '20 at 20:41
  • 1
    The `Anagram` algorithm is just plain wrong. You return false as soon as a letter in the first word does not match **any** letter in the second word. For example, for `bob` and `obb` you will return false because the `b` in the first word does not match the `o` in the second. – kaylum Nov 21 '20 at 20:48
  • 1
    This won't work because your algorithm is completely broken. Use a frequency table. I.e. given `bob` and `obb`, consider an algorithm where you build a frequency table of the first word (which will result in b:2, o:1) Then scan the second string and use that table to verify whether the current character is accounted. if it's there, decrement the count in the table and move on. When done, if the table is empty and there were no under-hits (chars in the second string that weren't in the table), you have an anagram. – WhozCraig Nov 21 '20 at 20:49
  • @kaylum An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once, in the example bob - obb the function returns true because the letter b exist 2 times in the first word and also 2 times in the second word, also for the letter o – MED LDN Nov 21 '20 at 21:14
  • I know what an anagram is. But as I explained your algorithm isn't correct. `for(int j=0;j – kaylum Nov 21 '20 at 21:18
  • 2
    Have a look at [Why gets() is so dangerous it should never be used!](https://stackoverflow.com/q/1694036/3422102) – David C. Rankin Nov 21 '20 at 22:38
  • 1
    Sort the letters and compare the words (copy first if you ignore whitespaces) – Déjà vu Nov 22 '20 at 00:11

3 Answers3

1

qsort is your friend! Why reinvent the wheel? The stdlib provides all means for this task! Whitespace can easily be stripped after sorting using strcspn, as each of the whitespace chars ascii code is < alnum characters ascii code. If you don't want to rely on those ascii properties, the compare_chars function can easily adapted so that all whitespace are sorted either to the front or to the end (In the example it sorts the ws to the end). I wonder if somebody comes up with a unicode version of isAnagram. Please note that i applied the sorting on a copy of the original strings so that the isAnagram function does not mess up the input.

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

int compare_chars(const void *c1, const void *c2)
{
    // Sign corresponds to backward sorting so that
    // whitespace appears at the end
    return *(char *)c2 - *(char *)c1;
}

void sort_remove_whitespace(const char *src, char dest[strlen(src) + 1])
{
    strcpy(dest, src);
    qsort(dest, strlen(dest), sizeof(char), compare_chars);
    dest[strcspn(dest, " \b\t\v\r\n")] = '\0';
}

bool isAnagram(char* T1, char *T2)
{
    char T1_copy[strlen(T1) + 1];
    char T2_copy[strlen(T2) + 1];
    
    sort_remove_whitespace(T1, T1_copy);
    sort_remove_whitespace(T2, T2_copy);
    
    printf("T1 sorted: '%s', T2 sorted: '%s'\n", T1_copy, T2_copy);
    
    return 0 == strcmp(T1_copy, T2_copy);
}

void prompt(const char *msg, char *buf, size_t N)
{
    char *fgets_return;

    puts(msg);
    fgets_return = fgets(buf, N, stdin);
    
    if (NULL == fgets_return)
    {
        printf("Input error!");
        exit(-1);               // fail fast fail early
    }
    
    printf("OK. Got %s\n", buf);
}

int main()
{
    char T1[100], T2[100];

    prompt("Give the first word :", T1, sizeof(T1));
    prompt("Give the second word :", T2, sizeof(T2));

    if ( isAnagram(T1, T2) )
    {
        printf("The two words are Anagrams !\n");
    }
    else
    {
        printf("The two words are not Anagrams !\n");
    }

    return 0;
}

Example output:

Give the first word :
dead beef
OK. Got dead beef

Give the second word :
fat thief
OK. Got fat thief

T1 sorted: 'feeeddba', T2 sorted: 'ttihffea'
The two words are not Anagrams !


Give the first word :
anagram
OK. Got anagram

Give the second word :
nag a ram
OK. Got nag a ram

T1 sorted: 'rnmgaaa', T2 sorted: 'rnmgaaa'
The two words are Anagrams !
  • The only issue is that anagrams are not required to be the same length. They are comprised of the same letters (not including whitespace). The classic example is `"anagram"` and `"nag a ram"`. That is a proper anagram, even though the second rearrangement of characters contains whitespace. – David C. Rankin Nov 21 '20 at 23:41
  • Also, since you ignore whitespace, no need to remove trailing newline (but good job on thinking to do that) – David C. Rankin Nov 21 '20 at 23:48
  • Yep, I figured that is where you were going `:)` – David C. Rankin Nov 21 '20 at 23:49
  • I undeleted my former post as i updated the algorithm to check for anagram not for palindrome. – Wör Du Schnaffzig Nov 22 '20 at 22:20
1

The biggest problem is with your concept of Anagram. The classic example is:

"anagram"
"nag a ram"

Each uses the same letters exactly once with whitespace ignored.

There are several ways to approach determining in two strings are an anagram. You can either use a single array (generally of 128 integer values initialized all zero to cover all characters in the ASCII character set, or 256 to also cover the Extended-ASCII characters.

With the single array, you simply loop over each string. With the first string for each non-whitespace character you increment the index corresponding to the ASCII value of the character, and for the second string you decrement the value at the index corresponding to the ASCII value of the character. At the end, if each character in each string is used exactly the same number of times -- all array values will be zero which will confirm an anagram.

Using two arrays of the same size (either 128 or 256), you simply loop over the characters in each string and for each non-whitespace character you increment the index corresponding to that characters ASCII value in similar fashion, but when done, you compare whether the two arrays are equal to each other with a loop or memcmp().

A short implementation would be:

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

#define NCHARS 256      /* constant to count array size, covers ASCII + extended ASCII */

int isanagram (const char *s1, const char *s2)
{
    int count[NCHARS] = {0};            /* counting array, covers all extended ASCII */
    
    for (; *s1; s1++)                   /* loop over chars in string 1 */
        if (!isspace(*s1))              /* if not whitespace */
            count[(int)*s1]++;          /* add 1 to index corresponding to char */
    
    for (; *s2; s2++)                   /* loop over chars in string 2 */
        if (!isspace(*s2))              /* if not whitespace */
            count[(int)*s2]--;          /* subtract 1 from index corresponding to char */
    
    for (int i = 0; i < NCHARS; i++)    /* loop over counting array */
        if (count[i])                   /* if any index non-zero, not anagram */
            return 0;
    
    return 1;       /* all chars used same number of times -> anagram */
}

(NULL parameter checks omitted above, add for completeness)

To test you could use a simple main() that reads two strings and then checks the return from the function above. A return of 1 (true) means the words are anagrams, otherwise they are not anagrams. Simple press Enter alone on a line to quit.

int main (void) {
    
    char str1[NCHARS * 4], str2[NCHARS * 4];    /* arrays for string 1 & string 2 */
    
    for (;;) {  /* loop continually */
        fputs ("\nenter string 1: ", stdout);
        if (!fgets (str1, sizeof str1, stdin) || *str1 == '\n') /* EOF or ENTER alone */
            break;
        
        fputs ("enter string 2: ", stdout);
        if (!fgets (str2, sizeof str2, stdin) || *str2 == '\n') /* EOF or ENTER alone */
            break;
        
        printf ("\nwords %s an anagram\n", isanagram (str1, str2) ? "are" : "are not");
    }
}

Example Use/Output

$ ./bin/anagram_count_array

enter string 1: anagram
enter string 2: nag a ram

words are an anagram

enter string 1: anagram
enter string 2: naag a ram

words are not an anagram

enter string 1: cat
enter string 2: tac

words are an anagram

enter string 1: cat
enter string 2:     a       t        c

words are an anagram

enter string 1:

Look things over and let me know if you have questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
-1

As I understand your anagram is just the word with ordered other wany same letters.

#define NCHARS  (127-31)

int *freq(const char *str)
{
    int *freqTable = calloc(NCHARS, sizeof(freqTable)) ;

    if(freqTable)
    {
        while(*str)
        {
            if( *str < ' ') 
            {
                free(freqTable);
                freqTable = NULL;
                break;
            } 
            freqTable[*str++ -' ']++;
        }
    }
    return freqTable;
}


bool isAnagram(const char *str1, const char *str2)
{
    int *freq1 = freq(str1), *freq2 = freq(str2);
    bool result = false;

    if(freq1 && freq2)
    {
        result = !memcmp(freq1, freq2, sizeof(*freq1) * NCHARS);
    }
    free(freq1); free(freq2);
    return result;
}

int main(void)
{
    printf("%d", isAnagram("bob", "obb"));
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • The free in the nested block can make all sorts of hazzle because one is tempted to place another free in the callers scope ! This already happened, here in the `isAnagram` function. – Wör Du Schnaffzig Nov 23 '20 at 08:36