1-11 开发你的第一个程序
前几节课介绍了大量术语和概念,这些知识将贯穿我们编写的每个程序。本节课我们将逐步演示如何将这些知识融入首个简单程序的开发过程。
乘以2
首先,我们编写一个程序:要求用户输入一个整数,等待用户输入后,告知该数字乘以2的结果。程序应输出如下内容(假设输入为4):
Enter an integer: 4
Double that number is: 8
如何解决这个问题?分步进行。
最佳实践
新手程序员常试图一次性编写完整程序,结果因大量错误而不知所措。更佳策略是逐段添加代码,确保编译通过并测试功能。确认运行正常后,再推进下一部分。
我们将在此采用该策略。在执行每个步骤时,请将程序代码手动输入(而非复制粘贴)到代码编辑器中,完成编译并运行测试。
首先创建一个新的控制台项目。
现在开始搭建基础框架。我们知道需要一个 main() 函数(所有 C++ 程序都必须包含此函数),若创建项目时 IDE 未自动生成空白函数,请手动创建:
int main()
{
return 0;
}
我们知道需要向控制台输出文本,并从用户的键盘获取文本,因此需要包含 iostream 以访问 std::cout 和 std::cin。
#include <iostream>
int main()
{
return 0;
}
现在让我们告知用户需要输入一个整数:
#include <iostream>
int main()
{
std::cout << "Enter an integer: ";
return 0;
}
此时,您的程序应输出以下结果:
Enter an integer:

然后终止。
接下来,我们将获取用户的输入。我们将使用 std::cin 和 operator>> 来获取用户的输入。但我们还需要定义一个变量来存储该输入,以便后续使用。
#include <iostream>
int main() // note: this program has an error somewhere
{
std::cout << "Enter an integer: ";
int num{ }; // define variable num as an integer variable
std::cin << num; // get integer value from user's keyboard
return 0;
}
该编译我们的修改了……然后……
哎呀!这是作者在 Visual Studio 2017 上遇到的问题:
1>------ Build started: Project: Double, Configuration: Release Win32 ------
1>Double.cpp
1>c:\vcprojects\double\double.cpp(8): error C2678: binary '<<': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)
1>c:\vcprojects\double\double.cpp: note: could be 'built-in C++ operator<<(bool, int)'
1>c:\vcprojects\double\double.cpp: note: while trying to match the argument list '(std::istream, int)'
1>Done building project "Double.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
在我的clang上面是, 后面请看作者Visual Studio 2017上如何分析解决的,这里仅记录clang面对这种错误是如何提示开发者的。
我们遇到了编译错误!
首先,由于程序在本次更新前能编译通过,而现在无法编译,错误必然出现在我们刚添加的代码中(第7行和第8行)。这大大缩小了需要排查的代码范围。第7行相当简单(只是变量定义),因此错误可能不在此处。剩下的第8行很可能是罪魁祸首。
其次,这条错误信息不太易读。但让我们拆解关键要素:编译器告知错误出现在第8行,这意味着实际错误可能就在第8行或其前一行,进一步印证了我们的判断。接着,编译器指出找不到左操作数类型为std::istream(即std::cin类型)的‘<<’运算符。换言之,<<运算符无法处理std::cin,因此错误必然出现在std::cin的使用方式或<<运算符的调用逻辑上。
现在看出问题了吗?若仍不确定,请花点时间仔细检查。
以下是修正后的程序代码:
#include <iostream>
int main()
{
std::cout << "Enter an integer: ";
int num{ };
std::cin >> num; // std::cin uses operator >>, not operator <<!
return 0;
}
现在程序可以编译了,我们可以测试它。程序会等待你输入一个数字,所以让我们输入4。输出应该如下所示:

