簡體   English   中英

如何查找C中的字符數組中出現的次數?

[英]How to find number of occurrences in array of chars in C?

我試圖輸入一個單詞,並輸入多少次字母。

說我的輸入是“你好”

我的輸出將是:h = 1,e = 1 l = 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的輸出?

正如Ry-此評論中建議的那樣,您可以迭代回原始字符串,並使用char作為頻率表的索引。 類似於以下內容:

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 當您問這樣一個模棱兩可的問題時,很難提供幫助。

#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;
}

目前尚不清楚您的意思是:

我怎樣才能改變它,使我得到的只是輸入的chararray的輸出?

因為無論如何這就是您要做的事情:向函數輸入一個char數組; 用字母順序更新數字; 然后按原樣輸出。

因此,我猜測您要按照首次遇到每個字符的順序輸出計數?


這將需要更多的工作。 您可以保留另一個數組,以跟蹤在find_frequency遇到每個字符的順序。 但是,然后那個簡單的clean函數開始做太多事情了。

因此,請考慮調整輸出方式:

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++;
    }
}

如果您嘗試獲取有序計數而不是按字母順序計數,則只需要將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 (offset)從以下字符開始搜索,直到在字符串中找不到其他匹配項為止。如果需要,可以對緩沖區中的字符使用附加循環。)

使用/輸出示例

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

但是,這確實會重新計數每個字符,如果該字符重復,則會再次計數(例如,每個'l' l: 2, l: 2 )。 現在不清楚:

“我的輸出將是: 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'僅報告一次,且計數正確。

注意,在每個示例中,您都應該進行額外的驗證,以確保整個輸入適合您的緩沖區,等等。... count (和chars )數組的大小設置為128以覆蓋整個ASCII值范圍。 不要忽略緩沖區大小。 如果您明確將輸入限制為大寫或小寫-則可以將計數大小限制為26 ,否則,您需要考慮將要遇到的其他字符和標點符號。 這同樣適用於您的輸入緩沖區。 如果您預計最大輸入將為500個字符,則將其加倍(通常為下一個可用的2的冪,對2的冪沒有實際要求,但您很可能會這樣看)。

最重要的是,我寧願將10,000個字符過長,也不要將一個字符過短...導致Undefined Behavior

最后,正如我在評論中提到的,從來沒有,永遠也永遠不會使用gets 它是如此不安全,已從C11中的C標准庫中刪除。 請改用fgets或POSIX getline

仔細檢查一下,如果您還有其他問題,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM