C++测试题简评一下
C++测试题简评一下
前天我发了一道测试题
http://bbs.pediy.com/showthread.php?t=126118
收到了三份答案,都写得很差
* 当我们说要解析一下文本文件时,通常这个文件是不大的,你第一感觉就应该是把整个文件都读到内存,然后用 char c = *p++ 之类代码就可以简单处理了。或者用 CreateFileMapping 转化成可以直接操作的内存。而这几份答案都是直接文件操作,满篇的 fread fgetc fseek ftell 看起来很乱。
* 要求中,有一个函数IsLineEnd,要得到当前是不是在一个行尾。既然是检查什么东西是不是,那么这个函数一定应该是const的,不能改变任何状态。你用fgetc得到下一个字母,发现不是行尾,这取出来的一个字母怎么还回去?即使能还回去这代码也是不好的。全读出来后用 *p++ 就不存在这个问题了。
* 要求中,多次提到要跳过空白,你应该有一个函数SkipWhiteSpace,而不要满篇代码,到处都在比较空格,很乱
* 重点戏 GetOneWord,因为需要考虑三种情况
* 跳过开头的空白
* 遇非单词字符要停下来,非单词字符有多种可能
* 以引号开头要特殊处理
于是初学者就乱了方寸,不知道怎么写了,搞得代码极乱。
这里为什么我不提 \ 的行结束这种情况呢?其实可以把 \ 当作是一个空格,是个单词结束符就可以了。这个符号仅仅是 IsLineEnd 和 SkipLineEnd 要考虑的,并没有增加 GetOneWord 的复杂度。
优秀的程序员总是能把复杂的事情条理化。既然GetOneWord需要跳过开头的空白,那么在函数开始调用一下 SkipWhiteSpace 就解决了。这就少了一种情况。
以引号开头需要特殊处理,那么接下来判断一下第一个字符,如果是引号,就转到另一段例程,找到下一个引号就可以return 了
总之,函数的流程应该是这样的:
if (IsLineEnd) return;
SkipWhiteSpace();
if (*p = '\"')
{
...;
return;
}
while (IsWordChar(*p))
{
...;
p++;
}
整个流程清晰明了。如果
* 你不是用*p而是用fread或fgetc来得到下一个字母,
* 你没有用 SkipWhiteSpace 来跳过前头空白,而是到处比较,
* 你用一个flag来表示是在单词中还是单词前,还是单词后,
* 你没有把引号开头的情况独立处理,而是用一个flag来区分,
那么,每一种情况都会让这个简单的函数变得复杂。如果这些错误你都犯了,这个函数会复杂得不堪入目,一个小时也看不懂,而且极可能有BUG。
GetOneWord的原型定义,可能是
void GetOneWord(OUT stl:string & s);
bool GetOneWord(OUT char s[]);
CString GetOneWord();
等等。如果你写成 char * GetOneWord() 那是不好的。
当你拿到一个模块工作任务时,你应该安静地完成。你不能因为文件打开失败就
cout << "file open error";
你怎么知道我有cout ? 你怎么知道我是一个命令行console的工程而不是GUI甚至驱动?当你要失败时,你只能return false,或者抛出异常。
实际应用中,我们还考虑了以下这些情况,
* 单词中出现\
* 单词中出现引号
* 引号中出现\换行
* 引号不配对
* 自动支持多种格式的文本文件unicode,utf-8,ansi
