1.3 第一个程序(2)
如果IDE没有自动保持窗口的打开状态,并且你没有发现任何选项或者设置来保持窗口打开,你可以通过在程序结束的右花括号处,或者在调试器允许设置断点的最近语句上设置一个断点,来强制窗口打开。
知道如何运行程序后,还应该知道输入什么数字来高效地测试程序。你如何测试list0101以确保它能正确地执行?
好,去做这些。程序正确运行了吗?
这很简单,不是吗?你应该尝试几种不同的顺序。不输入,运行程序。用1个数字来试试。用2个已经排好序的数字和2个已经反序的数字试试。试试多个排好序的数字。试试随机顺序的多个数字。试试多个反序的数字。
在完成这些探索之前,还有一个练习。这次,源文件更加复杂,它由一个专业的且很爱显摆的程序员编写。即使有人指导,也不要尝试去读程序,更不要尝试去弄懂程序。首先,不要模仿这个程序的编程(www.cppentry.com)风格。这个练习不是为你,而是为你的工具写的。目的是来查看编译器是否能够正确地编译程序,库实现是否有标准库的必要部分。这个测试虽然不会让编译器觉得备受折磨,但是它确实涉及一些高级C++(www.cppentry.com)特性。
因此不必费劲儿地去读这些代码,仅从本书网站上下载文件list0102.cpp就可以了,然后试着用你的工具编译和链接它。(列出程序的代码仅仅为那些不方便上网的读者。)如果编译器不能正确地编译并运行代码清单1-2,则需要更换它(更换编译器,而不是程序)。如果不更换,你可能在早期的课程中能侥幸通过,但是本书后面将会写一些相当复杂的程序,所以需要一个能够胜任的编译器。(另外,代码清单1-2和代码清单1-1做的基本是同样的事情。)
代码清单1-2 测试编译器
- /// 把标准输入按照字母表顺序进行排序。
- /// 逐行读取文本,进行排序,并且把结果打印到标准输出。
- /// 如果命令行输入了一个文件名,则从该文件中
读入。否则,从标准输入读入。 - /// 所有的输入都保存在内存中,所以不要用超过
可用RAM大小的文件来测试这个程序。 - ///
- /// 比较采用命令行指定的区域设置,如果没有指
定,则使用默认区域设置。 -
- #include <algorithm>
- #include <cstdlib>
- #include <fstream>
- #include <iostream>
- #include <iterator>
- #include <locale>
- #include <ostream>
- #include <string>
- #include <vector>
-
- /// 将文本行从参数in读入到参数iter。
- /// @param in 输入流
- /// @param iter 输出迭代器
- template<class Ch, class Tr, class OutIter>
- void read(std::basic_istream<Ch,Tr>& in, OutIter iter)
- {
- std::basic_string<Ch,Tr> line;
- while (std::getline(in, line))
- {
- *iter = line;
- ++iter;
- }
- }
-
- /// 排序函数对象
- /// 参数化对象的字符类型,缓存区域设置,然后比较string。
- template<typename Ch>
- class sorter
- {
- public:
-
- /// 构造排序对象,缓存输入的区域名。
- /// @param locname, 要缓存的区域名。
- sorter(Ch const* locname) :
- loc_(std::locale(locname)),
- collate_(std::use_facet<std::collate<Ch> >(loc_))
- {}
- /// 使用全局区域设置,构造默认排序对象。
- sorter() :
- loc_(std::locale()),
- collate_(std::use_facet<std::collate<Ch> >(loc_))
- {}
- /// 小于,用于标准算法的比较
- /// @param lhs 左操作数
- /// @param rhs 右操作数
- /// 在指定的区域设置下,如果参数lhs小于参数rhs,
返回true,否则返回false - template<typename Tr>
- bool operator()(const std::basic_string<Ch,Tr>& lhs,
- const std::basic_string<Ch,Tr>& rhs)
- {
- return collate_.compare(lhs.data(),
lhs.data()+lhs.size(), - rhs.data(),
- rhs.data()+rhs.size()) < 0;
- }
- private:
- std::locale loc_;
///< cached locale - const std::collate<Ch>& collate_;
///< cached @c collate facet - };
-
- /// 通过推理模板参数,构造sorter对象。
- /// @param name 传给sorter构造函数的区域名
- /// @返回一个新的sorter对象
- template<typename Ch>
- sorter<Ch> make_sorter(Ch const * name)
- {
- return sorter<Ch>(name);
- }
-
- /// 主程序
- int main(int argc, char* argv[])
- try
- {
- // 当出现不可恢复的输入错误时,比如硬盘故障,抛出异常。
- std::cin.exceptions(std::ios_base::badbit);
-
- // 第一部分 把所有输入读入text,如果命
令行输入了一个文件名,读取那个文件, - // 否则读取标准输入。
- std::vector<std::string> text; ///< 把行文本保存在这儿
- if (argc < 2)
- read(std::cin, std::back_inserter(text));
- else
- {
- std::ifstream in(argv[1]);
- if (not in)
- {
- std::perror(argv[1]);
return EXIT_FAILURE; - }
- read(in, std::back_inserter(text));
- }
-
- // 第二部分 对text进行排序。第二个命令行参数
代表区域名,控制排序顺序。如果存在,则使用它; - // 如果不存在,则使用默认区域设置(从操作系统获取)。
- std::sort(text.begin(), text.end(),
make_sorter(argc >= 3 argv[2] : "" )); -
- // 第三部分 打印排序后的text
- std::copy(text.begin(), text.end(),
- std::ostream_iterator<std::string>(std::cout, "\n"));
- }
- catch (std::exception& ex)
- {
- std::cerr << "Caught exception: " << ex.what() << '\n';
- std::cerr << "Terminating program.\n";
- std::exit(EXIT_FAILURE);
- }
- catch (...)
- {
- std::cerr << "Caught unknown exception
type.\nTerminating program.\n"; - std::exit(EXIT_FAILURE);
- }
我知道你会看这些代码。尽管我已经事先警告过,你仍然情不自禁地阅读了它们,是不是?请记住,我故意用繁琐的方式编写这段程序仅仅是为了测试你的工具。当你读完本书时,就可以阅读并理解这个程序了。更重要的是,你可以更简单、更清晰地重写这段程序。学会跑前,先学会走。当你能够舒适地使用工具之后,就该开始学习C++(www.cppentry.com)了。下一步探索之旅将从阅读代码开始。