How to create a function that counts the characters of a sentence and shows the frequency of one?

Asked

Viewed 102 times

-3

Context

I need to create a function - using the C language - that from a sentence counts its characters and tells how many times each character appeared.

Example

Phrase: good proof to all Upshot:

b = 1
o = 4
a = 3
p = 1
r = 1
v = 1
t = 1
d = 1
s = 1
! = 1
  • One possibility is you sort the characters of your string and go counting the repetitions. I didn’t see in your table the space counter, it’s not to count?

2 answers

1

Unlike the other answer, you don’t need to sort characters or anything like that.

Just scroll through the characters and go computing the totals. And how one char in C always has 1 byte (and therefore there are 256 possible values), you can create an array with 256 positions, and go saving the totals of each character in it:

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

int main(void) {
    char *str = malloc(1024);
    if (str == NULL) {
        printf("Erro ao alocar memória\n");
        exit(EXIT_FAILURE);
    }
    printf("digite a frase:");
    if (fgets(str, 1024, stdin) == NULL) {
        printf("Erro ao ler dados\n");
        exit(EXIT_FAILURE);
    }
    int counts[256] = { 0 };
    // percorre a string, atualizando a contagem de cada caractere
    for (char *ptr = str; *ptr != '\0' && *ptr != '\n'; ptr++) {
        if (*ptr != ' ') // entendi que não conta os espaços
            counts[(unsigned char) *ptr]++;
    }

    // mostra os totais que forem maiores que zero
    for (int i = 0; i < 256; i++) {
        if (counts[i] != 0)
            printf("%c = %d\n", i, counts[i]);
    }

    free(str);
    return 0;
}

Also be sure to allocate space for the string before calling fgets - the other answer did not do this, and if it worked, it is by coincidence, therefore call fgets without allocating memory before has undefined behavior and it’s not guaranteed that it always works - so much so that I tested it without allocating memory and it didn’t work (see the difference here and here).

Anyway, I made one for checking that the character is not the null Terminator or the \n - for fgets adds the \n, except if you type more characters than indicated by the second parameter (because in this case you will not have the \n).

Of course, if you’re going to use this string later and you don’t want the \n, then it’s worth doing what was done in the other answer. But if you just want to count the characters and nothing else, I think it’s simpler to do a single loop and stop when you find the \n or the \0.

In this loop I’ll update the count of each character, taking advantage of the fact that in fact char are bytes and can be interpreted as numbers (and therefore I can use them as array indices counts). I didn’t count the spaces, which seems to be what you wanted (but if so, just change the if within the for, to choose which characters will be counted).

This is more efficient by going through the string only once. I saw no need to sort it (and even more so using a quadratic algorithm), and on top of that strlen is called several times, which makes everything even more inefficient.

0


I made the algorithm according to @anonimo’s idea:

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

int main() {
    char* frase;
    fgets (frase, 256, stdin);

    // Verificando se o último caracter é uma quebra de linha e substituindo
    if (frase[strlen(frase)-1] == '\n') {
        frase[strlen(frase)-1] = '\0';
    }

    // Ordenando a frase
    for (int i = 0; i < strlen(frase); i++) {
        for (int o = 0; o < strlen(frase); o++) {
            if (frase[i] < frase[o]) {
                char temp = frase[i];
                frase[i] = frase[o];
                frase[o] = temp;
            }
        }    
    }

    // Imprimindo na tela    
    char caracterAtual = frase[1];
    int contador = 0;
    for (int i = 1; i <= strlen(frase); i++) {
        if (frase[i] != ' ') {
            if (frase[i] == caracterAtual) {
                contador++;
            } else {
                if (caracterAtual != ' ') {
                    printf("%c = %d\n", caracterAtual, contador);
                }
                contador = 1;
                caracterAtual = frase[i];
            }
        }
    }
    
    return 0;
}

First he orders the characters of the phrase for the same to be next to each other. Secondly, it traverses the ordered string and counts how many equal characters are followed by each other, if the next character is different, it prints the amount it found and restarts the counter. In this example I did he will ignore the spaces. Of course I can improve but C is not my specialty.


Entree:

boa prova a todos!

Exit:

! = 1
a = 3
b = 1
d = 1
o = 4
p = 1
r = 1
s = 1
t = 1
v = 1
  • Just one observation: the function fgets embeds, as a character of the string read the character \n which signals the end of the input (provided that the string read has fewer characters than the maximum specified in the function), so you must check whether the last character of the string is ' n' and, if so, replace it with a ' 0'.

  • Thank you for the warning. I edited the answer, I could say if what I did is correct?

  • There is a problem - that is often not perceived - that is to keep calling strlen several times: https://answall.com/q/167528/112052

  • Not to mention calling fgets without first having allocated memory for the phrase generates undefined behavior and is not guaranteed to always work - example: https://ideone.com/6PkLjg

  • Do not use the function strlen() to iterate through a string, facilitates reading but weighs in code performance

Browser other questions tagged

You are not signed in. Login or sign up in order to post.