我正在处理一个项目,其中我有两个主要文件。本质上,程序读入一个文本文件,该文件定义了一个具有键值映射的字典。每个键都有一个唯一的值,文件的格式如下,其中每个键值对都在自己的行上:
ipsum i%#@!
fubar fubar
IpSum XXXXX24
Ipsum YYYYY211
然后程序从stdin读入输入,如果其中任何一个"字"匹配字典文件中的键,它们被替换为值。大小写有个小问题——这是"match priority">
"的顺序。- 确切的单词在替换集
- 在替换集 中,除第一个字符外所有字符都转换为小写的单词
- 完全转换为小写的单词在替换集 中
意思是如果这个词在字典中,它将被替换,但如果没有,则检查下一个可能性(2),依此类推…
我的程序通过了我们提供的基本案例,但随后终端显示输出与引用二进制文件不同
我打开了两个文件(不是c文件,而是二进制文件),其中一个非常长,有大量的数字,而另一个只有一行随机字符。所以这并没有什么帮助。我也审查了我的代码,并做了一些小测试,但它似乎还好吗?一个朋友建议我确保我在processInput()中考虑空操作符,我已经是(或者至少我认为是这样,如果我错了,请纠正我)。我还将getchar()转换为int以正确检查EOF,并为char数组分配了额外的空间。我也试过vimdiff
,更困惑了。我希望有一些帮助调试这个,请!我一整天都在做这件事,我很困惑。
processInput()
函数存在多个问题:
-
当字节读取为0时循环不应该停止,你应该处理完整的输入:
while ((ch = getchar()) != EOF)
-
EOF
的测试实际上应该以不同的方式完成,以便文件的最后一个单词得到处理的机会,如果它恰好发生在文件的末尾。 -
isalnum((char)ch)
中的强制转换是不正确的:您应该将ch
直接传递给isalnum
。将字节值转换为char
实际上是适得其反的,因为它会将超过CHAR_MAX
的字节值转换为负值,而isalnum()
具有未定义的行为。 -
测试
if(ind >= cap)
太松散:如果word
包含cap
字符,将空终止符设置在word[ind]
将写入超出数组的末尾。将测试更改为if (cap - ind < 2)
,以允许在任何时候都有一个字节和一个空终止符。 -
您应该检查单词中至少有一个字符,以避免使用空字符串调用
checkData()
。 -
char key[ind + 1];
是无用的:你可以把word
传递给checkData()
。 -
checkData(key, ind)
是不正确的:你应该为大小写转换传递缓冲区的大小,它至少是ind + 1
以允许空终止符。 -
putchar((char)ch);
中的强制转换是无用的和令人困惑的。
在代码的其余部分有一些小问题,但没有一个应该引起问题。
首先使用以下命令测试标记器:
$ ./a.out <badhash2.c >zooi
$ diff badhash2.c zooi
$
它也适用于二进制文件吗?:
$ ./a.out <./a.out > zooibin
$ diff ./a.out zooibin
$
是的,它有!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
void processInput(void);
int main(int argc, char **argv) {
processInput();
return 0;
}
void processInput() {
int ch;
char *word;
int len = 0;
int cap = 60;
word = malloc(cap);
while(1) {
ch = getchar(); // (1)
if( ch != EOF && isalnum(ch)) { // (2)
if(len+1 >= cap) { // (3)
cap += cap/2;
word = realloc(word, cap);
}
word[len++] = ch;
} else {
if (len) { // (4)
#if 0
char key[len + 1];
memcpy(key, word, len); key[len] = 0;
checkData(key, len);
#else
word[len] = 0;
fputs(word, stdout);
#endif
len = 0;
}
if (ch == EOF) break; // (5)
putchar(ch);
}
}
free(word);
}
我只修复了你的标记器,遗漏了哈希表和搜索&替代的东西。它现在应该生成输入的逐字副本。(这是愚蠢的,但很适合测试)
如果你想允许二进制输入,你不能使用
中仍然可能有一个最终的单词。while((ch = getchar()) ...)
:输入中的NUL会导致循环结束。您必须推迟EOF的测试,因为在您的缓冲区...&& ch != EOF)
把EOF当作空格:它可以是一个单词的结尾
您也必须为NUL(' ')保留空间。
if (len==0)将没有单词,所以不需要查找。
我们把EOF当作一个空格,但是我们不想把它写到输出中。是时候跳出这个循环了