今日学习笔记:
(思路):

1. 定义变量与初始化计数数组

  • 定义字符变量 c 用于临时存储读取到的字符。
  • 定义数组 arr[123] 并初始化为 {0}:
    • 数组大小为 123,是因为小写字母 'a' 到 'z' 的 ASCII 值范围是 97~122,数组索引刚好可以覆盖这个范围(arr['a'] 对应索引 97,arr['z'] 对应索引 122)。
    • 初始化 {0} 确保所有元素初始值为 0,避免随机值干扰计数结果。

2. 循环读取输入并统计字母

  • 使用 while ((c = getchar()) != EOF) 循环读取所有输入字符,直到遇到 “文件结束符”(EOF,通常通过 Ctrl+Z 或 Ctrl+D 输入):
    • getchar() 每次读取一个字符(包括空格、回车、标点等)。
    • 仅当读取的字符 c 是小写字母(c >= 'a' && c <= 'z')时,才执行计数:arr[c]++(例如读到 'a' 时,arr[97] 的值加 1)。
    • 非小写字母字符会被直接跳过,不参与计数。

3. 输入结束后输出统计结果

  • 当输入结束(循环退出),使用 for (c = 'a'; c <= 'z'; c++) 遍历所有小写字母:
    • 对每个字母 c,若其计数 arr[c] > 0(即该字母出现过),则通过 printf("%c:%d\n", c, arr[c]) 输出 “字母:次数” 的格式(例如 a:3 表示 'a' 出现 3 次)。
    • 未出现过的字母(计数为 0)不输出,减少冗余信息。

一些迷惑的点:
计数操作:
arr 是一个数组,其索引对应字符的 ASCII 码(例如 arr[97] 对应 'a',arr[98] 对应 'b',以此类推)。
当 c 是小写字母时(比如 c = 'k'),arr[c] 等价于 arr['k'],而 'k' 的 ASCII 码是 107,所以实际操作的是 arr[107]。
++ 是自增运算符,arr[c]++ 表示将当前字母对应的计数加 1(例如第一次读到 'k' 时,arr['k'] 从 0 变成 1;第二次读到 'k' 时,从 1 变成 2,以此类推)。



(原来的代码中出现的问题):
char i,j; int arr[10000]; while (scanf("%c",&i)!=EOF) { if (i>='a' && i<='z') { arr[i]++; } for (j='a';j<='z';j++) { if (arr[j]>0) { printf("%c:%d\n",j,arr[j]); } } }
  1. 数组未初始化:arr[10000] 定义后未初始化,其元素初始值是随机的,导致首次统计结果不正确。
  2. 输入包含非字母字符:scanf("%c", &i) 会读取所有字符(包括空格、回车等),非小写字母字符会被跳过,但循环仍会执行后续的输出逻辑。
  3. 输出时机不当:每次读取一个字符后就输出所有字母的计数,会导致输出过于频繁(例如输入一个字母就输出 26 行可能的结果)。
  4. 数组下标范围:小写字母 'a'-'z' 的 ASCII 值是 97-122,arr 数组只需索引到 122 即可,定义为 arr[123] 更合理(避免空间浪费)。

#include<stdio.h>
int main()
{
    char i,j;
    int arr[123]={0};
    while ((i=getchar())!=EOF) {
                //判断当前读取的字符是否为小写字母,如果是,则对应字母的计数加 1         if (i>='a' && i<='z') {
            arr[i]++;
        }
    }    
        for (j='a';j<='z';j++) {
            if (arr[j]>0) {
                printf("%c:%d\n",j,arr[j]);
            }
        }
    return 0;
}