字符串指针数组中字符的频率

4
我正在处理一个涉及IT技术的练习,需要完成以下任务:
  1. 从用户那里读取20个单词;
  2. 根据单词长度使用内存分配将它们保存到指针数组中;
  3. 计算字母频率;
  4. 使用直方图将其输出。
我已经成功完成了步骤1和2。问题出在第3步,我尝试打印测试信息来确定是否有计算错误,结果发现字符数没有被统计进去。请帮我解决这个问题。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N         20
#define MAX_SIZE  200

int main() {
    char *words[N];
    int i, c = 0, length;
    char *temp;
    int freq[26] = { 0 };

    temp = (char *)malloc(MAX_SIZE * sizeof(char));

    for (i = 0; i < N; i++) {
        printf("Give a word:");
        gets(temp);
        length = strlen(temp);
        *(words + i) = (char *)malloc((length + 1) * sizeof(char));
        strcpy(*(words + i), temp);
        printf("%s\n", *(words + i));
    }
    free(temp);

    while (*words[c] != '\0' && c < 20) {
        if ((*words[c] >= 'a' && *words[c] <= 'z') || (*words[c] >= 'A' &&  *words[c] <= 'Z')) {                    
            freq[*words[c] - 'a']++;
            words[c]++;
        }
        c++;
    }

    for (i = 0; i < 26; i++) {
        printf("%c occurs %d times in the entered string.\n", i + 'a', freq[c]);
    }
    return 0;
}

1
为你的代码添加缩进将有助于他人阅读和理解你的问题所在。 - BlueMoon93
3
在增加频率时,您不能区分大写字母和小写字母。 'b'-'a'与'B'-'a'不同,会导致问题。 - BlueMoon93
1
知道 *(words + i) 等同于 words[i] 吗?虽然两者可以互换使用,但后者通常更受欢迎,因为它真正展示了你正在做什么(索引一个数组)。此外,根据C规范,sizeof(char) 总是返回值 1 - Some programmer dude
@BlueMoon93,你是正确的,我会处理的。你能详细解释一下你的第二条评论吗? - Georgez
我还需要指出我是初学者,所以不要太苛刻。 - Georgez
显示剩余2条评论
3个回答

2

你的代码存在几个问题:

  • 你修改了words数组中的指针,而不是通过索引进行迭代。
  • 你检查大写字母,但在这种情况下访问超出其边界的偏移量freq[*words[c]-'a']
  • 最后一个循环中有一个拼写错误:应该是freq[i]而不是freq[c]
  • 你不需要分配数组temp
  • 你不能使用已从标准中删除的getsgets无法检查缓冲区溢出,任何恶意输入都可能会产生不可预知的后果。
  • 你应该检查malloc失败

这是一个纠正后的版本:

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

#define N         20
#define MAX_SIZE  200

int main(void) {
    char *words[N];
    int n, i, j, c, length;
    char temp[MAX_SIZE];
    int freq[26] = { 0 };

    for (n = 0; n < N; n++) {
        printf("Give a word:");
        if (!fgets(temp, sizeof temp, stdin))
            break;
        temp[strcspn(temp, "\n")] = '\0';  /* strip the \n if present */
        length = strlen(temp);
        words[n] = malloc(length + 1);
        if (words[n] == NULL) {
            printf("cannot allocate memory\n");
            exit(EXIT_FAILURE);
        }
        strcpy(words[n], temp);
        printf("%s\n", words[n]);
    }

    for (i = 0; i < n; i++) {
        for (j = 0; (c = words[i][j]) != '\0'; j++) {
            if (c >= 'a' && c <= 'z')
                freq[c - 'a']++;
            else
            if (c >= 'A' && c <= 'Z')
                freq[c - 'A']++;
        }
    }

    for (i = 0; i < 26; i++) {
        if (freq[i] > 0)
            printf("%c occurs %d times in the entered strings.\n", i + 'a', freq[c]);
    }
    return 0;
}

哦,我的天啊!你是正确的。它解决了部分问题,例如如果我放置; - Georgez
如果我输入“ab”,它只会计算“a”,而不是“b”。 - Georgez

1
你似乎只检查每个单词的第一个字母,然后继续下一个单词。显然你需要两个循环来解决这个问题。
或者像这样:
while (c<N) {
    if(( *words[c]>='a' && *words[c]<='z') || (*words[c]>='A' &&  *words[c]  <='Z')) {                    

        freq[*words[c]-'a']++;
    }
    words[c]++;
    if(*words[c] == '\0')
        c++;
}

但我认为你最终会得到一个字符串结尾的数组,虽然似乎没有关系,但仍然很奇怪。

1
我找到了解决方案,我想...在你上面的代码中,如果你将"!="改为"==",它就会起作用...因为当没有更多字符可读时,它将转到下一个单词。 - Georgez
哦,抱歉提供了一个有漏洞的解决方案^^。很高兴它有所帮助。 - rustypaper
没问题,非常感谢。 - Georgez

0

首先要区分大小写。这可能不是完整的解决方案,但它是一个开始。

    if (*words[c]>='a' && *words[c]<='z'){                       
        freq[*words[c]-'a']++;
        words[c]++;
    }
    else if (*words[c]>='A' &&  *words[c]  <='Z'){                       
        freq[*words[c]-'A']++;
        words[c]++;
    }

明白了,我会立即处理。 - Georgez
1
使用 #include <ctype.h> 并使用 islower(),isupper() 不是更简单吗? - Claudio Cortese
@BlueMoon93 我做到了,现在有时候会显示所有字母已经出现1次,有时候则全部都是0。 - Georgez
@user2719403 请查看chqrlie的回答。他的回答修复了那个bug。 - BlueMoon93
@BlueMoon93 部分修复了问题。 - Georgez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接