c++教程
c++教程

第一章
关于基本语法

开始
本书用的是visualstdio软件进行编写代码与演示的
1.开头语句与固定格式
#include <iostream>
using namespace std;
int main()
{
  return 0;
}
如你所见，上面的这一段代码就是每一个c++程序必须写的代码，下面我们将会一一解释其中的含义。
#include 这一行代码是用来引用头文件的，就像想要打扫房间就必须有工具一样，后面的：iostream就是c++所需的工具。
using namespace std;这一段先不用理解，后面的章节会讲到，先照抄就行。
int main（）这一段是最重要的，这个main函数里包括了程序开始时最先运行的代码，如果没有这一行，编译器会报错。代码在大括号中写。
return 0；这一段是返回值，也是记住就行，后面会讲。
2.关于程序运行的顺序
几乎所有编译器的运行顺序是从上到下，从左到右。
在c++中，每一个在函数内的语句结束后都要加分号。

输入输出流
在我们之前的章节里讲过，#include是用来引用头文件iostream的，而我们今天讲的输入输出流就包括在了iostream里。
最基本的语法如下
//输出流
cout<<"Hello World"<<endl;
//输入流
int a;
cin>>a;
这就是最简单的一个输入输出流。
cout用来把后面的内容输出到控制台，cin用来把控制台用户输入的信息给到程序里。
1.cout
这里的双引号用来告诉编译器这是文字，不是函数名或变量名。
<<这个符号就像压缩机，把这一行的代码从右向左压成一个包，发给控制台。
endl的作用是换行。
2.cin
>>这个符号就跟cout里的<<作用相反。把控制台里用户输入的东西打包发给程序。
后面接的只能是变量名。
意思是把控制台内的用户输入的数字或字符传给程序内的变量，实现人机接口。
3.应用
现在让我们结合上面写一个简单的代码吧
 
#include <iostream>
using namespace std;
int main()
  {
  cout<<"Hello World"<<endl;
  int a;
  cin>>a;
  cout<<a<<endl;
  return 0;
  }
 

变量
变量，顾名思义，就是可以改变的量，下面我们将会学习如何创建变量与改变变量。
1.变量
1.变量的定义
int a=0;
这里就是定义变量的方法。前面的int为变量的类型，后面的为名称。这里将一个int类型的变量初始化为了0。
变量的类型有很多种。
有：
布尔：
bool
字符：
char
整数：
short
int
long
long long
浮点：
float
double
long double
 bool类型的变量只能存储true与false
char类型的变量只能存储单个字符，例如‘a’或‘n’。但是单个中文不能存储，因为中文在程序里算两个字符。
 整数类型分为很多种，但是都大差不差，存储都只能存整数，不能存小数与字符。这些类型的差别为存储容量的不同，每一个不同类型的整数变量存储数字的大小上线都不同。
浮点型是存储小数的，注意，在使用float时做相等时无论什么数都要后面加个.0例如：float a=0.0;即使这个数为整数。在存储double时不仅要加.0也要加f例如double a=0.0f;
2.变量的赋值与运算
int a = 10;  // 初始化
a = 20;      // 赋值：把 20 存进 a
a = a + 5;   // 先算 a+5 得 25，再存回 a
局部变量如果只写 
int a; 而没有初始化，它的值是不确定的，不要直接读取。建议总是初始化：
int a = 0;
double price = 0.0;
3 初始化 vs 赋值
int a = 1;  // 初始化：变量创建时给值
a = 2;      // 赋值：变量已经存在，改它的值
const 变量只能初始化，不能赋值：
加了const的变量只能在初始化时进行赋值，这个代码便于后面防止误修改变量而设置很好用。
const int MAX = 100;
// MAX = 200; // 错误
2. 赋值号左边能放什么？
赋值号左边必须是“可以被修改的变量类东西”，通常叫左值。常见可以放：
int a;
a = 10;          // 变量
int arr[3];
arr[0] = 5;      // 数组元素
int* p = &a;
*p = 20;         // 解引用指针
int& r = a;
r = 30;          // 引用，改的是 a
不能放：
// 5 = a;        // 错误，5 不是变量
// a + 1 = 3;    // 错误，表达式不能赋值
// const int c=1; c=2; // 错误，const 不能改
注意：引用赋值不是“改绑”
int x = 1, y = 2;
int& r = x;  // r 是 x 的别名
r = y;       // 等价于 x = y，x 变成 2
             // r 仍然引用 x，不会改成引用 y
