我的一个项目遇到了一个小问题。我应该编写一个 c 程序来计算输入/文件中存在的每个字符。 (它应该是一个基本程序。)约束 - 我不能使用 math.h 库来生成日志函数并获得以下格式的输出:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
程序应该计算标准输入流中每个字母(不区分大小写)的出现次数并显示直方图。
如您所见,输出是垂直格式化的,每行打印字符位置的以 10 为底的数字。 现在,这可能看起来很愚蠢,但到目前为止我所拥有的是:
#include <stdio.h>
#include <ctype.h>
/*
int logBase10 (int num) {
method to calculate the log base 10 of num
}
*/
int main (int argc, char * argv[]) {
char alpha;
int count = 0;
int ascii[128] = {0};
while ( (alpha = getchar()) != EOF) {
count++;
ascii[(int)alpha]++;
alpha = getchar();
}
printf("Char \t Count \n");
printf("------------------------\n");
for (int i = 0; i < 127; i++) {
if(ascii[i] > 0) {
printf("%c \t %d \n", i, ascii[i]);
}
}
}
产生这样的输出:
Char Count
------------------------
5
93
, 6
- 2
. 3
; 2
C 2
I 6
N 1
T 1
W 2
a 26
b 5
c 8
d 13
e 55
f 11
g 7
h 28
i 32
k 3
l 26
m 17
n 31
o 27
p 12
q 1
r 26
s 22
t 42
u 11
v 8
w 8
y 13
z 1
首先,我的程序正在打印不需要的 ascii 字符(、; - 等),我正在努力将打印功能更改为更垂直,但我根本无法弄清楚日志方法。我知道 log(10) 是 1,因为 10^1 是 1,但我无法弄清楚如何使用它来创建方法本身。另外,对于额外的字符,我尝试使用:
if(ascii[i] > 65 || ascii[i] < 90 || ascii[i] >= 97 || ascii[i] <= 122 ) {
printf("%c \t %d \n", i, ascii[i]);
}
没有用。尝试这样做会产生更多乱码。
感谢任何帮助/反馈。
- 灵魂
最佳答案
评论者已经指出了您的代码存在的问题。这是一个只计算字母并打印垂直标签的版本。它不需要 <ctype.h>
或 <math.h>
.
每个字符都有一个字母索引,对于大写和小写字母,该索引是 0 到 25 之间的数字;如果字符不是字母,则为 -1。这将数组大小减少到 26。
您可以通过复杂的计算找出每个数字,但最简单的方法是将数字打印成字符串。
snprintf
为你做这件事。您可以将数字与字段宽度右对齐。典型int
的最大值大约是20亿,有10位数字。你应该考虑到这一点,即使你必须通过整个 Moby-Dick 加上圣经才能得到那么多计数。您可以先假设宽度为十位,然后检查最大计数是否有十位,即是否为 1,000,000,000 或更高,以测试是否应该开始打印。然后在每次迭代中将该限制除以 10。
代码如下:
#include <stdio.h>
// return letter index or -1 for non-letter
int letter(int c)
{
if ('a' <= c && c <= 'z') return c - 'a';
if ('A' <= c && c <= 'Z') return c - 'A';
return -1;
}
int main(int argc, char * argv[])
{
int count[26] = {0}; // letter counts
char label[26][12]; // buffer for printing numbers
int limit = 1000000000; // smallest 10-digit number
int max = 0;
int i, j;
// read and count letters
while (1) {
int c = getchar();
if (c == EOF) break;
c = letter(c);
if (c >= 0) count[c]++;
}
// write auxiliary labels
for (i = 0; i < 26; i++) {
snprintf(label[i], sizeof(label[i]), "%10d", count[i]);
if (count[i] > max) max = count[i];
}
// print vertical labels
for (j = 0; j < 10; j++) {
if (max >= limit) {
for (i = 0; i < 26; i++) {
putchar(' ');
putchar(label[i][j]);
}
putchar('\n');
}
limit /= 10;
}
// print horizontal rule
for (i = 0; i < 26; i++) {
putchar('-');
putchar('-');
}
putchar('-');
putchar('\n');
// print letters
for (i = 0; i < 26; i++) {
putchar(' ');
putchar('A' + i);
}
putchar('\n');
return 0;
}
在你的例子中,它产生:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
-----------------------------------------------------
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
关于使用日志函数(没有 math.h)和数组计算 C 中的字母表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35415730/