2016-01-17 118 views
2

我需要编写一个在文本文件中输出字母频率的程序。它读取其他文本文件的文本。问题在于大多数字母都被正确计数,但是少数字母会得到不正确的巨大频率。有人可以帮我解决这个问题吗?C程序不计算文本文件中的字母频率

谢谢!

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

#define NLETTERS 26 

int main(int argc, char *argv[]) 
{ 
    int c, i, accum = 0, letter[26]; 
    FILE *ifp, *ofp; 

    printf ("argument 0 = argv[0] = '%s'n", argv[0]); 
    printf ("argument 1 = argv[1] = '%s'n", argv[1]); 
    printf ("argument 2 = argv[2] = '%s'n", argv[2]); 

    ifp = fopen(argv[1], "r"); 
    ofp = fopen(argv[2], "w"); 

    if (ifp == NULL) 
     perror("No input file"); 

    if (ofp == NULL) 
     perror("Trouble making file"); 

    for (i = 0; i < NLETTERS; i++) { 
     letter[i] = 0; 

     for(; (c = getc(ifp)) != EOF; ++accum) { 
      if (c >='a' && c <= 'z') 
       ++letter[c - 'a']; 
     } 

     for (i = 0; i < NLETTERS; ++i) { 
      if (letter[i] != 0) { 
       fprintf(ofp, "%c:%5d",i + 'a', letter[i]); 
       putc('n', ofp); 
       fprintf(ofp, "%f%cnn", ((double)letter[i]/accum), 37); 
      } 
     } 
    } 
    return 0; 
} 

输入文件是:

Hi my name is niels and i a tying to write code. 

输出文件包含:

a: 3 
0.062500% 

b:32767 
682.645833% 

c:1606416521 
33467010.854167% 

d:32769 
682.687500% 

e: 7 
0.145833% 

g:1606416545 
33467011.354167% 

h:32767 
682.645833% 

i: 6 
0.125000% 

j: 1 
0.020833% 

l: 1 
0.020833% 

m:1606416578 
33467012.041667% 

n:32771 
682.729167% 

o: 2 
0.041667% 

r: 1 
0.020833% 

s: 2 
0.041667% 

t: 3 
0.062500% 

w: 1 
0.020833% 

y:1606416530 
33467011.041667% 

z:32767 
682.645833% 
+0

将字母向量中的所有元素初始化为0: int letter [26] = {0}; –

+0

了解如何使用调试器,并逐行浏览代码以查看所发生的情况。这个程序应该非常有启发性。 –

+0

此外,除数字“0” - “9”之外的其他字符不保证具有连续的表示。 '如果(c> ='a'&& c <='z')'不能保证代表所有小写字母的集合。参见C标准的[** 5.2.1字符集**](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)。虽然它*可能*在您的环境中工作,它不*有*。 “碰巧工作”和“必须按照标准工作”之间存在巨大的**差异。 –

回答

0

你永远不会初始化letters阵列。未初始化的变量将包含导致您正在观察的行为的未知值。这也是未定义的行为

尝试

int letters[26] = {0}; 
-1

如果您声明一个变量或数组,你不初始化,那么该变量将包含垃圾。在这种情况下,您需要将letters阵列清零。那就是:

int letters[26] = { 0 }; 

或(使用memset从string.h中)

int letters[26]; 
memset(letters, 0, 26); 
+0

为什么downvote? – stackptr

0

下面似乎是嵌套的另一内部for循环从0到25。嵌套和外循环是也都使用i。这意味着,外环将再也看不到我= 2作为内环会把它转移到25

for (i = 0; i < 26; ++i) { 
    if (letter[i] != 0) { 
     fprintf(ofp, "%c:%5d",i + 'a', letter[i]); 
     putc('n', ofp); 
     fprintf(ofp, "%f%cnn", ((double)letter[i]/accum), 37); 

    } 
} 

它看起来像你26次打印的字母给我。你能否将上面的代码移到第一个for循环之外?

我的改写:

/*for (i = 0; i < 26; i++) 
{ 
    letter[i] = 0; 
}*/ 
letter = {0}; 

while ((c= getc(ifp)) != EOF) { 

    if (c >='a' && c <= 'z') 
     ++letter[c-'a']; 
    accum++; 

} 

for (i = 0; i < 26; ++i) { 
    if (letter[i] != 0) { 
     fprintf(ofp, "%c:%5d",i + 'a', letter[i]); 
     putc('n', ofp); 
     fprintf(ofp, "%f%cnn", ((double)letter[i]/accum), 37); 

    } 
} 
1

问题是你在循环归零的阵列放错位置的主代码。
变化:

for (i = 0; i < 26; i++) { 
    letter[i] = 0; 

    while ((c= getc(ifp)) != EOF) { 

for (i = 0; i < 26; i++) { 
    letter[i] = 0; 
} 

while ((c= getc(ifp)) != EOF) { 

return 0之前删除大括号,你就大功告成了。