Как найти количество вхождений в массиве символов в C? - PullRequest
0 голосов
/ 06 октября 2018

Я пытаюсь ввести слово и узнать, сколько раз были напечатаны буквы.

Скажите, что мой ввод "привет"

Мой вывод будет: h = 1, e= 1 л = 2 и т. Д.

Я очень близок к пониманию этого, но у меня есть небольшая проблема с этим кодом:

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

void find_frequency(char s[], int count[]) {
    int c = 0;

    while (s[c] != '\0') {
        if (s[c] >= 'a' && s[c] <= 'z' )
            count[s[c]-'a']++;
        c++;
    }
}

int main()
{
    char string[100];
    int c, count[26] = {0};

    printf("Input a string\n");
    gets(string);

    find_frequency(string, count);

    printf("Character Count\n");

    for (c = 0 ; c < 26 ; c++)
        if(count[c] > 0)
            printf("%c : %d\n", c + 'a', count[c]);
    return 0;
}

Этот код выполняет половину работы, ноне все.

Вывод в алфавитном порядке.Как я могу изменить это, чтобы дать мне вывод только chararray, который является входным?

Ответы [ 4 ]

0 голосов
/ 06 октября 2018

Если вы пытаетесь получить счет по порядку вместо счетчика в в алфавитном порядке , вам просто нужно согласовать индексы массива count с порядкомсимволов в вашем входном буфере.Чтобы сделать это, просто зациклите все символы в вашем входном буфере и сделайте второй проход, подсчитав, сколько раз текущий символ встречается.Это даст вам порядковый счетчик количества повторений каждого символа, например,

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

#define COUNT  128
#define MAXC  1024

int main (void) {

    char buf[MAXC] = "";                /* buffer to hold input */
    int count[COUNT] = {0};             /* array holding inorder count */

    fputs ("enter string: ", stdout);   /* prompt for input */

    if (!fgets (buf, MAXC, stdin)) {    /* read line into buf & validate */
        fputs ("error: EOF, no valid input.\n", stderr);
        return 1;
    }

    /* loop over each character not '\n' */
    for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
        char *p = buf;          /* pointer to buf */
        size_t off = 0;         /* offset from start of buf */
        while ((p = strchr (buf + off, buf[i]))) {  /* find char buf[i] */
            count[i]++;         /* increment corresponding index in count */
            off = p - buf + 1;  /* offset is one past current char */
        }
    }
    for (int i = 0; count[i]; i++)  /* output inorder character count */
        printf (i ? ",  %c: %d" : "%c: %d", buf[i], count[i]);
    putchar ('\n');     /* tidy up with new line */

    return 0;
}

( примечание: strchr используется для удобства, чтобы просто найти следующее вхождениетекущего символа в строке, а затем off (смещение) используется для начала поиска со следующим символом, пока не найдены другие совпадения в строке. Вы можете просто использовать дополнительный цикл над символами в буфере, если выкак.)

Пример использования / Вывод

$ /bin/charcnt_inorder
enter string: hello
h: 1,  e: 1,  l: 2,  l: 2,  o: 1

Тем не менее, это пересчитывает каждый символ и дает счет снова, если символ дублируется (например, l: 2, l: 2 за каждый 'l').Теперь неясно из:

«мой вывод будет: h = 1, e = 1 l = 2 и т. Д.»

что вы намеревались в этом отношении, но с небольшим дополнительным усилиемВы можете использовать отдельный индекс и отдельный массив для хранения первого экземпляра каждого символа (скажем, массива chars[]) вместе со счетчиком каждого в вашем массиве count[] и сохранить количество внутренних символов, удаляя дубликаты символов.Необходимые изменения показаны ниже:

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

#define COUNT  128
#define MAXC  1024

int main (void) {

    char buf[MAXC] = "",
        chars[COUNT] = "";              /* array to hold inorder chars */
    int count[COUNT] = {0};
    size_t cdx = 0;                     /* add count index 'cdx' */
    fputs ("enter string: ", stdout);

    if (!fgets (buf, MAXC, stdin)) {
        fputs ("error: EOF, no valid input.\n", stderr);
        return 1;
    }

    for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
        char *p = buf;
        size_t off = 0;
        chars[cdx] = buf[i];            /* store in chars array */
        if (i) {                        /* if past 1st char */
            int n = i;
            while (n--)                 /* simply check all before */
                if (buf[n] == buf[i])   /* if matches current */
                    goto next;          /* bail and get next char */
        }
        while ((p = strchr (buf + off, buf[i]))) {
            count[cdx]++;               /* increment count at index */
            off = p - buf + 1; 
        }
        cdx++;                          /* increment count index */
        next:;                          /* goto label to jump to */
    }
    for (int i = 0; count[i]; i++)
        printf (i ? ",  %c: %d" : "%c: %d", chars[i], count[i]);
    putchar ('\n');

    return 0;
}