3. 赋值表达式本身也有值
a = 5 不只是一个动作，它本身也是一个表达式，值是赋值后的 
a。所以可以链式赋值：
int a, b, c;
a = b = c = 0;  // 从右往左：c=0，然后 b=0，然后 a=0
也可以：
int a;
int b = (a = 3); // a 变成 3，b 也得到 3
但初学阶段建议少写复杂链式赋值，分步写更清楚。
4. 算术运算
C++ 常见算术运算符：
运算符
含义
例子
+
加
a + b
-
减
a - b
*
乘
a * b
/
除
a / b
%
取余，只能用于整数
a % b
-a
取负
-a
+a
正号
+a
例子：
int a = 10, b = 3;
int sum = a + b;   // 13
int diff = a - b;  // 7
int prod = a * b;  // 30
int quo = a / b;   // 3
int rem = a % b;   // 1
4.1 整数除法会“截断”
如果 
/ 两边都是整数，结果还是整数，小数部分直接丢掉：
int a = 5, b = 2;
int c = a / b;       // 2，不是 2.5
double d = a / b;    // 2.0，因为先算 5/2 得 2，再转 double
想要小数除法，至少让一边是浮点数：
double d1 = 5.0 / 2;  // 2.5
double d2 = 5 / 2.0;  // 2.5
double d3 = static_cast<double>(5) / 2; // 2.5，推荐写法
负数除法是向零截断：
-5 / 2   // -2
-5 % 2   // -1
C++11 起，取余结果的符号和被除数相同。
4.2 除零和取余零
int a = 10;
// int b = a / 0; // 错误/未定义，程序可能崩溃
// int c = a % 0; // 错误
取余 
% 只能用于整数，
5.0 % 2 是错的。
4.3 溢出
int max = 2147483647;
// max + 1 的有符号溢出行为不可依赖
无符号整数溢出会按 2 的位数回绕：
unsigned char c = 255;
c++;  // c 变成 0
初学阶段记住：不要让整数运算超出范围。
4.4 浮点数有精度问题
double x = 0.1 + 0.2;
// x 不一定精确等于 0.3
不要直接用 
== 比较两个计算出来的浮点数：
#include <cmath>
double a = 0.1 + 0.2;
if (std::fabs(a - 0.3) < 1e-9) {
    // 认为它们足够接近
}
5. 复合赋值
复合赋值是“先运算，再存回左边”：
a += b;   // 等价于 a = a + b
a -= b;   // a = a - b
a *= b;   // a = a * b
a /= b;   // a = a / b
a %= b;   // a = a % b
还有位运算版本：
a &= b;
a |= b;
a ^= b;
a <<= 1;
a >>= 1;
例子：
int a = 10;
a += 5;  // a 变成 15
a *= 2;  // a 变成 30
a /= 4;  // a 变成 7，整数除法
注意类型转换：
int a = 10;
a += 2.5;  // 等价于 a = a + 2.5，先得 12.5，再转成 int，a 变成 12
6. 自增和自减
int i = 5;
i++;  // i 变成 6
i--;  // i 变成 5
前置和后置在单独使用时效果一样：
i++;
++i;
i--;
--i;
但在表达式里，它们有区别：
int i = 5;
int a = i++;  // 后置：先把旧值 5 给 a，然后 i 变成 6
// 此时 a == 5，i == 6
int b = ++i;  // 前置：i 先变成 7，再把 7 给 b
// 此时 b == 7，i == 7
记忆：
i++：先用旧值，再加一
++i：先加一，再用新值
初学阶段重要建议
不要在一个表达式里对同一个变量多次自增，例如：
// int a = i++ + ++i; // 不要这样写
这种写法结果不可靠，应拆成多步：
int i = 1;
int a = i;
i++;
int b = ++i;
7. 关系运算和逻辑运算
7.1 关系运算
运算符
含义
==
等于
!=
不等于
>
大于
<
小于
>=
大于等于
<=
小于等于
关系运算的结果是 
bool，即 
true 或 
false：
int a = 5, b = 3;
bool ok = a > b;  // true
千万不要把 
== 写成 
=：
int a = 5;
if (a == 0) { /* 比较 */ }
if (a = 0) {
    // 这是把 0 赋给 a，然后条件为 false
}
7.2 不要连写数学不等式
int x = 5;
// if (0 < x < 10) // 错误理解！
// 实际是 (0 < x) < 10，即 true/false 再和 10 比较
应该写：
if (x > 0 && x < 10) {
    // ...
}
7.3 逻辑运算
运算符
含义
例子
&&
逻辑与，两边都真才真
a > 0 && b > 0
||
逻辑或，一边真就真
a == 0 || b == 0
!
逻辑非，真变假，假变真
!ok
int a = 5, b = 3;
bool ok = (a > 0) && (b > 0);  // true
bool bad = (a == 0) || (b == 0); // false
7.4 短路求值
&& 左边为假时，右边不再计算；
|| 左边为真时，右边不再计算：
int a = 10, b = 0;
if (b != 0 && a / b > 2) {
    // b 为 0 时，左边 false，右边不会算，避免除零
}
但位运算 
& 和 
| 不短路：
// if (b != 0 & a / b > 2) // 不推荐这样写，右边仍可能计算
条件判断中，非零为真，零为假：
if (a)      // 等价于 if (a != 0)
if (!a)     // 等价于 if (a == 0)
8. 类型转换
8.1 隐式转换
混合类型运算时，通常会把范围小的转成范围大的：
int a = 5;
double b = 2.0;
double c = a + b;  // a 转成 double，结果是 7.0
赋值时，右边会转成左边的类型：
int a = 3.99;   // a 变成 3，小数被截掉
double d = 5;   // d 变成 5.0
bool b = 5;     // b 变成 true
int n = true;   // n 变成 1
char 参与算术通常提升为整数：
char c = 'A';
int x = c + 1;   // 'A' 的编码通常是 65，x 是 66
char d = c + 1;  // d 是 'B'
8.2 显式转换
推荐用 
static_cast：
int a = 7, b = 2;
double r = static_cast<double>(a) / b; // 3.5
也可以：
double d = 3.9;
int n = static_cast<int>(d); // 3，向零截断
不要依赖 C 风格转换的复杂规则，初学阶段用 
static_cast 更清楚。
8.3 有符号和无符号混用的坑
unsigned u = 1;
int n = -1;
if (n < u) {
    // 可能不是你想象的结果
}
因为 
n 可能被转成很大的无符号数。初学阶段尽量少混用 
int 和 
unsigned。
9. 位运算简介
位运算直接操作整数的二进制位：
运算符
含义
&
按位与
|
按位或
^
按位异或
~
按位取反
<<
左移
>>
右移
int x = 5;      // 二进制 0101
int y = x << 1; // 1010，即 10
int z = x & 1;  // 判断奇偶：1 表示奇数
初学阶段知道它们存在即可，注意：
& 和 
&& 不同
| 和 
|| 不同
移位位数不要超过类型宽度，不要移负数
x & 1 == 0 容易出错，应该写 
(x & 1) == 0
10. 条件运算符和 
sizeof
条件运算符：
int a = 10, b = 20;
int max = (a > b) ? a : b;  // 如果 a>b 取 a，否则取 b
sizeof 求类型或变量占多少字节：
int a = 0;
std::cout << sizeof(int) << '\n';
std::cout << sizeof a << '\n';
sizeof 的结果类型是 
size_t，通常是无符号整数。
11. 运算符优先级：不确定就加括号
常见优先级从高到低简化如下：
优先级
运算符
说明
高
a++ 
a-- 
a() 
a[] 
a.b 
a->b
后缀、调用、下标、成员
++a 
--a 
!a 
~a 
+a 
-a 
sizeof 
*p 
&a
一元
* 
/ 
%
乘除余
+ 
-
加减
<< 
>>
移位
< 
> 
<= 
>=
关系
== 
!=
相等
&
位与
^
位异或
|
位或
&&
逻辑与
||
逻辑或
?:
条件
= 
+= 
-= 等
赋值
低
,
逗号
几个容易错的例子：
int a = 1, b = 2, c = 3;
int x = a + b * c;   // 先乘后加，x = 7
int y = (a + b) * c; // 先加后乘，y = 9
// if (a & b == c) 实际可能被理解成 a & (b == c)
// 应该写 if ((a & b) == c)
int m = a > b ? a : b; // 条件运算符
赋值运算符是右结合：
a = b = c = 0;  // 等价于 a = (b = (c = 0))
优先级只决定“怎么分组”，不决定“先算左边还是右边”。例如 
f() + g() 中，
f() 和 
g() 谁先执行并不保证。不要依赖复杂表达式的求值顺序。
12. 常见错误清单
变量没初始化就使用
int a;
// std::cout << a; // 值不确定
整数除法丢小数
double d = 5 / 2; // 2.0，不是 2.5
把 
== 写成 
=
if (a = 0) { } // 赋值，不是比较
连写不等式
// if (0 < x < 10) // 错
if (x > 0 && x < 10)
浮点数直接用 
== 比较
在复杂表达式里多次自增同一变量
整数溢出、除零、取余零
有符号和无符号混用
优先级记错，不加括号
const 变量赋值、数组整体赋值
const int c = 1;
// c = 2; // 错
int x[3], y[3];
// x = y; // 错，数组不能整体赋值
13. 一个完整示例
#include <iostream>
#include <cmath>
int main() {
    int a = 10, b = 3;
    std::cout << "a + b = " << a + b << '\n';   // 13
    std::cout << "a - b = " << a - b << '\n';   // 7
    std::cout << "a * b = " << a * b << '\n';   // 30
    std::cout << "a / b = " << a / b << '\n';   // 3
    std::cout << "a % b = " << a % b << '\n';   // 1
    std::cout << "a / 2.0 = " << a / 2.0 << '\n'; // 5
    double r = static_cast<double>(a) / b;
    std::cout << "r = " << r << '\n';  // 3.33333
    int x = 5;
    int old = x++;  // old = 5，x = 6
    int now = ++x;  // x = 7，now = 7
    std::cout << old << ' ' << now << ' ' << x << '\n'; // 5 7 7
    a += 5;  // a = 15
    a *= 2;  // a = 30
    std::cout << "a = " << a << '\n'; // 30
    bool ok = (a > b) && (b != 0);
    int max = (a > b) ? a : b;
    std::cout << ok << ' ' << max << '\n'; // 1 30
    double p = 0.1 + 0.2;
    std::cout << std::boolalpha
              << (std::fabs(p - 0.3) < 1e-9) << '\n'; // true
}
14. 小练习
下面输出什么？
int a = 7, b = 2;
std::cout << a / b << ' ' << a % b;
答案：
3 1
下面 
d 是多少？
double d = 7 / 2;
答案：
3.0。因为先做整数除法。改成 
7 / 2.0 才是 
3.5。
下面 
a 是多少？
int a = 3;
a += 2.6;
答案：
5。先得 
5.6，再转成 
int 截断为 
5。
下面 
a、
b、
i 分别是多少？
int i = 1;
int a = i++;
int b = ++i;
答案：
a = 1，
i 先变 
2；然后 
++i 让 
i 变 
3，
b = 3。所以 
a=1, b=3, i=3。
下面写法为什么错？
if (0 < x < 10) { }
应改为：
if (x > 0 && x < 10) { }

流程控制
1.判断语句
1.1if语句
if语句是几乎所有编程语言中最重要的一个语句。
if，顾名思义就是如果，如果成立则……
 
 