-1

I need to make a program that will print characters in a word on how frequent it is used. The unique characters will be printed in increasing order (spaces are ignored), if there are ties the character with lower ascii value will be printed first.

For an example if the input is hello world, the letters "h", "e", "w", "r" and "d" are only used once, the character "o" is used twice and the character "l" is used thrice. Since h,e,w,r,d are tie we should sort it into d,e,h,r,w. Then next would be o since it is used twice and then last is l. Thus if the input is hello world the output must be dehrwol. On my current program the problem is that when there are ties, it would not sort it alphabetically so the output is hewrdol instead of dehrwol.

This is the code I have written

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

int times[256];

int cmpLetters(const void* a, const void* b)

{

return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);

}

int main()

{

char letters[256];

int i, j, k, lnum, t;

char s[1000];


fgets(s, sizeof(s), stdin);

// Init occurrences as 0

memset(times, 0, sizeof(times));

for (i = lnum = 0; s[i] != '\0'; i++)

if (times[s[i]]++ == 0)

letters[lnum++] = s[i];

// Sort letters by number of occurrences

qsort(letters, lnum, sizeof(char), cmpLetters);

char* new = malloc(sizeof(char) * (i + 1));

for (j = k = 0; j < lnum; j++)

for (i = 0; i < times[letters[j]]; i++)

new[k++] = letters[j];

// new[k] = '\0';

for (i = 0; i<lnum; i++)

{

if(letters[i] != '\n' && letters[i] !=' ')

printf("%c",letters[i]);

}

printf("\n\n");



return 0;

}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    Please fix your indentation. – 500 - Internal Server Error Nov 16 '22 at 11:55
  • Hi, I fixed it already should now be running – edmung vunxh Nov 16 '22 at 12:05
  • That's a novel use of `qsort`. All you need to do is incorporate a comparison of the two values in `cmpLetters`. – William Pursell Nov 16 '22 at 12:05
  • You should certainly also fix many things in `main` (check the return value of `scanf`, always), but you can probably get by with just doing: `char a = *(char *)av; char b = *(char *)bv; return times[a] == times[b] ? a - b : times[a] - times[b];` – William Pursell Nov 16 '22 at 12:11
  • `scanf("%d",&t);` leaves the newline character in the input buffer, so the first `fgets` will read an empty string. [scanf() leaves the newline character in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-newline-character-in-the-buffer) – Retired Ninja Nov 16 '22 at 12:11
  • Sorry that one is to take multiple number of inputs at one run, I have edited my code already and removed that part thank you – edmung vunxh Nov 16 '22 at 12:16
  • 1
    There is still no indentation applied at all. And while you fix that, maybe also remove most of those empty lines. – Gerhardh Nov 16 '22 at 12:20

1 Answers1

0

In this for loop

for (i = lnum = 0; s[i] != '\0'; i++)

if (times[s[i]]++ == 0)

letters[lnum++] = s[i];

you are not checking whether s[i] represents a letter.

The comparison function

int cmpLetters(const void* a, const void* b)

{

return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);

}

compares only characters without comparing also their frequencies.

This code snippet

char* new = malloc(sizeof(char) * (i + 1));

for (j = k = 0; j < lnum; j++)

for (i = 0; i < times[letters[j]]; i++)

new[k++] = letters[j];

does not make sense because the array new is not used further in the program. It only produces a memory leak.

The program will be simpler if to introduce a structure that contains two data members that store a letter and its frequency.

Here is a demonstration program.

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

struct Pair
{
    char c;
    size_t n;
};

int cmp( const void *a, const void *b )
{
    const struct Pair *p1 = a;
    const struct Pair *p2 = b;

    int result = ( p2->n < p1->n ) - ( p1->n < p2->n );

    if (result == 0)
    {
        result = ( p2->c < p1->c ) - ( p1->c < p2->c );
    }

    return result;
}

int main( void )
{
    enum { N = 1000} ;
    char s[N];

    fgets( s, sizeof( s ), stdin );

    size_t n = 0;

    for (size_t i = 0; s[i] != '\0'; ++i)
    {
        if (isalpha( ( unsigned char )s[i] ))
        {
            size_t j = 0;

            while (j != i && s[j] != s[i]) ++j;

            n += j == i;
        }
    }

    if (n != 0)
    {
        struct Pair pairs[n];
        memset( pairs, 0, n * sizeof( struct Pair ) );

        for (size_t i = 0, m = 0; s[i] != '\0'; i++)
        {
            if (isalpha( ( unsigned char )s[i] ))
            {
                size_t j = 0;

                while (j != m && pairs[j].c  != s[i]) ++j;

                if (j == m)
                {
                    pairs[m].c = s[i];
                    ++pairs[m].n;
                    ++m;
                }
                else
                {
                    ++pairs[j].n;
                }
            }
        }

        qsort( pairs, n, sizeof( *pairs ), cmp );

        for (size_t i = 0; i < n; i++)
        {
            putchar( pairs[i].c );
        }
        putchar( '\n' );
    }
}

The program output might look like

hello world
dehrwol
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335