快完成了!最后一步是将数字翻倍。
完成这最后一步后,我们的程序就能成功编译运行,输出预期结果。
实现这个目标至少有三种方法,让我们从最差到最佳依次探讨。
不理想的解决方案
#include <iostream>
// worst version
int main()
{
std::cout << "Enter an integer: ";
int num{ };
std::cin >> num;
num = num * 2; // double num's value, then assign that value back to num
std::cout << "Double that number is: " << num << '\n';
return 0;
}
在此方案中,我们使用表达式将 num 乘以 2,然后将该值重新赋值给 num。此后 num 将始终包含翻倍后的数值。
此方案存在缺陷的原因:
- 在赋值语句执行前,num 存储的是用户输入值;执行后则存储了不同值,这种行为容易造成混淆。
- 通过为输入变量赋予新值,我们覆盖了用户的输入。若后续想扩展程序对该输入值进行其他操作(例如将用户输入值乘以3),原始输入已然丢失。
基本可行的解决方案
#include <iostream>
// less-bad version
int main()
{
std::cout << "Enter an integer: ";
int num{ };
std::cin >> num;
int doublenum{ num * 2 }; // define a new variable and initialize it with num * 2
std::cout << "Double that number is: " << doublenum << '\n'; // then print the value of that variable here
return 0;
}
该方案的代码相当简洁易懂,同时解决了最差方案中出现的两个问题。
其主要缺点在于我们定义了一个新变量(增加了复杂度)来存储仅使用一次的值。我们还能做得更好。
首选方案
#include <iostream>
// preferred version
int main()
{
std::cout << "Enter an integer: ";
int num{ };
std::cin >> num;
std::cout << "Double that number is: " << num * 2 << '\n'; // use an expression to multiply num * 2 at the point where we are going to print it
return 0;
}


这是所有方案中最优的选择。当std::cout执行时,表达式num * 2将被求值,结果将是num值的两倍。该值将被打印出来。num本身的值不会被改变,因此我们可以在后续需要时再次使用它。
此版本是我们推荐的解决方案。
作者注:
编程的首要目标是让程序正常运行。无论代码写得多么精妙,无法运行的程序毫无价值。
但我钟爱这样一句箴言:“你必须先写出一个程序,才能明白当初该如何编写。
You have to write a program once to know how you should have written it the first time.” 这句话揭示了一个事实:最佳解决方案往往并非显而易见,而我们对问题的初始解答通常远未臻至完美。当我们专注于让程序运行时,将大量时间投入可能被弃用的代码显然不合时宜。于是我们选择捷径——跳过错误处理和注释等环节。我们在解决方案中穿插调试代码,以便诊断问题和查找错误。我们边做边学——原以为可行的方案最终行不通,不得不回溯尝试其他方法。
最终结果是:初始方案往往缺乏结构性、稳健性(抗错误能力)、可读性或简洁性。因此程序运行正常后,工作才真正开始(除非是临时/一次性程序)。下一步就是清理代码:移除(或注释掉)临时/调试代码、添加注释、完善错误处理、规范代码格式,并确保遵循最佳实践。即便如此,程序仍可能存在优化空间——或许存在可合并的冗余逻辑、可整合的多条语句、非必需的变量,以及千百种可简化的细节。新手程序员常过度关注性能优化,却忽视了可维护性优化。
这些教程中展示的解决方案,鲜少有首次就臻于完美。它们实则是持续打磨的成果,直至无可改进之处。而许多情况下,读者仍能提出诸多优化建议!
这一切想表达的是:若你的解决方案未能脱胎于脑海即臻完美,请勿沮丧。这很正常。编程中的完美是循序渐进的过程(需要反复打磨)。
作者注:
还有一件事:你可能在想,“C++有这么多规则和概念,我怎么记住这些东西?
C++ has so many rules and concepts. How do I remember all of this stuff?”简短回答:不必强求。C++的学习之道在于:一部分运用已掌握的知识,两部分查阅剩余内容的实现方法
You don’t. C++ is one part using what you know, and two parts looking up how to do the rest.。初次浏览本站时,请不必执着于记忆具体细节,更应着重理解语言的实现可能性。待你在编程实践中需要实现特定功能时,随时可重返本站(或参考文档)重温具体实现方式。
测验时间
问题 #1
修改上述“最佳解决方案”程序的输出,使其呈现如下效果(假设用户输入为4):
Enter an integer: 4
Double 4 is: 8
Triple 4 is: 12
我后面代码将采用编译器(clang+vim+lldb)呈现,如果没有写出来,则采用txt文件,并将我看完解决方案修正自己写的后补充在代码后面,以提醒自己后面温习此例子。
该编译器完整配置见vim 目录
- vim+cpp/c 是我自己配置的部分,会随时更改,打磨。
- neovim+cpp/c 是我采用claude写的,可以使用,作为一个备用项。
显示解决方案
#include <iostream>
int main()
{
std::cout << "Enter an integer: ";
int num{ };
std::cin >> num;
std::cout << "Double " << num << " is: " << num * 2 << '\n';
std::cout << "Triple " << num << " is: " << num * 3 << '\n';
return 0;
}




浙公网安备 33010602011771号