Подсчитайте, сколько раз каждая буква появляется в строке - PullRequest
0 голосов
/ 11 апреля 2020

Я играл с каким-то старым кодом, и я наткнулся на функцию, которую я сделал некоторое время go, которая вычисляет количество раз, когда каждая буква алфавита появляется в данной строке. В моей первоначальной функции я бы провел oop через строку 26 раз, посчитав, сколько раз каждая буква появляется, когда она повторяется. Однако я знал, что это действительно неэффективно, поэтому вместо этого я попытался сделать это:

int *frequency_table(char *string) { 
    int i;
    char c;
    int *freqCount = NULL;
    freqCount = mallocPtr(freqCount, 26, sizeof(int), "freqCount"); /* mallocs and checks for out of memory */

    for (i = 0; string[i] != '\0'; i++) {
        c = string[i];
        if (isalpha(c)) {
            isupper(c) ? freqCount[c - 65]++ : freqCount[c - 97]++;
        }
    }

    return (freqCount);
}

Приведенный выше код перебирает строку и проверяет каждый символ. Если символ представляет собой букву c в алфавитном порядке (az или AZ), то я увеличиваю счетчик частоты с указанным индексом c в массиве freqCount (где индекс 0 = a \ A, 1 = b \ B, ..., 25 = z \ Z).

Код выглядит нормально, но при печати массива я получаю следующий вывод:

Строка: "abcdefghijklmnopqrstuvwxyziii"

a/A     -1276558703
b/B     32754
c/C     -1276558703
d/D     32754
e/E     862570673
f/F     21987
g/G     862570673
h/H     21987
i/I     4
j/J     1
k/K     1
l/L     1
m/M     1
n/N     1
o/O     1
p/P     1
q/Q     1
r/R     1
s/S     1
t/T     1
u/U     1
v/V     1
w/W     1
x/X     1
y/Y     1
z/Z     1

Для справки, я печатаю массив следующим образом:

for (i = 0; i < 26; i++) {
     printf("%c/%c     %d\n", i + 97, i + 65, freqCount[i]);
}

Я проверил, чтобы убедиться, что указатель выделен правильно, я точно знаю, что не перезаписывал эту ячейку памяти. Может быть, я что-то упускаю, но я действительно не могу понять, почему он печатает значения мусорной памяти из \ Ah \ H.

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

Спасибо

Ответы [ 3 ]

2 голосов
/ 11 апреля 2020

В вашем коде есть 2 проблемы:

  • массив freqCount неинициализирован.
  • вам следует избегать передачи значений char в isalpha, поскольку это приведет к неопределенное поведение, если string содержит отрицательные значения char в системах, где char подписано по умолчанию.

Вместо троичного оператора или оператора if вы можете использовать toupper() преобразовать строчные буквы в прописные, и их удобнее читать 'A' или 'a' вместо их жестко заданных значений ASCII 65 и 97.

Вот исправленная версия:

int *frequency_table(const char *string) { 
    size_t i;

    /* allocate the array with malloc and check for out of memory */
    int *freqCount = mallocPtr(freqCount, 26, sizeof(int), "freqCount");

    for (i = 0; i < 26; i++) {
        freqCount[i] = 0;
    }
    for (i = 0; string[i] != '\0'; i++) {
        unsigned char c = string[i];
        if (isalpha(c)) {
            /* this code assumes ASCII, so 'Z'-'A' == 25 */
            freqCount[toupper(c) - 'A']++;
        }
    }
    return freqCount;
}
2 голосов
/ 11 апреля 2020
  • Как уже упоминалось, вы должны инициализировать значение 0
  • Также вы можете использовать приведенный ниже трюк для ускорения подсчета букв: если это буква, вы сбрасываете бит 32, который является разницей в битах. между прописными и строчными буквами, что даст вам правильный индекс.
  • Наконец, вы можете использовать короткий массив, если вы не ожидаете много букв.
#include <stdio.h>
#include <stdlib.h>

short *frequency_table(char *string){ 
    char c;
    short *freqCount;

    if (!(freqCount = (short*)calloc(26, sizeof(short))))
        return NULL;

    for(int i = 0; (c = string[i]) != '\0'; i++) {
        if(isalpha(c))
            freqCount[(c & ~32) - 'A']++;
    }

    return(freqCount);
}

Основной тест:

int main() {
    short *n = frequency_table("helloiHEllo6456gdrgd#%#^#$^#_thirde");

    for (char c = 'a'; c <= 'z'; c++)
         printf("%c: %d\n", c, n[c - 'a']);
    return 0;
}
0 голосов
/ 11 апреля 2020

следующий предложенный код:

  1. избегает malloc(), calloc(), et c
  2. сохраняет определение данных, et c внутри main() function
  3. выполняет желаемую функциональность
  4. безошибочно компилирует
  5. использует простые символьные литералы, а не числа 'magi c'
  6. ожидает символ ASCII установите

и теперь предложенный код:

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

#define MAX_ALPHA  26

void charCounter( char *,  int * );

int main( void )
{
    char string[] = "abcdefghijklmnopqrstuvwxyziii";    
    int  freqCount[ MAX_ALPHA ] = {0};

    charCounter(  string, freqCount );


    for( size_t i = 0; i < 26; i++)
    {
        printf("%c/%c     %d\n", (char)(i + 'A'), (char)(i + 'a'), freqCount[i]);
    }
}


void charCounter( char *string, int freqCount[] )
{
    for( size_t i=0; string[i]; i++ )
    {
        if( isalpha( string[i] ) )
        {
            freqCount[ toupper(string[i]) - 'A' ]++;
        }
    }
}

выполнение кода приводит к:

A/a     1
B/b     1
C/c     1
D/d     1
E/e     1
F/f     1
G/g     1
H/h     1
I/i     4
J/j     1
K/k     1
L/l     1
M/m     1
N/n     1
O/o     1
P/p     1
Q/q     1
R/r     1
S/s     1
T/t     1
U/u     1
V/v     1
W/w     1
X/x     1
Y/y     1
Z/z     1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...