2.1 进入C++
本节将引导你编写第一个C++程序,并介绍一些基本概念。
2.1.1 main()函数
每个C++程序都必须包含一个名为 main 的函数。操作系统通过调用 main 函数来启动C++程序。main 函数是程序的入口点。
基本结构:
1 | int main() |
-
int main(): 这是main函数的函数头。int表示main函数执行完毕后将返回一个整数值给操作系统。括号()表示这是一个函数。 -
{ ... }: 花括号标记了函数体的开始和结束。函数体包含了程序要执行的指令(语句)。 -
return 0;: 这条语句表示main函数执行完毕。返回值0通常表示程序成功执行。非零返回值通常表示程序遇到了错误。
示例:
一个最简单的C++程序:
1 | int main() |
这个程序什么也不做,但它是一个完整的、可以编译和运行的C++程序。
2.1.2 C++注释
注释是程序中用于解释代码的部分,它们会被编译器忽略,不会影响程序的执行。注释可以提高代码的可读性。
C++支持两种类型的注释:
- 单行注释: 以
//开始,直到该行结束。 - 多行注释: 以
/*开始,以*/结束,可以跨越多行。
用法与示例:
1 |
|
2.1.3 C++预处理器和iostream文件
在编译C++程序之前,预处理器会首先处理源代码。预处理器指令以 # 符号开头。
#include 是一个常见的预处理器指令,它告诉预处理器将另一个文件的内容包含到当前文件中。
iostream 文件是C++标准库的一部分,包含了进行输入(input)和输出(output)操作所需的信息。例如,要使用 cout 进行输出,就需要包含 iostream 文件。
用法与示例:
1 |
|
-
#include <iostream>: 这条指令告诉预处理器查找名为iostream的标准头文件,并将其内容插入到该指令所在的位置。
2.1.4 头文件名
头文件(Header Files)包含了函数、类、对象等的声明,使得我们可以在程序中使用它们。C++标准库提供了许多头文件。
- 标准库头文件: 通常使用尖括号
<>括起来,例如<iostream>,<cmath>,<string>。编译器会在标准库的包含路径中查找这些文件。 - 用户自定义头文件: 通常使用双引号
""括起来,例如"myheader.h"。编译器会首先在当前源文件所在的目录查找,然后在标准包含路径中查找。
C++98之前的头文件: 以前的C++头文件可能带有 .h 后缀(如 <iostream.h>)。现代C++(C++98及以后)推荐使用不带 .h 后缀的标准头文件(如 <iostream>),这些头文件的内容位于 std 命名空间中。
示例:
1 |
|
2.1.5 名称空间
名称空间(Namespace)是C++中避免命名冲突的一种机制。不同的名称空间可以包含同名的函数、类或变量。
标准C++库中的所有内容(如 cout, cin, endl, string 等)都定义在名为 std 的名称空间中。
要使用 std 名称空间中的元素,有几种方法:
- 使用作用域解析运算符
::: 在每个元素前加上std::。1
std::cout << "Hello!" << std::endl;
- 使用
using声明: 将特定的名称引入当前作用域。1
2
3
4
5
6
7
8
9
10
using std::cout; // 只引入 cout
using std::endl; // 只引入 endl
int main() {
cout << "Hello!" << endl; // 不需要 std:: 前缀
// std::cin >> variable; // 如果要用 cin,仍需 std:: 或 using std::cin;
return 0;
} - 使用
using编译指令: 将整个名称空间的所有名称引入当前作用域。(不推荐在头文件中或全局作用域中使用,可能导致命名冲突)1
2
3
4
5
6
7
8
9
10
using namespace std; // 引入 std 中的所有名称
int main() {
cout << "Hello!" << endl; // 不需要 std:: 前缀
int x;
cin >> x; // cin 也不需要 std:: 前缀
return 0;
}
推荐做法:
- 在
.cpp文件的函数内部或较小作用域内,可以使用using声明或using namespace std;。 - 在头文件 (
.h) 中,绝对不要使用using namespace std;,应始终使用std::前缀。 - 在简单的示例或小型项目中,
using namespace std;可以简化代码,但在大型项目中,坚持使用std::::或using声明是更安全的做法。
2.1.6 使用cout进行C++输出
cout 是 iostream 库中预定义的一个对象,代表标准输出流,通常连接到控制台(屏幕)。
<< 运算符(插入运算符)用于将数据发送给 cout 对象,使其显示在屏幕上。
用法与示例:
1 |
|
-
std::endl: 是一个特殊的控制符(manipulator),它会输出一个换行符,并刷新输出缓冲区(确保内容立即显示)。 -
\n: 是一个转义字符,代表换行符。它只输出换行,通常不保证立即刷新缓冲区。在多数情况下,\n比std::endl效率稍高。
2.1.7 C++源代码的格式化
C++语言对代码格式(如空格、缩进、换行)的要求相对宽松,但良好的格式化对于代码的可读性和可维护性至关重要。
基本规则和建议:
- 语句分隔: C++使用分号
;来结束大多数语句。 - 空格:
- 通常在运算符(
=,+,-,*,/,<<,>>,==等)两边添加空格。 - 在逗号
,后面添加空格。 - 在函数名和后面的括号
()之间通常不加空格。
- 通常在运算符(
- 缩进: 使用一致的缩进(通常是4个空格或一个制表符)来表示代码块(如
main函数体、循环体、条件语句体)。这极大地提高了代码结构的可读性。 - 换行:
- 通常每行只写一条语句。
- 可以在合适的地方(如运算符之后、逗号之后)将长语句分成多行。
- 花括号
{}: 对于代码块(如函数体、if语句块等),花括号的放置风格有多种(如 K&R 风格、Allman 风格),选择一种并保持一致即可。
示例 (良好格式):
1 |
|
示例 (不良格式,但语法正确):
1 |
|
虽然第二个示例也能编译运行,但极难阅读和理解。遵循一致的、清晰的格式化风格是专业编程的重要组成部分。
2.2 C++语句
C++程序由一系列语句组成。语句是C++程序的基本执行单元,通常以分号 ; 结尾。本节将介绍两种基本的语句:声明语句和赋值语句,并进一步探讨 cout 的用法。
2.2.1 声明语句和变量
声明语句 (Declaration Statement) 用于向编译器声明程序中将要使用的变量 (Variable) 的名称和类型。
变量 是计算机内存中用于存储数据的一块区域,并且有一个名字(标识符)。通过变量名,我们可以访问和修改存储在内存中的数据。在使用变量之前,必须先声明它。
声明变量的语法:
1 | typeName variableName; |
-
typeName: 指定变量要存储的数据类型(例如int表示整数,double表示浮点数)。 -
variableName: 你为变量选择的名称(标识符)。
用法与示例:
1 |
|
- 声明 (Declaration): 告诉编译器变量的名称和类型。
- 定义 (Definition): 声明通常也是定义,因为它会为变量分配内存空间。
- 初始化 (Initialization): 在声明变量的同时给它赋一个初始值。这是一个好习惯,可以避免使用未定义的值。
2.2.2 赋值语句
赋值语句 (Assignment Statement) 用于将一个值赋给一个变量。它使用赋值运算符 =。
语法:
1 | variableName = value; |
-
variableName: 要接收值的变量的名称(必须是已声明的变量)。 -
value: 要赋给变量的值。这可以是一个字面常量(如25)、另一个变量、或一个表达式的结果。
重要概念:
- 赋值操作是将右侧的值复制到左侧的变量中。
- 左侧必须是一个可修改的**左值 (lvalue)**,通常就是一个变量名。
- 右侧可以是一个**右值 (rvalue)**,即一个可以产生值的表达式。
用法与示例:
1 |
|
2.2.3 cout的新花样
我们在 2.1.6 节已经学习了如何使用 cout 输出字符串和使用 endl 换行。cout 的一个强大之处在于它的“智能”,它可以识别并正确显示多种不同类型的数据。
cout 对象与插入运算符 << 结合使用,可以自动处理 C++ 的内置数据类型,如整数 (int)、浮点数 (double, float)、字符 (char) 以及 C 风格字符串和 std::string 对象。
用法与示例:
1 |
|
cout 之所以能做到这一点,是因为 << 运算符针对不同的数据类型进行了**重载 (Overloading)**(我们将在后续章节详细学习)。简单来说,就是为 << 运算符定义了多个版本,每个版本知道如何处理特定类型的数据,并将它们转换为适合输出的字符序列。
2.3 其他C++语句
本节将介绍更多C++语句,包括如何从用户那里获取输入,如何更灵活地使用 cout,并对C++的核心概念——类进行初步介绍。
2.3.1 使用cin
与 cout 用于输出类似,cin 是 iostream 库中预定义的一个对象,代表标准输入流,通常连接到键盘。我们可以使用 cin 来读取用户输入的数据。
>> 运算符(提取运算符)用于从 cin 对象获取数据,并将其存储到变量中。
用法与示例:
1 |
|
-
#include <iostream>: 使用cin同样需要包含此头文件。 -
std::cin:cin对象也位于std名称空间中。 -
cin >> variable;: 提取运算符>>从输入流(键盘)中读取数据,并根据variable的类型进行解释,然后将值存入variable。cin也会根据读取的数据类型自动进行转换。 - 输入分隔:
cin通常使用空白(空格、制表符、换行符)来分隔不同的输入项。例如,如果程序期望读取两个整数cin >> a >> b;,用户可以输入10 20然后按 Enter,或者输入10按 Enter 再输入20按 Enter。
2.3.2 使用cout进行拼接
我们在前面已经看到如何使用 cout 和插入运算符 << 输出单个值或字符串。cout 的一个便捷之处在于,你可以在一条语句中连续使用 << 运算符,将多个输出项“拼接”在一起。这称为**链式输出 (Chaining Output)**。
用法与示例:
1 |
|
-
cout << item1 << item2 << item3;:cout对象在处理完第一个<< item1后,会返回自身 (cout),因此可以继续处理下一个<< item2,以此类推。 - 这种链式调用使得将变量值、字符串字面量和表达式结果组合输出变得非常方便和易读。
2.3.3 类简介
类 (Class) 是C++的核心概念,也是面向对象编程(OOP)的基础。可以把类看作是创建对象 (Object) 的蓝图或模板。
- 封装 (Encapsulation): 类将数据(称为成员变量或属性)和操作这些数据的函数(称为成员函数或方法)捆绑在一起。
- 抽象 (Abstraction): 类提供了一个接口(通过其公有成员函数),隐藏了内部实现的复杂细节。
我们已经在使用类的对象了!cout 和 cin 就是 C++ 标准库中定义的类的对象:
-
cout是ostream类(输出流类)的一个对象。 -
cin是istream类(输入流类)的一个对象。
ostream 类定义了如何处理输出,包括 << 运算符如何针对不同数据类型工作。istream 类定义了如何处理输入,包括 >> 运算符如何读取数据。
概念理解:
想象一下 “汽车” 这个类:
- 数据/属性 (成员变量): 颜色、品牌、型号、当前速度、油量等。
- 操作/行为 (成员函数): 启动()、加速()、刹车()、鸣笛()、获取当前速度() 等。
根据这个 “汽车” 类,我们可以创建具体的对象,比如 “我的蓝色丰田卡罗拉” 或 “邻居的红色法拉利”。每个对象都有自己的属性值(不同的颜色、品牌等),但它们都共享类定义的行为(都可以启动、加速、刹车)。
示例 (概念性,非完整代码):
1 | // 这是一个非常简化的概念展示,不是完整的 C++ 类定义 |
在后续章节中,我们将深入学习如何定义和使用自己的类。目前,只需理解类是定义数据和相关操作的一种方式,而对象是类的具体实例,cout 和 cin 就是我们已经接触到的对象实例。
2.4 函数
函数是C++程序的构建块,它们是执行特定任务的命名代码段。使用函数可以使程序模块化、更易于理解和维护。本节将介绍如何使用和定义函数。
2.4.1 使用有返回值的函数
许多C++函数会执行一个操作并返回一个值给调用它的代码。这种函数被称为**有返回值的函数 (Function with Return Value)**。
我们已经使用过一些有返回值的函数,例如 C++ 标准库 <cmath> (或 C 语言的 <math.h>) 中提供的 sqrt() 函数,它计算一个数的平方根并返回结果。
使用方法:
- 包含头文件: 确保包含了提供该函数声明的头文件(例如
<cmath>)。 - 函数调用: 使用函数名,并在括号
()内提供所需的**参数 (Argument)**(传递给函数的值)。 - 处理返回值: 函数调用本身就是一个表达式,其值就是函数的返回值。可以将这个返回值赋给变量、用在更复杂的表达式中或直接输出。
用法与示例:
1 |
|
-
std::sqrt(area): 这是一个函数调用。std::sqrt是函数名,area是传递给函数的参数。 -
double side = ...:sqrt()函数返回一个double类型的值,这个值被用来初始化side变量。
2.4.2 函数变体
函数可以有多种形式:
- 有参数,有返回值: 如
sqrt(double x),接收一个double参数,返回一个double值。 - 无参数,有返回值: 例如,某些库函数可能读取系统时间并返回一个值,不需要用户提供参数。
- 有参数,无返回值: 这种函数执行一个操作(如打印到屏幕),但不需要返回任何计算结果。这种函数的返回类型通常声明为
void。我们将在 2.4.3 节看到例子。 - 无参数,无返回值: 执行一个固定的操作,不接受输入参数也不返回结果,返回类型也是
void。
示例 (概念性):
1 |
|
2.4.3 用户定义的函数
除了使用库函数,我们还可以定义自己的函数来执行特定任务。这有助于组织代码和重用代码。
定义函数的基本结构:
1 | returnType functionName(parameterList) |
-
returnType: 函数执行完毕后返回的数据类型。如果函数不返回值,则使用void。 -
functionName: 你为函数选择的名称。 -
parameterList: 函数接受的参数列表,包括每个参数的类型和名称。如果没有参数,括号()仍然需要,但内部为空。 -
{ ... }: 函数体,包含函数的代码。
函数原型 (Function Prototype):
在使用函数之前,编译器需要知道函数的接口(返回类型、名称、参数列表)。通常将函数原型放在 main() 函数之前或单独的头文件中。原型看起来像函数头,但以分号 ; 结尾,可以省略参数名。
1 | returnType functionName(parameterTypeList); // 函数原型 |
用法与示例 (定义一个无返回值的函数):
1 |
|
- 原型:
void cheers(int n);告诉编译器main函数后面会定义一个名为cheers的函数。 - 调用:
cheers(count);执行cheers函数的代码,并将count的值复制给cheers函数的参数n(这称为按值传递)。 - 定义: 提供了
cheers函数的具体实现。
2.4.4 用户定义的有返回值的函数
我们可以定义自己的函数来执行计算并返回结果。只需将 returnType 指定为期望的返回类型,并在函数体中使用 return 语句返回一个该类型的值。
用法与示例:
1 |
|
- 原型:
double cube(double x);声明了函数的接口。 - 调用:
cube(side)调用函数,side的值被传递给参数x。函数执行后返回一个double值。 - 定义:
double cube(double x)提供了函数的实现。return result;将计算出的立方值返回给调用者。
2.4.5 在多函数程序中使用using编译指令
当程序包含多个函数时,每个函数都需要访问 std 名称空间中的元素(如 cout, cin, endl)。有几种处理方式:
- 在每个函数中都使用
std::前缀: 这是最安全的方式,尤其是在头文件中,但可能使代码冗长。1
2
3
4
5
6
7
8void func1() {
std::cout << "Hello from func1\n";
}
void func2() {
int x;
std::cin >> x;
std::cout << "Input in func2: " << x << std::endl;
} - 在每个需要访问
std的函数内部使用using声明或using namespace std;: 这将using的作用域限制在函数内部,减少了命名冲突的风险。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void func1() {
using namespace std; // using 指令只在 func1 内部有效
cout << "Hello from func1\n";
}
void func2() {
using std::cin; // using 声明只引入 cin
using std::cout;
using std::endl;
int x;
cin >> x;
cout << "Input in func2: " << x << endl;
}
int main() {
// 在 main 中也需要访问 std
using namespace std;
func1();
func2();
cout << "Back in main." << endl;
return 0;
} - 在所有函数定义之前(通常是在所有
#include之后)放置一个using namespace std;指令: 这使得文件中的所有后续代码都可以直接使用std中的名称,无需std::前缀。这种方式最简单,但在大型项目中或编写头文件时不推荐,因为它可能引入全局命名冲突。 对于学习和小型项目,这通常是可接受的。
用法与示例 (全局 using 指令):
1 |
|
选择哪种方式取决于项目的规模和个人/团队的编码规范。对于初学者编写的简单多函数程序,将 using namespace std; 放在 #include 之后是一种常见的简化方法。
2.5 总结
本章引导我们迈出了学习C++的第一步,涵盖了编写、编译和理解一个基本C++程序所需的 foundational concepts。
我们从C++程序的核心——main()函数开始,它是程序的入口点。了解了如何使用注释(// 和 /* */)来提高代码的可读性。接着,我们接触了C++预处理器,特别是 #include 指令,它用于包含头文件(如 <iostream>),这些头文件提供了函数和对象的声明。我们区分了标准库头文件(用 <>)和用户自定义头文件(用 "")。
名称空间的概念被引入,特别是 std 名称空间,它包含了C++标准库的大部分内容。我们学习了访问 std 中元素的三种方式:使用 std:: 前缀、using 声明和 using 编译指令,并讨论了它们的适用场景和潜在风险。
我们重点学习了如何使用 iostream 库中的 cout 对象和插入运算符 << 来显示各种类型的数据(字符串、整数、浮点数等),以及如何使用 endl 或 \n 进行换行。代码格式化的重要性也被强调,以保证代码清晰、易于维护。
随后,我们学习了C++的基本语句类型。声明语句用于创建变量,指定其类型和名称,并可以选择在声明时进行初始化。赋值语句使用 = 运算符将值存储到变量中。我们还看到了 cout 如何智能地处理不同数据类型,以及如何通过链式调用 << 来拼接输出。
输入操作通过 cin 对象和提取运算符 >> 实现,允许程序从用户那里读取数据并存储到变量中。
最后,我们初步探讨了函数。我们学习了如何调用库函数(如 <cmath> 中的 sqrt())并使用它们的返回值。我们了解了函数的不同变体(有/无参数,有/无返回值)。更重要的是,我们学习了如何定义自己的函数,包括编写函数原型(声明)和函数定义(实现),以及如何通过函数调用来执行它们。我们还讨论了如何在包含多个函数的程序中管理 std 名称空间的使用。
通过本章的学习,我们已经能够编写简单的C++程序,实现基本的输入、处理和输出功能,并对C++程序的结构和一些核心概念有了初步的认识。