先放代码,然后详解:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int main(void)
{
char *str = NULL;
int size = 100;
str = (char*)malloc(size*sizeof(char*));
fgets(str,size,stdin);
int cnt[26] = {0};
for (int i = 0;i < strlen(str);i ++)
{
cnt[str[i] - 'a'] ++;
}
for (int i = 0;i < 26;i ++)
{
if (cnt[i] != 0)
{
printf("%c:%d\n",'a' + i,cnt[i]);
}
}
free(str);
return 0;
}
接下来我们分段讲述.
- 输入字符串?
如图所示,输入的字符串以指针数组形式存在,我们使用了malloc函数来对它进行动态分配内存.
char *str = NULL;//先对该指针进行初始化;
int size = 100;
str = (char*)malloc(size*sizeof(char*));//使用malloc函数进行动态分配内存;
fgets(str,size,stdin);//这里使用fgets函数,使数据的输入更加安全,能够防止数据溢出。
其中的fgets函数比gets函数更加安全,str指被输入的字符串,size指能输入进去的大小,stdin表示标准输入.
当然对于某些情况来说,这是脱裤子放屁的写法,笔者写这个纯纯是为了练习malloc函数(什么)。在OJ里,我们可以这么写:
char str[100];
scanf("%99s",str);//为什么要加个%99?这意味着防止缓冲区溢出。程序只允许输入99个字符。
//最后别忘了清除缓冲区。这是一个好习惯。
int c;
while ((c = getchar() != '\n') && c != '\n');
但是读者们可以试着运行一下,其运行时间和效率显然是比图上所述要长的.
- 如何计数?
这里计数的核心原理是:ASCII码.
int cnt[26] = {0};
for (int i = 0;i < strlen(str);i ++)
{
cnt[str[i] - 'a'] ++;
}
定义一个有26个下标的数组;将char型的字符转换为可以计数的int型;用相减的方法计算出该字符与'a'的距离,并将其存放到相应的数组下标内。
如下图对照表,例如'a'与'a'之间的距离是0,则存放到cnt[0]内;'d'与'a'之间的距离是3,因此存放到cnt[3]内。这样数组下标的0~25可分别表示为从'a'~'z',通过遍历str,有几个相应的字符,就在相应字符的内存中加1.
二进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 |
---|---|---|---|---|
01100001 | 97 | 61 | a | |
01100010 | 98 | 62 | b | |
01100011 | 99 | 63 | c | |
01100100 | 100 | 64 | d | |
01100101 | 101 | 65 | e | |
01100110 | 102 | 66 | f | |
01100111 | 103 | 67 | g | |
01101000 | 104 | 68 | h | |
01101001 | 105 | 69 | i | |
01101010 | 106 | 6A | j | |
01101011 | 107 | 6B | k | |
01101100 | 108 | 6C | l | |
01101101 | 109 | 6D | m | |
01101110 | 110 | 6E | n | |
01101111 | 111 | 6F | o | |
01110000 | 112 | 70 | p | |
01110001 | 113 | 71 | q | |
01110010 | 114 | 72 | r | |
01110011 | 115 | 73 | s | |
01110100 | 116 | 74 | t | |
01110101 | 117 | 75 | u | |
01110110 | 118 | 76 | v | |
01110111 | 119 | 77 | w | |
01111000 | 120 | 78 | x | |
01111001 | 121 | 79 | y | |
01111010 | 122 | 7A | z |
- 最后遍历输出
for (int i = 0;i < 26;i ++)
{
if (cnt[i] != 0)
{
printf("%c:%d\n",'a' + i,cnt[i]);
}
}
if的意思为,如果某下标中的数据存放的不是0,那么该下标对应的字符绝对出现过,便将其打印出来.
- 如果也统计大写?
至此,原理已经搞懂,大写怎么计数也不是一件难事。只需找到大写相应的ACSII码值(对对对,就是比小写字母小32位的那个),在计数时加一个判断条件
//计数小写be like:
if (str[i] >= 'a' &&str[i] <= 'z')
//计数大写be like:
if (str[i] >= 'A' &&str[i] <= 'Z')
即可.