Пример использования / Вывод

$ /bin/charcnt_inorder2
enter string: hello
h: 1,  e: 1,  l: 2,  o: 1

или

$ ./bin/charcnt_inorder2
enter string: amarillo
a: 2,  m: 1,  r: 1,  i: 1,  l: 2,  o: 1

Теперь ваш 'l'сообщается только один раз с правильным счетом.

Обратите внимание, что в каждом примере вы должны выполнять дополнительную проверку для обеспечения полного соответствия ввода в вашем буфере и т. д. ... Массив countchars)имели размер 128, чтобы охватить весь диапазон значений ASCII.Не экономьте на размере буфера.Если вы явно ограничите свой ввод в верхнем или нижнем регистре - тогда вы можете ограничить размер счета до 26, в противном случае вам нужно учитывать дополнительные символы и знаки препинания, которые будут встречаться.То же самое относится и к вашему входному буферу.Если вы ожидаете, что ваш максимальный вклад составит 500 символов, удвойте его (как правило, до следующей доступной степени два, нет реальных требований к степени двойки, но вы, вероятно, увидите это так).

Суть в том, что я предпочел бы быть на 10 000 символов длиннее, чем один символ слишком коротким ..., что приводит к неопределенному поведению .

И наконец, как упоминалось в моем комментарии никогда, никогда, никогда использовать gets.Это настолько небезопасно, что было удалено из стандартной библиотеки C в C11.Вместо этого используйте fgets или POSIX getline.

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 06 октября 2018

Непонятно, что вы подразумеваете под:

Как я могу изменить его, чтобы он выдавал мне вывод только chararray, который вводится?

Потому что это точночто вы делаете в любом случае: ввод массива char в функцию;который обновляется с номерами в алфавитном порядке;и позже выведите как есть.

Итак, я предполагаю, что вы хотите вывести счет в том же порядке, в котором каждый символ был впервые обнаружен?


Решение

Это потребует немного больше работы.Вы можете сохранить второй массив, отслеживая порядок, с которым встречается каждый символ в find_frequency.Но затем эта простая функция очистки начинает делать слишком много.

Так что рассмотрите скорее настройку, как вы делаете вывод:

void output_frequency(char s[], int count[]) {
    int c = 0;

    //loop s for the output
    while (s[c] != '\0') {
        if (s[c] >= 'a' && s[c] <= 'z' ) {
            //found a character, report the count only if not reported before
            if (count[s[c]-'a'] > 0) {
                printf("%c : %d\n", s[c], count[s[c] - 'a']);
                count[s[c]-'a'] = 0; //so you don't report this char again
            }
        }
        c++;
    }
}
0 голосов
/ 06 октября 2018

Как и Ry- , предложенный в этом комментарии , вы можете перебрать исходную строку и использовать символы в качестве индексов в своей таблице частот.Что-то вроде следующего:

int len_string = strlen(string);

for (c=0; c<len_string; c++) {
  char ch = string[c];
  printf("%c: %d, ", ch, count[ch-'a']);
}

Это не будет полностью соответствовать вашему ожидаемому выводу, так как этот код будет выводить l: 2 дважды, но это поднимает вопрос:

Что вы ожидаетевывод, когда у вас есть строка вроде abba?a:2, b:2?a:1, b:2, a:1?a: 2, b:2, a:2?Трудно помочь, когда ты задаешь такой неоднозначный вопрос.

0 голосов
/ 06 октября 2018
#include <stdio.h>
#include <string.h>

size_t ASCIIfreq[256];

void CountASCII(void *buff, size_t size)
{
    unsigned char *charsptr = buff;

    memset(ASCIIfreq, 0, sizeof(ASCIIfreq));
    while(size--)
    {
        ASCIIfreq[*charsptr++]++;
    }
}

void print(int printall)
{
    for(size_t index = 0; index < 256; index++)
    {
        if(ASCIIfreq[index] || printall)
        {
            printf("The %03zu (0x%02zx) ASCII - '%c' has occured in the buffer %zu time%c\n", 
                    index, index, (index > 32 && index < 127) ? (char)index : ' ',
                    ASCIIfreq[index], ASCIIfreq[index] == 1 ? ' ' : 's');
        }
    }
}

int main()
{
    char teststring[] = "i am trying to enter a word, and get how many times the letters were typed. Say my input is \"hello\" my output would be: h = 1, e = 1 l = 2 etc.I am very close to getting it right, but i have a small issue with this code";

    CountASCII(teststring, sizeof(teststring));
    print(0);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...