C++全文

1、Windows开发环境的准备
1)下载Visual Studio 2022安装文件
从微软官方网站下载,网址:https://visualstudio.microsoft.com/zh-hans/

选中Community 2022,它是Visual Studio 2022官方免费社区版,无需注册,不需要破解和盗版。(请不要从国内的其它网站下载安装文件,有病毒和插件)
下载后的文件名是VisualStudioSetup.exe。
2)安装Visual Studio 2022
双击安装文件VisualStudioSetup.exe。

2、Linux开发环境
本课程适用于各种Linux发行版,建议采用CentOS7.0至CentOS7.9之间的版本,它是目前企业在实际项目开发中最广泛采用的Linux版本。
用root登录,执行以下命令,将安装gcc和g++编译器以及gdb调试器。
yum -y install gcc gcc-c++ gdb
几十秒即可安装完成。
3、第一个C++程序
VS2022太方便了,它可以帮我们生成一个最简单的C++程序。
1)用VS生成最简单的C++程序
鼠标双击Visual Studio 2002,运行它。

点击“创建新项目”。

选择“控制台应用”,再点“下一步”。

点击“创建”后将生成一个最简单的C++程序。

2)运行C++程序
选择“调试->开始执行“菜单,或快捷键Ctrl+F5运行程序。
3)示例
// 包含头文件。
#include

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
// 在控制台输出一首诗。
std::cout << “\n\n 我是一只傻傻鸟\n”;
std::cout << " 生活美好如鲜花,不懂享受是傻瓜;\n";
std::cout << " 傻呀傻呀傻呀傻,不如小鸟和乌鸦。\n";
std::cout << " 芳草地啊美如画,谁要不去是傻瓜;\n";
std::cout << " 我是一只傻傻鸟,独在枯枝丫上趴。\n";

// std::cout         向控制台输出内容的指令,只能小写,不能用大写。
// <<              输出的运算符。
// ""               字符串内容的边界符,半角。
// Hello World!     输出字符串的内容,可以是中文、英文和任意符号,半角的双引号除外。
// \n               输出一个换行。
// ;                 C++语句结束的标志,半角。

}
4、C++输出数据
数据是信息的载体,写程序的目的就是为了处理数据。
1)数据的分类
数据有数字、字符和字符串三种类型。
 数字:直接书写,如:100、18.52、0、9;
 字符:用半角的单引号包含的一个符号,如:‘A’、‘Z’、‘0’、‘9’、‘~’、‘+’,汉字和全角的标点符号不是字符;
 字符串:用半角的双引号包含的多个符号,如:“Hello World”、“我是一只傻鸟”、“西施”、“100”、“X”。
2)输出数据
 std::cout可以输出各种类型的数据;
 <<操作符可以拼接多个数据项;
 std::endl也可以用于换行;
 using namespace std;指定缺省的命名空间。
3)示例
#include

// 指定缺省的命名空间。
using namespace std;

int main()
{
// 用多个数据项输出超女信息,姓名:西施;年龄:25;体重:48.5;性别:X
// std::cout << “姓名:西施;年龄:25;体重:48.5;性别:X\n”;
cout << “姓名:” << “西施” << “;年龄:” << 25 << “;体重:” << 48.5
<< “;性别:” << ‘X’ << endl;
}
5、程序的注释
在程序中添加的说明文字,对代码的流程或功能加以解释,方便自己和其他的程序员阅读和理解代码。
编译器在编译源代码的时候,会忽略注释。
1)单行注释
用两根反斜线打头,一般放在代码的上方,或者一行语句的末尾。
注意:字符串内容中的两根反斜线是内容的一部分,不是注释。
2)多行注释
从/开始,到/结束,把一些内容夹住。
注意:a)字符串内容中的//是内容的一部分,不是注释;b)//可以出现在一行代码的中间。
3)注释的注释
单行注释可以注释多行注释,多行注释也可以注释单行注释,但是,不建议使用。
4)VS中的快捷键
添加注释:Ctrl+k+c
取消注释:Ctrl+k+u
5)示例
// 包含头文件。
#include

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
// 在控制台输出一首诗。
cout << “\n\n 我是一只傻傻鸟\n”;
cout << " 生活美好如鲜花,不懂享受是傻瓜;\n";
cout << " 傻呀傻呀傻呀傻,不如小鸟和乌鸦。\n";
cout << " 芳草地啊美如画,谁要不去是傻瓜;\n";
cout << " 我是一只傻傻鸟,独在枯枝丫上趴。\n";

cout << "姓名:" << "西施" << /*";年龄:" << 25 << */";体重:" << 48.5 << "。" << endl;

/*
 std::cout         向控制台输出内容的指令,只能小写,不能用大写。
 <<              输出的运算符。
 ""               字符串内容的边界符,半角。
 Hello World!     输出字符串的内容,可以是中文、英文和任意符号,半角的双引号除外。
 \n               输出一个换行。
 ;                 C++语句结束的标志,半角。
 */

}
6、使用变量
变量是内存变量的简称,用于存放数据。
1)声明变量
变量在使用之前要先声明。
语法:数据类型 变量名
C++常用的数据类型有五种:整数(int)、浮点数(float和double)、字符(char)、字符串(string)和布尔(bool)。
变量在声明的时候可以赋初始值。
语法:数据类型 变量名=值
2)变量的赋值
语法:变量名=值
3)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
// 整数(int)、浮点数(float和double)、字符(char)、字符串(string)和布尔(bool)。
// 超女基本信息:姓名、年龄、体重、性别、颜值。
// 声明变量,存放超女基本信息的数据项。
string name = “西施”; // 姓名。
int age = 25; // 年龄。
double weight = 48.6; // 体重(kg)。
char sex = ‘X’; // 性别:X-女;Y-男。
bool yz = false; // 颜值:true-漂亮;false-不漂亮。

cout << "姓名:" << name << ",年龄:" << age << ",体重:" << weight 
     << ",性别:" << sex << ",颜值:" << yz << endl;

name = "冰冰";           // 字符串有双引号包含。
age = 23;                // 整数直接书写。
weight = 50.5;           // 浮点数直接书写。
sex = 'X';                // 字符用单引号包含。
yz = true;                // 布尔型取值只能是true和false,或1和0。

cout << "姓名:" << name << ",年龄:" << age << ",体重:" << weight
     << ",性别:" << sex << ",颜值:" << yz << endl;

}
注意,布尔型变量输出的时候,如果值是true,将显示1,false显示0。
7、使用常量
常量是程序中固定不变的数据。
1)宏常量
一般在main函数的上面声明,用大写命名。
语法:#define 常量名 值
2)const修饰的变量
在程序的任何地方都可以声明。
语法:const 数据类型 常量名=值
3)常量的特点
程序中不允许改变常量的值,否则编译的时候会报错。
4)示例
#include // 包含头文件。

#define MONTHS 12 // 一年中的月份数。
#define PI 3.14159 // 圆周率。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
const int days = 7; // 一个星期中的天数。

cout << "一年有" << MONTHS << "个月。" << endl;
cout << "圆周率的值是:" << PI << endl;

cout << "一个星期有" << days << "天。\n";

}
8、标识符的命名
1)C++命名规则
C++规定给标识符(变量、常量、函数、结构体、类等)命名时,必须遵守以下规则。
 在名称中只能使用字母字符、数字和下划线;
 名称的第一个字符不能是数字;
 名称区分大写字符与小写字符;
 不能将C++关键字用作名称;
 以下划线和大写字母打头的名称被保留给编译器及其使用的资源使用,如果违反了这一规则,会导致行为的不确定性。
 C++对名称的长度没有限制,但有些平台可能有长度限制(64字符)。
C++提倡有一定含义的名称(望名知义)。
2)C++关键字
关键字也叫保留字,是C++预先保留的标识符。
每个C++关键字都有特殊的含义,用于声明类型、对象、函数、命名空间等,程序中不能声明与关键字同名的标识符。
asm do if return typedef
auto double inline short typeid
bool dynamic_cast int signed typename
break else long sizeof union
case enum mutable static unsigned
catch explicit namespace static_cast using
char export new struct virtual
class extern operator switch void
const false private template volatile
const_cast float protected this wchar_t
continue for public throw while
default friend register true
delete goto reinterpret_cast try
9、输入数据
程序输入数据的方式有多种。
 从控制台的界面中输入(网页、PC桌面程序、APP程序);
 从文件中读取;
 从数据库中读取;
 从网络中读取。
1)用std::cin输入数据
语法:std::cin>>变量名;
注意:
 a)布尔型变量的值在计算机内部用1(true)和0(false)存储;b)程序中可以书写true和false,也可以书写1和0,其它值将强制转换成1;c)用cin输入时可以填1和0,其它值也强制转换成1;d)用cout输出时只显示1和0,不显示true和false。
 如果输入的数据与变量的数据类型不匹配,会导致行为的不确定性。
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
string name; // 姓名。
cout << “请输入超女的姓名:”;
cin >> name;
cout << “输入的超女姓名是:” << name << endl;

int age;               // 年龄。
cout << "请输入超女的年龄:";
cin >> age;
cout << "输入的超女年龄是:" << age << endl;

double weight;        // 体重(kg)。
cout << "请输入超女的体重(kg):";
cin >> weight;
cout << "输入的超女体重是:" << weight << endl;

char sex;              // 性别:X-女;Y-男。
cout << "请输入超女的性别(X-女;Y-男):";
cin >> sex;
cout << "输入的超女性别是:" << sex << endl;

bool yz;               // 颜值:true-漂亮;false-不漂亮。
cout << "请问输入超女的颜值(1-漂亮;0-不漂亮):";
cin >> yz;
cout << "输入的超女颜值是:" << yz << endl;

}
10、算术运算
运算符 描述

  • 两个数相加。
  • 一个数减另一个数。
  • 两个数相乘。
    / 分子除以分母。
    % 取模运算,整除后的余数。
    注意:
     整数进行除法运算时,如果分母为0,程序将异常退出;
     浮点数进行除法运算时,如果分母为0.0,将得到inf(infinite,无穷大);
     两个整数进行除法运算时,将舍去小数部分,得到一个整数;
     整数与浮点数进行除法运算时,得到的结果是浮点数;
     进行除法运算时,在整数前面加(float)或(double)可以将整数转换为float或double类型;
     取模运算只能用于整数(分母也不能为0)。
    11、自增和自减
    运算符 描述
    ++变量名 先把变量的值加1,然后再执行表达式。
    变量名++ 先执行表达式,再把变量的值加1。
    –变量名 先把变量的值减1,然后再执行表达式。
    变量名-- 先执行表达式,再把变量的减1。
    12、赋值运算
    1)赋值运算
    运算符 示例 描述
    = c = a + b; 将把a + b的值赋给c。 把右边操作数的值赋给左边操作数。
    += c += a; 相当于 c = c + a; 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数。
    -= c -= a; 相当于 c = c - a; 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数。
    *= c *= a; 相当于 c = c * a; 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数。
    /= c /= a; 相当于 c = c / a; 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数。
    %= c %= a; 相当于 c = c % a; 求余数且赋值运算符,求两个操作数的模赋值给左边操作数,浮点数不适用取余数。
    注意:
     字符串(string)只能使用等号(=)赋值,不能使用其它的赋值运算符;
     浮点数不能使用%=运算符;
     等号(=)赋值运算符可以连续使用;
     如果赋值运算符两边操作数的数据类型不同,C++将自动转换数据类型,可能会损失精度,也可能超出取值范围,如果转换不成功,编译时会报错。
    2)示例
    #include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
int a = 10;
int c = 20;

// c += a;                       // c=c+a;
// c -= a;                        // c=c-a;
// c *= a;                        // c = c * a;
// c /= a;                        // c = c / a;
//c %= a;                       // c = c % a;
// cout << "c=" << c << endl;

a = c = 30;
cout << "a=" << a<<endl;
cout << "c=" << c << endl;

}
13、C++11初始化赋值
1)C++和C++11初始化赋值
 把值写在小括号中,等于号可以省略(C++标准)
int a=(15); // 声明变量a,初始化值为15。
int b(20); // 声明变量b,初始化值为20。
 把值写在花括号中,等于号也可以省略(C++11标准),统一初始化列表。
int a={15}; // 声明变量a,初始化值为15。
int b{20}; // 声明变量b,初始化值为20。
注意:在Linux平台下,编译需要加-std=c++11参数。
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
int a = 10;
int b = (10);
int c(10);
int e = {10};
int f{ 10 };

cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
cout << "e=" << e << endl;
cout << "f=" << f << endl;

}
14、关系运算
用于比较两个表达式的值,运算的结果为1-true和0-false。
1)关系运算
关系 数学的表示 C++的表示
等于 = ==
不等于 ≠ !=
小于 < <
小于等于 ≤ <=
大于 > >
大于等于 ≥ >=
注意:
 关系运算符的两边可以是数值,也可以是表达式;
 用std::cout输出关系运算表达式时,关系表达式要加括号;
 关系运算也适用于字符串(string),字符串常用的关系运算是==和!=,其它的基本上不用。
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
int a = 7;
int b = 7;
bool result;

result = a <= b-3;            // a和b先做比较(关系)运算,然后再赋值给result。

cout << "result=" << result << endl;    // 关系运算表达式需要括号,算术运算表达式可以不用括号。

string str1 = "西施";
string str2 = "西瓜";
cout << (str1 ==> str2) << endl;

}

15、逻辑运算
1)逻辑运算
根据给定的逻辑因子(表达式或值)返回一个新的逻辑因子。
运算符 术语 示例 结果
&& 逻辑与 a&&b; 如果a和b都为真,则结果为真,否则为假。
|| 逻辑或 a||b; 如果a和b中有一个为真,则结果为真,二者都为假时,结果为假。
! 逻辑非(反) !a; 如果a为假,则!a为真; 如果a为真,则!a为假。
注意:
 逻辑运算符的两边可以是数值,也可以是表达式;
 用std::cout输出逻辑运算表达式时,逻辑表达式要加括号;
 在实际开发中,逻辑运算的多重组合是重点。
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
bool a = false;
bool b = true;
// bool c = a && b; // 如果a和b都为真,则结果为真,否则为假。
// bool c = a || b; // 如果a和b中有一个为真,则结果为真,二者都为假时,结果为假。
bool c = !a; // 如果a为假,则!a为真; 如果a为真,则!a为假。

// cout << "c=" << c << endl;
// cout << "a&&b=" << (a && b) << endl;
// cout << "a||b=" << (a || b) << endl;
cout << "!a=" << c << endl;

}

///

#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
// 超女必须满足四个条件:年龄25岁以下,身高165以上、体重50公重以下,颜值要漂亮。
int age = 23;
int height = 168;
double weight = 48.8;
bool yz = true;

cout << "result="<<(age<25&&height>165&&weight<50&&yz==true) << endl;

}

16、逗号运算
1)逗号运算
把一行语句中的多个表达式连接起来,程序将从左到右执行表达式。
语法:表达式一,表达式二,……,表达式n;
逗号运算常用于声明多个变量。
int a,b; // 声明变量a和b。
int a=10,b=20; // 声明变量a和b并初始化。
也可以用于其它语句中,但是,逗号运算符是所有运算符中级别最低的,以下两个表达式的效果是不同的。
int a,b;
b=a=2,a2;
b=(a=2,a
2);
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
/*int a =10, b=20;

cout << "a=" << a << endl;
cout << "b=" << b << endl;*/

int a, b;
//b = a = 2, a * 2;
b = (a = 2, a * 2);
cout << "a=" << a << endl;
cout << "b=" << b << endl;

}
17、运算的优先级
1)运算的优先级
一个表达式可以包含多个运算符,运算符的优先级决定了表达式各部分的执行顺序。
例如,按照运算规则, *的优先级比+高,所以的b * c将先执行:
a + b * c;
如果想让a + b先执行,则必须使用括号:
(a + b) * c;
如果一个表达式中操作符的优先级相同,那么它们的结合律(associativity)决定了它们的执行顺序(从左到右或从右到左)。例如,算术运算的组合方式是从左到右,赋值运算则是从右到左。如下:
表达式 结合律 组合方式
a/b%c 从左到右 (a/b)%c
a=b=c 从右到左 a=(b=c)
下表是全部运算符的优先级和结合律:
优先级 运算符 名称或含义 使用形式 结合方向
1 [] 下标 地址[表达式] 左到右
() 圆括号 (表达式)/函数名(形参表)
. 成员选择(对象) 对象.成员名
-> 成员选择(指针) 对象指针->成员名
2 - 负号运算符 -表达式 右到左
(类型) 强制类型转换 (数据类型)表达式
++ 前置自增运算符 ++变量名
++ 后置自增运算符 变量名++
– 前置自减运算符 --变量名
– 后置自减运算符 变量名--
* 取值运算符 指针变量
& 取地址运算符 &变量名
! 逻辑非运算符 !表达式
~ 按位取反运算符 ~表达式
sizeof 长度运算符 sizeof(表达式)
3 / 除 表达式/表达式 左到右
* 乘 表达式
表达式
% 余数(取模) 整型表达式/整型表达式
4 + 加 表达式+表达式 左到右
- 减 表达式-表达式
5 << 左移 变量 左到右
>> 右移 变量>>表达式
6 > 大于 表达式>表达式 左到右
>= 大于等于 表达式>=表达式
< 小于 表达式
<= 小于等于 表达式
7 == 等于 表达式==表达式 左到右
!= 不等于 表达式!= 表达式
8 & 按位与 表达式&表达式 左到右
9 ^ 按位异或 表达式^表达式 左到右
10 | 按位或 表达式|表达式 左到右
11 && 逻辑与 表达式&&表达式 左到右
12 || 逻辑或 表达式||表达式 左到右
13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左
14 = 赋值运算符 变量=表达式 右到左
/= 除后赋值 变量/=表达式
= 乘后赋值 变量=表达式
%= 取模后赋值 变量%=表达式
+= 加后赋值 变量+=表达式
-= 减后赋值 变量-=表达式
<<= 左移后赋值 变量
>>= 右移后赋值 变量>>=表达式
&= 按位与后赋值 变量&=表达式
^= 按位异或后赋值 变量^=表达式
|= 按位或后赋值 变量|=表达式
15 , 逗号运算符 表达式,表达式,… 左到右
注意:
 如果不确定运算符的优先级,可以加括号;
 多用括号,让代码的可读性更好。
2)示例
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
int a, b, c;

c = 10;                             // 赋值表达式的值为赋值符号右边的值。
cout << "(c = 10)=" << (c = 10) << endl;

a = b = c = 10;               // 赋值运算的结合律是从右到左。

}

///
#include // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// main函数,程序从这里开始执行,每个程序只能有一个main函数。
int main()
{
int a, b, c, d;

a = 4, b = 2, c = 5;

d = a * (b / c);                       // 算术运算的结合律是从左到右。

cout << "d=" << d << endl;

}

18、if语句的基本结构
语法:
if (表达式)
{
// 表达式为真时执行的语句。
}
else
{
// 表达式为假时执行的语句。
}
注意:
 if (表达式)之间的空格可以不写。
 表达式必须使用括号。
 表达式可以是具体的值。
 表达式一般是关系运算和逻辑运算表达式,也可以是赋值运算或其它的表达式。
 不要把if(变量名==值)写成if(变量名=值)。
 整个if语句可以没有else分支。
 if或else分支花括号内的代码如果只有一行,花括号可以不写;如果一行也没有,花括号一定要写;如果有多行,花括号一定要写,如果不写,除了第一行,其它的代码将不是if语句的一部分。
 if (表达式)和else后不能加分号,因为分号表示空语句。(C++用分号作为一条语句结束的标志。如果在C++程序中不小心多写了一个分号,那么该分号会被当成一条空语句。)
2)示例
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// C++用分号作为一条语句结束的标志。
// 如果在C++程序中不小心多写了一个分号,那么该分号也许会被视作一个空语句。

// 判断超女的颜值,如果漂亮,在控制台输出“晋级下一轮”,否则输出“冲关失败”。
// 1)声明一个bool型变量,用于存放超女的颜值数据。
bool yz;

// 2)显示输入超女颜值的提示信息。
cout << "请输入超女的颜值(1-漂亮;0-不漂亮):";

// 3)输入超女的颜值数据,存放在变量中。
cin >> yz;

// 4)用if语句判断超女的颜值,如果漂亮,显示“晋级下一轮”,否则显示“冲关失败”。
if (yz == true)
{
	cout << "小姐姐很漂亮哟!" << endl;
	cout << "恭喜您,晋级下一轮!" << endl;
}
else
{
	cout << "对不起,冲关失败!" << endl;
	cout << "推荐一个美容院,......" << endl;
}

}
19、嵌套使用if语句
1)嵌套使用if语句
if语句可以嵌套使用,实现多级(层)的条件判断(最多127层)。
语法:
if (表达式一)
{
if (表达式二)
{
// 表达式二为真时执行的语句。
}
else
{
// 表达式二为假时执行的语句。
}
}
else
{
// 表达式一为假时执行的语句。
}
2)示例
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 超女选秀:1)性别(X-女,Y-男);2)颜值(1-漂亮,0-不漂亮);3)身材(1-火辣,2-丰满,3-苗条)。

// 声明三个变量,存放超女的性别、颜值和身材数据。
char sex;        // 性别(X-女,Y-男)。
bool yz;         // 颜值(1-漂亮,0-不漂亮)。
int    sc;         // 身材(1-火辣,2-丰满,3-苗条)。

// 显示“请输入超女的性别(X-女,Y-男):”的提示文字。
cout << "请输入超女的性别(X-女,Y-男):";

// 输入超女的性别,存放在变量中。
cin >> sex;

// 判断超女的性别,如果是女,流程继续,否则程序结束。
if (sex == 'X')
{
	// 显示“请输入超女的颜值(1-漂亮,0-不漂亮):”的提示文字。
	cout << "请输入超女的颜值(1-漂亮,0-不漂亮):";

	// 输入超女的颜值,存放在变量中。
	cin >> yz;

	// 判断超女的颜值,如果是漂亮,流程继续,否则程序结束。
	if (yz == true)     // 漂亮。
	{
		// 显示“请输入超女的身材(1-火辣,2-丰满,3-苗条):”的提示文字。
		cout << "请输入超女的身材(1-火辣,2-丰满,3-苗条):";

		// 输入超女的身材,存放在变量中。
		cin >> sc;

		// 判断超女的身材,如果是火辣,显示“晋级成功”,如果是丰满,显示“待定”,程序结束。
		if (sc == 1)        // 1-火辣。
		{
			cout << "晋级成功!" << endl;
		}
		else
		{
			if (sc == 2)    // 2-丰满
			{
				cout << "待定!" << endl;
			}
		}
	}
}

}
20、嵌套if语句的坑
嵌套使用if语句时候,会出现if与else的配对问题。
C++编译器处理该问题的原则是:else总是与前面最近if 配对。
如果要改变这种配对关系,可以使用花括号来确定新的配对关系。
if (sex == ‘X’)
if (yz == true)
cout << “sexX,yztrue\n”;
else
cout << “sexY,yztrue or false\n”;
以上代码中的else与第二个if配对,如果想让它与第一个if配对,代码如下:
if (sex == ‘X’)
{
if (yz == true)
cout << “sexX,yztrue\n”;
}
else
cout << “sexY,yztrue or false\n”;
21、多条件的if语句
1)多条件的if语句
语法:
if (表达式一)
{
// 表达式一为真时执行的语句。
}
else if (表达式二)
{
// 表达式二为真时执行的语句。
}
else if (表达式三)
{
// 表达式三为真时执行的语句。
}
……
else if (表达式n)
{
// 表达式n为真时执行的语句。
}
else
{
// 全部表达式都不为真时执行的语句。
}
注意:
 多条件的if语句本质上是嵌套的if语句。
 最多只能有127个条件分支。
 最后一个else可以没有。
2)示例
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 超女的身材:1-火辣;2-丰满;3-苗条;4-强壮;5-肥胖;>5-未知 。

// 声明存放超女身材数据的变量。
int sc;

// 显示“请输入身材的代码(1-火辣;2-丰满;3-苗条;4-强壮;5-肥胖;>5-未知):”的提示文字。
cout << "请输入身材的代码(1-火辣;2-丰满;3-苗条;4-强壮;5-肥胖;其它表示未知):";

// 输入超女身材的代码,存放在变量中。
cin >> sc;

// 用多条件的if语句,判断身材代码,显示身材的中文描述。
if (sc == 1)     cout << "火辣!\n";
else if (sc == 2) cout << "丰满!\n";
else if (sc == 3) cout << "苗条!\n";
else if (sc == 4) cout << "强壮!\n";
else if (sc == 5) cout << "肥胖!\n";
else			 cout << "未知!\n";

}
22、if语句中的逻辑表达式
采用括号、对齐、空格、换行有助于更清晰的表达复杂的逻辑表达式。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 超女的数据:年龄(16-50岁),身高(150cm-190cm),身材(火辣;丰满;苗条)
// 颜值(漂亮;一般;歪瓜裂枣)。
// 晋级的标准:年龄25-30岁,身高165cm-175cm,身材火辣,颜值漂亮或者一般。

// 已准备好的超女数据。
int age = 28;
int height = 170;
string sc = "火辣";
string yz = "漂亮";

if (  (age > 25       && age < 30      ) &&        // 年龄
	  (height > 165 && height < 175    ) &&        // 身高
	  (sc == "火辣"                      ) &&        // 身材
	  (yz == "漂亮"  ||     yz == "一般"  )  )         // 颜值
{
	cout << "晋级成功!\n";
}

}
23、三目运算
三目运算也叫条件运算或三元运算,可以实现简单if语句的功能,但是书写更简洁。
语法: 表达式一 ? 表达式二 : 表达式三
先计算表达式一的值,如果为真,整个表达式的结果为表达式二的值,如果为假,整个表达式的结果为表达式三的值。
int a,b,c;
a=7;
b=6;
c=(a>b)?a:b;
等同于
if (a>b) c=a;
else c=b;
三目运算表达式可以嵌套使用,但是,过于复杂的三目运算表达式不方便理解。
比如判断year是不是闰年,是则返回1,不是返回0。
int year;
year=(year%1000)?(year%4000?1:0):(year%4==0?1:0)
① 、普通年能被4整除且不能被100整除的为闰年。
② 、世纪年能被400整除的是闰年。
③ 、对于数值很大的年份,这年如果能整除3200,并且能整除172800则是闰年。如172800年是闰年,86400年不是闰年。
24、switch语句
switch也是一种选择结构的语句,可以代替简单的多条件的if语句。
语法:
switch (表达式)
{
case 值一:
语句一;
break;
case 值二:
语句二;
break;

case 值n:
语句n;
break;
default:
上述条件都不满足时执行的语句;
}
注意:
 case后面必须是整数和字符,或者是结果为整数和字符的表达式,但不能使用变量。
 default不是必须的,当没有default时,如果全部的case匹配失败,那么就什么都不执行。
 每个分支不要漏写break;语句。
25、while循环语句
语法:
while (表达式)
{
语句块
}
先计算表达式的值,如果为真就执行语句块,执行完语句块后,回到循环首部再次计算表达式的值,如果为真又执行一次语句块……,这个过程会一直重复,直到表达式的值为假时不再执行语句块。
注意:
 如果表达式的值永远为真,那么将进入死循环,所以在循环中应该有改变表达式的值的方法。
 如果循环体中的语句块只有一行代码,大括号可以不书写。
 有疑问先放一边,在以后的课程中,会介绍循环的各种使用方法。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 有十个超女,编号是1-10,在控制台输出这十个超女的编号。
int no = 1; // 超女的编号。

while (no <= 10)
{
	cout << "这是第" << no++ << "名超女的编号。\n";
}

}
26、循环的跳转
break和continue两个关键字用于控制循环体中代码的执行流程。
break跳出(中止)当前循环语句。
continue回到当前循环语句的首部。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// break跳出(中止)当前循环语句,continue回到当前循环语句的首部。
// 程序运行后一直工作,逐个输入超女的数据,判断是否晋级,如果到了休息时间,就把程序停下来。
// 超女选秀的流程:1)如果漂亮,直接晋级;2)不漂亮也行,身材火辣的也可以晋级。
bool once = true; // 是否为第一次执行循环。

while (true)
{
	if (once == false)
	{
		// a)显示“是否继续下一名超女选秀(1-继续,0-结束):”的提示文字。
		cout << "是否继续下一名超女选秀(1-继续,0-结束):";
		// b)输入是否继续的决定,存放在变量中。
		bool exist; cin >> exist;
		// c)判断输入的决定,如果是结束,流程跳出循环。
		if (exist == false) break;
	}
	
	once = false;     // 表示循环已经被执行过。

	// 1)显示“请输入超女的颜值(1-漂亮,0-不漂亮):”的提示文字。
	cout << "请输入超女的颜值(1-漂亮,0-不漂亮):";
	// 2)输入超女的颜值,存放在变量中。
	bool yz; cin >> yz;
	// 3)判断超女的颜值,如果漂亮,显示“晋级成功”,流程跳转到循环的首部。
	if (yz == true)
	{
		cout << "晋级成功\n";  continue;
	}

	// 4)显示“请输入超女的身材(1-火辣,0-不辣):”的提示文字。
	cout << "请输入超女的身材(1-火辣,0-不辣):";
	// 5)输入超女的身材,存放在变量中。
	bool sc; cin >> sc;
	// 6)判断超女的身材,如果火辣,显示“晋级成功”。
	if (sc == true) cout << "晋级成功\n";
}

}

27、for循环语句
语法:
for (语句一 ; 表达式 ; 语句二)
{
语句块
}
1)循环开始的时候,先执行语句一,在整个循环过程中语句一只会被执行一次。
2)计算表达式的值,如果为真,就执行一次循环体中的语句块。
3)执行完语句块后,执行一次语句二。
4)重复第2)步和第3),直到表达式的值不为真才结束for循环。
注意:
 不要纠结for循环与while循环的区别,它们本质上没有区别。
 for循环一般需要一个相当于计数器的变量,在语句一中对它进行初始化,在语句二中进行计数操作。
 在for循环的语句一中,可以声明计数器变量。
 在for循环中,语句一、表达式和语句二都可以为空,for (;;)等同于while (true)。
 continue和break两个关键字也可以用在for循环体中。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 有十个超女,编号是1-10,在控制台输出这十个超女的编号。

for (int no = 1; no <= 10; no++)
{
	cout << "这是第" << no << "名超女的编号。\n";
}

}

28、嵌套使用循环
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 超女分4个小组,每个小组有3名超女,在控制台显示每个超女的小组编号和组内编号。
// 用一个循环,显示4个小组的信息。
//for (int ii=1; ii<=4; ii++)
//{
// // 再用一个循环,显示一组中3名超女的信息。
// for (int jj = 1; jj <= 3; jj++)
// {
// cout << “这是第” <<ii<<“个小组的第” << jj << “名超女。\n”;
// }
//}

// 在控制台输出九九乘法表。
for (int ii=1; ii<=9; ii++)
{
	for (int jj = 1; jj <= ii; jj++)
	{
		cout << ii << "*" <<  jj << "=" << ii*jj <<" ";
	}

	cout << endl;
}

}

29、do…while循环语句
语法:
do
{
语句块
} while (表达式);
功能与while语句类似,不同的是:
 进入循环时,先执行一次语句块,再计算表达式的值。
 循环的首部书写在循环的尾部,(表达式)后面还有一个分号。
30、goto语句
goto语句也称为无条件转移语句。
goto的语法:goto 语句标号;
语句标号的语法:语句标号:
如果在程序中使用了goto,程序的流程将跳转到语句标号的位置,并执行它后面的代码。
其中语句标号是按标识符规定书写的符号,放在某一语句行的前面,可以独占一行,标号后加半角冒号。
语句标号用于标识语句的位置,与goto语句配合使用。
在实际开发中,goto语句容易造成程序流程的混乱,不方便理解,调试也更麻烦,不建议使用。

31、函数的声明和定义
在复杂的程序中,如果全部的代码都写在main函数中,main函数体将非常庞大臃肿。
把任务分工到其它的函数中,main函数只负责程序的核心流程,具体的任务由其它函数完成。
这种思想就是模块化编程。
声明和定义函数的语法:
返回值的数据类型 函数名(参数一的数据类型 参数一, 参数二的数据类型 参数二,……)
{
实现函数功能的代码。
return 返回值;
}
函数的声明:让编译器知道函数的存在,包括返回值的数据类型、函数名和参数列表。
函数的定义:函数的实现过程。
注意:
 函数的声明和定义可以书写在一起,也可以分开,如果书写在一起,一般放在main函数的上面,如果分开,一般在main函数的上面声明,在main函数的下面定义。
 如果函数的声明和定义分开书写,函数的声明后面一定要有分号,函数的定义后面一定不能写分号。
 在同一个程序中,函数只需要声明和定义一次,也可以多次声明,但只能定义一次。
 函数的声明必须和函数的定义一致(返回值的数据类型、函数名和参数列表),如果函数名和参数列表不同,表示它们不是同一个函数。
 return语句返回值的数据类型必须与函数的声明一致。
 在函数体中,return语句可以多次使用。
 如果函数的重点是实现功能,不关心返回值,返回值的数据类型填void,return语句后面就空着。
 函数可以没有任何参数。
 函数名是标识符,必须满足标识符的命名规则。
 在函数的声明和函数的定义中,参数命名可以不同,但是没必要这么书写。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

// 写一个函数,给它两个整数,让它比较两个整数的大小,返回较大的那个整数。
int max(int a, int b); // 函数声明后面的分号不能少。
// 写一个函数,给它一个字符串,让它在控制台显示出来。
void print(string str);
// 写一个函数,在控制台输出九九乘法表。
void printmt();

int main()
{

}

int max(int a, int b) // 函数定义后面不能加分号。
{
if (a > b) return a;

return b;

}

void print(string str)
{
cout << str << endl;

return;

}

void printmt()
{
// 在控制台输出九九乘法表。
for (int ii = 1; ii <= 9; ii++)
{
for (int jj = 1; jj <= ii; jj++)
{
cout << ii << “*” << jj << “=” << ii * jj << " ";
}

	cout << endl;
}

return;

}
32、函数的调用
语法:函数名(参数一,参数二,……)
注意:
 声明函数的代码必须放在调用之前,定义函数的代码可以放在调用之后。
 调用函数的时候,参数列表必须与函数的声明一致(参数的个数、书写的顺序和数据类型)。
 不管在什么地方,都不能调用main函数,但是,在普通函数中,可以调用其它的普通函数。
 调用函数的代码可以独占一条语句,也可以用于表达式(赋值运算、算术运算、关系运算、函数的参数)。
 如果函数用于表达式中,返回值的数据类型要匹配(否则可能会被隐式转换或编译错误)。
 如果函数有返回值,可以不关心它,忽略它。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

// 写一个函数,给它两个整数,让它比较两个整数的大小,返回较大的那个整数。
int max(int a, int b); // 函数声明后面的分号不能少。
// 写一个函数,给它两个参数:no-超女编号,str-表白的内容。
void print(int no,string str);
// 写一个函数,在控制台输出九九乘法表。
void printmt();

int main()
{
cout << “max(5,8)=” << max(5,8) << endl;

print(8, "请借给我五分钱吧。");

printmt();

}

int max(int a, int b) // 函数定义后面不能加分号。
{
if (a > b) return a;

return b;

}

void print(int no, string str)
{
cout << “亲爱的”<<no<<“号:”<<str << endl;

return;

}

void printmt()
{
// 在控制台输出九九乘法表。
for (int ii = 1; ii <= 9; ii++)
{
for (int jj = 1; jj <= ii; jj++)
{
cout << ii << “*” << jj << “=” << ii * jj << " ";
}

	cout << endl;
}

return;

}

33、变量的作用域
作用域是指程序中变量存在(或生效)的区域,超过该区域变量就不能被访问。
变量分全局变量和局部变量两种,全局变量在整个程序中都可以访问,局部变量只能在函数或语句块的内部才能访问。
C++中定义变量的场景主要有五种:
1)在全部函数外面定义的是全局变量。
2)在头文件中定义的是全局变量。
3)在函数和语句块内部定义的是局部变量。
4)函数的参数是该函数的局部变量。
5)函数内部用static修饰的是静态局部变量。
1)全局变量
在整个程序生命周期内都是有效的,在定义位置之后的任意函数中都能访问。
全局变量在主程序退出时由系统收回内存空间。
2)局部变量
在函数或语句块内部的语句使用,在函数或语句块外部是不可用的。
局部变量在函数返回或语句块结束时由系统收回内存空间。
3)静态局部变量
用static修饰的局部变量生命周期和程序相同,并且只会被初始化一次。
其作用域为局部,当定义它的函数或语句块结束时,其作用域随之结束。
当程序想要使用全局变量的时候应该先考虑使用static(考虑到数据安全性)。
4)注意事项
 全局变量和静态局部变量自动初始化为0。
 局部变量不会自动初始化,其值是不确定的,程序中应该有初始化局部变量的代码,否则编译可能会报错(不同的编译器不一样)。
 局部变量和全局变量的名称可以相同,在某函数或语句块内部,如果局部变量名与全局变量名相同,就会屏蔽全局变量而使用局部变量,如果想使用全局变量,可以在变量名前加两个冒号(::)。
 for循环初始化语句中定义的变量的作用域是for语句块。
34、函数参数的传递
调用函数的时候,调用者把数值赋给了函数的参数。
实参:调用者程序中书写的在函数名括号中的参数,可以是常量、变量和表达式。
形参:函数的参数列表。
在函数定义的代码中,修改形参的值,会不会影响实参。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

// 调用函数的时候,调用者把数值赋给了函数的参数。
// 实参:调用者程序中书写的在函数名括号中的参数,可以是常量、变量和表达式。
// 形参:函数的参数列表。
// 在函数定义的代码中,修改形参的值,会不会影响实参?

void func(int no, string str); // 向超女表白的函数。

int main()
{
int bh = 3; // 超女的编号。
string message = “我是一只傻傻鸟。”; // 向超女表白的内容。

// func(bh, message);            // 调用向超女表白的函数。
// func(7, "小姐姐好漂亮哟。");            // 调用向超女表白的函数。
{
	int no=7;
	string str= "小姐姐好漂亮哟。";
	no = 5; str = "我有一只小小鸟。";
	cout << "亲爱的" << no << "号:" << str << endl;
}

cout << "亲爱的" << bh << "号:" << message << endl;

}

void func(int no, string str) // 向超女表白的函数。
{
no = 5; str = “我有一只小小鸟。”;
cout << “亲爱的” << no << “号:” << str << endl;
}

35、函数分文件编写
头文件(.h):需要包含的头文件,声明全局变量,函数的声明,数据结构和类的声明等。
源文件(
.cpp):函数的定义、类的定义。
主程序:main函数,程序的核心流程,需要用#include "头文件名"把头文件包含进来。
编译:
Windows是集成开发环境,不需要写编译指令。
在Linux系统下,把全部的源文件一起编译,如:g++ -o demo demo.cpp tools.cpp girls.cpp
示例:
/demo01.cpp/
#include “tools.h” // 包含头文件tools.h,min和max函数在里面。
#include “girls.h” // 包含头文件girls.h,print函数在里面。

int main()
{
cout << “max(5,8)=” << max(5, 8) << endl;
cout << “min(5,8)=” << min(5, 8) << endl;
print(3, “我是一只傻傻鸟。”);
}

/girls.cpp/
#include “girls.h”

void print(int no, string str) // 表白神器。
{
cout << “亲爱的” << no << “号:” << str << endl;
}

/tools.cpp/
#include “tools.h”

int max(int a, int b) // 比较两个数的大小,返回较大者。
{
return a > b ? a : b;
}

int min(int a, int b) // 比较两个数的大小,返回较小者。
{
return a < b ? a : b;
}

/girls.h/
#pragma once

#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

void print(int no, string str); // 表白神器。

/toolss.h/
#pragma once

#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int max(int a, int b); // 比较两个数的大小,返回较大者。
int min(int a, int b); // 比较两个数的大小,返回较小者。

36、VS中调试程序
F9设置/取消断点。
F5/F10开始调试。
Shift+F5放弃调试。
F10逐过程执行。
F11逐语句执行(可进入函数内部)。
局部变量窗口显示了变量的值,也可以修改。
37、递归函数
一个函数可以调用另一个函数,作为特例,如果函数调用了自己,就像故事中提到了同样的故事一样,我们把函数在运行时调用自己的情况叫做递归。
递归函数中一定要有递归终止的条件,否则是死递归。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int f(int x) // 递归函数。
{
if (x == 0) return 0; // 递归终止的条件。

return x + f(x - 1);          // 在函数体中调用了自己。

}

int main()
{
cout << “f(100)=” << f(100) << endl;
// 100+99+98+…+1+0
// 嵌套的调用函数 进入函数的过程是递去 函数返回的过程是归来

// 计算从1加到100的和。
int sum = 0;         //  存放累加的值。
for (int ii = 1; ii <= 100; ii++)
	sum = sum + ii;

cout << "sum=" << sum << endl;

}

38、sizeof运算符
sizeof运算符用于求数据类型或变量占用的内存空间。
用于数据类型:sizeof(数据类型)
用于变量:sizeof(变量名) 或 sizeof 变量名
注意:
 在32位和64位操作系统中,同一种数据类型占用的内存空间可能不一样。
 字符串(string)不是C++的基本数据类型,用sizeof求它占用内存的大小没有意义。

示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 用于数据类型:sizeof(数据类型)
// 用于变量:sizeof(变量名) 或 sizeof 变量名
// C++常用的数据类型:整数(int)、浮点数(float和double)、字符(char)和布尔(bool)。
cout << “sizeof(int)=” << sizeof(int) << endl;
cout << “sizeof(float)=” << sizeof(float) << endl;
cout << “sizeof(double)=” << sizeof(double) << endl;
cout << “sizeof(char)=” << sizeof(char) << endl;
cout << “sizeof(bool)=” << sizeof(bool) << endl;

int i; cout << "sizeof(int)=" << sizeof i << endl;
float f; cout << "sizeof(float)=" << sizeof f << endl;
double d; cout << "sizeof(double)=" << sizeof d << endl;
char c; cout << "sizeof(char)=" << sizeof c << endl;
bool b; cout << "sizeof(bool)=" << sizeof b << endl;

}
39、整型的基本概念
C++用int关键字来声明整型变量(int 是 integer 的简写)。
在声明整型变量的时候,可以在int关键字之前加signed、unsigned、short和long四种修饰符。
signed:有符号的,可以表示正数和负数。
unsigned:无符号的,只能表示正数,例如超女的身高和体重等。
short:短的,取值范围小,占用内存少。
long:长的,取值范围大,占用内存多。
类型简写 类型全称 长度 取值范围
short signed short int 2字节 -32768~32767
unsigned short unsigned short int 2字节 0~65535
int signed int 4字节 -2147483648~2147483647
unsigned unsigned int 4字节 0~4294967295
long signed long int 8字节 -9223372036854775808~
9223372036854775807
unsigned long unsigned long int 8字节 0~18446744073709551615
注意:
 整数的取值范围与计算机操作系统和C++语言编译器有关,没有一个固定的数值,我们可以根据它占用的内存大小来推断它的取值范围。
一个位的取值是 0 1 1=21-1
两个位的取值是 00 01 10 11 3=22-1
三个位的取值是 000 001 …… 111 7=23-1
a)一个字节有8个位,表示的数据的取值范围是28-1,即255。
b)如果占用的内存是两个字节,无符号型取值范围是28ⅹ28-1。
c)如果占用的内存是四个字节,无符号型取值范围是28ⅹ28ⅹ28ⅹ28-1。
d)如果占用的内存是八个字节,无符号型取值范围是28ⅹ28ⅹ28ⅹ28ⅹ28ⅹ28ⅹ28ⅹ28-1。
e)如果是有符号,取值范围减半,因为符号占一个位。
f)计算机用最高位1位来表达符号(0-正数,1-负数),unsigned修饰过的正整数不需要符号位,在表达正整数的时候比signed修饰的正整数取值大一倍。
 给整型变量赋值不能超出它的取值范围,否则能产生不可预后的后果。
 在实际开发中,为了防止超出取值范围,应该保证有足够的空间。
40、整数的书写
整数默认是十进制,一个表示十进制的数字不需要任何特殊的格式。
1、二进制
二进制由 0 和 1 两个数字组成,书写时必须以0b或0B(不区分大小写)开头。
以下是合法的二进制:
int a = 0b101; // 换算成十进制为 5
int b = -0b110010; // 换算成十进制为 -50
int c = 0B100001; // 换算成十进制为 33
以下是非法的二进制:
int m = 101010; // 无前缀 0B,相当于十进制
int n = 0B410; // 4不是有效的二进制数字
注意,C++标准并不支持上面的二进制写法,只是有些编译器自己进行了扩展,才支持二进制数字。换句话说,并不是所有的编译器都支持二进制数字,只有一部分编译器支持,并且跟编译器的版本有关系。
2、八进制
八进制由 0~7 八个数字组成,书写时必须以0开头(注意是数字 0,不是字母 o)。
以下是合法的八进制数:
int a = 015; // 换算成十进制为 13
int b = -0101; // 换算成十进制为 -65
int c = 0177777; // 换算成十进制为 65535
以下是非法的八进制:
int m = 256; // 无前缀 0,相当于十进制
int n = 03A2; // A不是有效的八进制数字
3、十六进制
十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,书写时必须以0x或0X(不区分大小写)开头。
以下是合法的十六进制:
int a = 0X2A; // 换算成十进制为 42
int b = -0XA0; // 换算成十进制为 -160
int c = 0xffff; // 换算成十进制为 65535
以下是非法的十六进制:
int m = 5A; // 没有前缀 0X,是一个无效数字
int n = 0X3H; // H不是有效的十六进制数字
4、需要注意的坑
在C++中,不要在十进制数前面加0,会被编译器当成八进制。
还有,不要随便删掉别人程序中整数前面的0,它不是多余的。
41、C++11的long long类型
在VS中,long是4字节,32位。 -2147483648~2147483647
在Linux中,long是8字节,64位。 -9223372036854775808~9223372036854775807
C++11标准增了long long类型的整数,至少64位,且至少与long一样长。
在VS中,long long是8字节,64位。 -9223372036854775808~9223372036854775807
在Linux中,long和long long类型都是8字节,64位。
42、浮点型(实数型)
C++浮点型分三种:float(单精度)、double(双精度)、long double(扩展精度)。
三者的区别是表示有效数字的范围不同。
数据类型 占用空间 有效数字范围
float 4字节 7位有效数字 8位
double 8字节 15~16位有效数字 17位
long double 不少于double 不低于double 17位
注意:
 在VS和Linux中,long double占用的内存空间分别是8和16字节。
 有效数字包括了小数点前面和后面的数字。
 C++缺省显示6位有效数字,如果要显示更多的有效数字,可以用printf()函数。
 浮点数的存储方法和整数不一样,比较复杂,如无必要,不用研究。(百度“为什么浮点数的小数位很多”、“为什么浮点数不精确”)
 在实际开发中,用整数代替浮点数,整数的运算更快,精度更高。9223372036854775807
示例:
#include <stdio.h> // 使用printf函数需要包含这个头文件。
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// float 7位有效数字;double 15~16位有效数字;long double 不低于double
float aa = 1234.45f; cout << “aa=” << aa << endl;
double bb = 12345123056789.45; cout << “bb=” << bb << endl;
long double cc = 12345126789.459; cout << “cc=” << cc << endl;

printf("aa=%lf\n", aa);
printf("bb=%lf\n", bb);
printf("cc=%lf\n", cc);

}
43、字符型的基本概念
字符型(char)占用的内存空间是1个字节,书写用单引号包含。
在内存中,不存放字符本身,而是存放与它对应的编码,即ASCII码。
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是现今最通用的单字节编码方案,包含了33个控制字符(具有特殊含义无法显示的字符)和95个可显示字符。
‘X’ -> 88 01011000 ‘a’->97 01100001 ‘3’->51 00110011
1)ASCII 控制字符 (0~31)
十进制 符号 中文解释 十进制 符号 中文解释
0 NULL 空字符 16 DLE 数据链路转义
1 SOH 标题开始 17 DC1 设备控制 1
2 STX 正文开始 18 DC2 设备控制 2
3 ETX 正文结束 19 DC3 设备控制 3
4 EOT 传输结束 20 DC4 设备控制 4
5 ENQ 询问 21 NAK 拒绝接收
6 ACK 收到通知 22 SYN 同步空闲
7 BEL 铃 23 ETB 传输块结束
8 BS 退格 24 CAN 取消
9 HT 水平制表符 25 EM 介质中断
10 LF 换行键 26 SUB 替换
11 VT 垂直制表符 27 ESC 换码符
12 FF 换页键 28 FS 文件分隔符
13 CR 回车键 29 GS 组分隔符
14 SO 移出 30 RS 记录分离符
15 SI 移入 31 US 单元分隔符
2)ASCII 可显示字符 (32~127)
十进制 符号 中文解释 十进制 符号 中文解释
32   空格 80 P 大写字母 P
33 ! 感叹号 81 Q 大写字母 Q
34 " 双引号 82 R 大写字母 R
35 # 井号 83 S 大写字母 S
36 $ 美元符 84 T 大写字母 T
37 % 百分号 85 U 大写字母 U
38 & 与 86 V 大写字母 V
39 ’ 单引号 87 W 大写字母 W
40 ( 左括号 88 X 大写字母 X
41 ) 右括号 89 Y 大写字母 Y
42 * 星号 90 Z 大写字母 Z
43 + 加号 91 [ 左中括号
44 , 逗号 92 \ 斜线
45 - 减号 93 ] 右中括号
46 . 句点或小数点 94 ^ 音调符号
47 / 反斜线 95 _ 下划线
48 0 数字0的符号 96 ` 重音符
49 1 数字1的符号 97 a 小写字母 a
50 2 数字2的符号 98 b 小写字母 b
51 3 数字3的符号 99 c 小写字母 c
52 4 数字4的符号 100 d 小写字母 d
53 5 数字5的符号 101 e 小写字母 e
54 6 数字6的符号 102 f 小写字母 f
55 7 数字7的符号 103 g 小写字母 g
56 8 数字8的符号 104 h 小写字母 h
57 9 数字9的符号 105 i 小写字母 i
58 : 冒号 106 j 小写字母 j
59 ; 分号 107 k 小写字母 k
60 < 小于 108 l 小写字母 l
61 = 等号 109 m 小写字母 m
62 > 大于 110 n 小写字母 n
63 ? 问号 111 o 小写字母 o
64 @ 电子邮件符号 112 p 小写字母 p
65 A 大写字母 A 113 q 小写字母 q
66 B 大写字母 B 114 r 小写字母 r
67 C 大写字母 C 115 s 小写字母 s
68 D 大写字母 D 116 t 小写字母 t
69 E 大写字母 E 117 u 小写字母 u
70 F 大写字母 F 118 v 小写字母 v
71 G 大写字母 G 119 w 小写字母 w
72 H 大写字母 H 120 x 小写字母 x
73 I 大写字母 I 121 y 小写字母 y
74 J 大写字母 J 122 z 小写字母 z
75 K 大写字母 K 123 { 左大括号
76 L 大写字母 L 124 | 竖线
77 M 大写字母 M 125 } 右大括号
78 N 大写字母 N 126 ~ 波浪号
79 O 大写字母 O 127   删除
a)32是空格。
b)48~57是0到9十个阿拉伯数字;
c)65~90是26个大写英文字母;
d)97~122号是26个小写英文字母;
e)其余的是一些标点符号、运算符号等;
f)第127个字符表示的是键盘上的删除键。
3)字符的本质
a)字符的本质是整数,取值范围是0~127。
b)在书写的时候可以用单引号包含,也可以用整数。
c)如果书写的时候用单引号包含,程序执行的时候,将把符号解释为对应的整数。
d)显示的时候,把整数解释为对应的符号,也可以直接显示整数。
d)可以与整数进行任何运算,运算的时候,书写方式可以用字符,也可以用整数。
e)C++为什么没有提供1字节的整型?
f)字符型也可以用unsigned修饰,意义何在?
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 字符型(char)占用的内存空间是1个字节,书写用单引号包含。
int a = ‘X’;
cout << “a=” << a << endl;
cout << “sizeof(a)=” << sizeof(a) << endl;
// 1234567 00000000 00010010 11010110 10000111
// ‘X’ -> 88 ‘a’->97 ‘3’->51
}

44、转义字符
在C++程序中,使用转义字符的原因有两个:
 控制字符没有符号,无法书写,只能用其它的符号代替。
 某些符号已被C++征用,语义冲突,只能用其它的符号代替。
ASCII码值 转义字符 含义
0 \0 空,给字符型变量赋值时可以直接书写0。
10 \n 换行(LF) ,将当前位置移到下一行开头。
13 \r 回车(CR) ,将当前位置移到本行开头
9 \t 水平制表(HT) (跳到下一个TAB位置)
92 \ 斜线
34 " 双引号,书写字符时不必转义。
39 ’ 单引号,书写字符串中不必转义。
7 \a 警报
8 \b 退格(BS) ,将当前位置移到前一列
12 \f 换页(FF),将当前位置移到下页开头
11 \v 垂直制表(VT)
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 字符型(char)占用的内存空间是1个字节,书写用单引号包含。
char a = ‘’';
cout << “a=” << a << endl;

// 换行符 ASCII值是10  书写用\n
cout << "我是一'只傻傻鸟!\n";

// 水平制表符用于对齐输出的内容。
cout << "1\t西施\n";
cout << "100\t西瓜\n";
cout << "10000\t冰冰\n";

}

45、C++11的原始字面量
原始字面量(值)可以直接表示字符串的实际含义,不需要转义和连接。
语法:R"(字符串的内容)"
R"xxx(字符串的内容)xxx"
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 使用转义的方法
string path = “C:\Program Files\Microsoft OneDrive\tail\nation”;
cout << "path is " << path << endl;

// 使用C++11原始字面量
string path1 = R"abcd(C:\Program Files\Microsoft OneDrive\tail\nation)abcd";
cout << "path1 is " << path1 << endl;

string str = R"(
    <no>0001</no>
    <name>西施</name>
    <sc>火树银花</sc>
    <yz>沉鱼</yz>
    <age>23</age>
    <weight>48.5</weight>
    <height>170</height>)";
cout << str << endl;

}

46、字符串型
C++风格字符串:string 变量名=“字符串的内容” ;
C风格字符串:char 变量名[]=“字符串的内容” ;
C风格字符串的本质是字符数组,C++风格字符串的本质是类,它封装了C风格字符串。
 C++风格字符串的常用操作:
 赋值:变量名=“字符串的内容” ;
 拼接:变量名=变量名+“字符串的内容一”+“字符串的内容一”+…+“字符串的内容n” ;
如果字符串的内容都是常量,不要写加号(+),如果内容很长,可以分成多行书写。
 比较:支持==、!=、>和<关系运算符,常用的是==和!=。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
string str=“西施”; // 声明字符串变量并初始化。

str = "美女西施";                    // 对字符串变量重新赋值。

cout << "请输入超女姓名:";         // 输出提示文字内容。
cin >> str;                                       // 从控制台输入数据,保存在变量str中。 

if (str == "冰冰")  cout << "我喜欢\n";           // 用==可以判断两个字符串是否相同。

if (str != "冰冰") cout << "我不玩了\n";          // 用!=可以判断两个字符串是否不相同。

str = "姓名:" + str + ",这是我现女友。";     // 用+可以拼接多个字符串。

// 如果字符串的内容都是常量,不要写加号(+),如果内容很长,可以分成多行书写。
str = "超女姓名:" 
	"幂幂" 
	",这是我的前女友。";

cout << str << endl;

}
47、布尔型
在C和C++中,关系运算和逻辑运算的结果有两种:真和假。
C语言用0表示假,非0表示真。
为了提高代码的可读性,C++新增了 bool 类型,占用1字节的内存,用true表示真,false表示假。
bool类型本质上是1字节的整数(unsigned char),取值只有1和0。
在程序中,书写的时候可以用true和false,编译器把它们解释为1和0。
如果对bool型变量赋非0的值,将转换成1。
用cin输入和cout输出的时候,仍是1和0,不会被解释为true和false。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
bool b = 1;

cout << "b+b=" << b+b << endl;       // 将显示2。

// 如果对bool型变量赋非0的值,将转换成1。
b = 30;
cout << "b=" << b << endl;                 // 将显示1。

// 找到布尔变量b的内存,把里面的数据强制为8。
char* c = (char *) & b; 
*c = 8;
cout << "b=" << b << endl;                 // 将显示8。

}

48、数据类型的转换
计算机进行运算时,要求各操作数的类型具有相同的大小和存储方式。
在实际开发中,不同类型的数据进行混合运算是基本需求。
自动类型转换:某些类型的转换编译器可以隐式的进行,不需程序员干预。
强制类型转换:有些类型的转换需要程序员显式指定。
1)自动类型转换
不同数据类型的差别在于取值范围和精度,数据的取值范围越大,精度越高。
整型从低到高:
char -> short -> int -> long -> long long
浮点型从低到高:
float -> double -> long double
自动类型转换的规则如下:
 如果一个表达式中出现了不同类型操作数的混合运算,较低类型将自动向较高类型转换。
 当表达式中含有浮点型操作数时,所有操作数都将转换为浮点型。
 赋值运算的右值类型与左值类型不一致时,将右值类型提升/降低为左值类型。
 赋值运算右值超出了左值类型的表示范围,把该右值截断后赋给左值,所得结果可能毫无意义。
2)强制类型转换
为了让程序设计更灵活,转换的目的更清晰,C++提供了强制类型转换的方法,也称之为显式转换。
强制类型转换的语法:(目标类型)表达式或目标类型(表达式)
注意:
 如果使用强制转换,表示程序员已有明确的目的。
 如果转换的行为不符合理,后果由程序员承担。
 如果采用了强制类型转换,编译的告警信息将不再出现。
 类型转换运算符的优先级比较高,如果没把握就加括号。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
char a = 30;
int b = 102400;
long long c = 15000000000001;

// 如果一个表达式中出现了不同类型操作数的混合运算,较低类型将自动向较高类型转换。
cout << "a+b+c=" << a + b + c << endl;

// 当表达式中含有浮点型操作数时,所有操作数都将转换为浮点型。
cout << "8/5=" << ((double)8) / 5 << endl;

// 赋值运算的右值类型与左值类型不一致时,将右值类型提升/降低为左值类型。
// 赋值运算右值超出了左值类型的表示范围,把该右值截断后赋给左值,所得结果可能毫无意义。
int d = (int)23.59;        // 降低了精度。
cout << "d=" << d << endl;

unsigned int e = (unsigned int)4294967295+10;       // 值被截断,从高位截断
cout << "e=" << e << endl;
// 4294967295         11111111111111111111111111111111
// 4294967296 000100000000000000000000000000000000
// 4294967297 000100000000000000000000000000000001

}

49、数据类型的别名typedef
创建数据类型的别名有两个目的:
 为名称复杂的类型创建别名,方便书写和记忆。
 创建与平台无关的数据类型,提高程序的兼容性。
语法:typedef 原数据类型名 别名;
C++11还可以用using关键字创建数据类型的别名。
语法:using 别名=原数据类型名;
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 1)为名称复杂的类型创建别名,方便书写和记忆。
// 2)创建与平台无关的数据类型,提高程序的兼容性。
// 在VS中,short是两个字节,int是四个字节,long也是四个字节,long long是八个字节。
typedef short int16_t; // 16位的整数。
typedef int int32_t; // 32位的整数。
typedef long long int64_t; // 64位的整数。
// 在Linux中,short是两个字节,int是四个字节,long也是八个字节,long long也是八个字节。
typedef short int16_t; // 16位的整数。
typedef int int32_t; // 32位的整数。
typedef long int64_t; // 64位的整数。

// 在程序源代码中,只使用别名int16_t、int32_t、int64_t,不使用原名。

}

50、指针的基本概念
1)变量的地址
变量是内存变量的简称,在C++中,每定义一个变量,系统就会给变量分配一块内存,内存是有地址的。

C++用运算符&获取变量在内存中的起始地址。
语法:&变量名
2)指针变量
指针变量简称指针,它是一种特殊的变量,专用于存放变量在内存中的起始地址。
语法:数据类型 变量名;
数据类型必须是合法的C++数据类型(int、char、double或其它自定义的数据类型)。
星号
与乘法中使用的星号是相同的,但是,在这个场景中,星号用于表示这个变量是指针。
3)对指针赋值
不管是整型、浮点型、字符型,还是其它的数据类型的变量,它的地址都是一个十六进制数。我们用整型指针存放整数型变量的地址;用字符型指针存放字符型变量的地址;用浮点型指针存放浮点型变量的地址,用自定义数据类型指针存放自定义数据类型变量的地址。
语法:指针=&变量名;
注意
 对指针的赋值操作也通俗的被称为“指向某变量”,被指向的变量的数据类型称为“基类型”。
 如果指针的数据类型与基类型不符,编译会出现警告。但是,可以强制转换它们的类型。
4)指针占用的内存
指针也是变量,是变量就要占用内存空间。
在64位的操作系统中,不管是什么类型的指针,占用的内存都是8字节。
在C++中,指针是复合数据类型,复合数据类型是指基于其它类型而定义的数据类型,在程序中,int是整型类型,int是整型指针类型,int可以用于声明变量,可以用于sizeof运算符,可以用于数据类型的强制转换,总的来说,把int*当成一种数据类型就是了。

51、使用指针
声明指针变量后,在没有赋值之前,里面是乱七八糟的值,这时候不能使用指针。
指针存放变量的地址,因此,指针名表示的是地址(就像变量名可以表示变量的值一样)
*运算符被称为间接值或解除引用(解引用)运算符,将它用于指针,可以得到该地址的内存中存储的值,*也是乘法符号,C++根据上下文来确定所指的是乘法还是解引用。
变量和指向变量的指针就像同一枚硬币的两面。

哪个银行? 什么东西? 数额
程序在存储数据的时候,必须跟踪三种基本属性:
 数据存储在哪里;
 数据是什么类型;
 数据的值是多少。
用两种策略可以达到以上目的:
声明一个普通变量,声明时指出数据类型和变量名(符号名),系统在内部跟踪该内存单元。
声明一个指针变量,存储的值是地址,而不是值本身,程序直接访问该内存单元。

52、指针用于函数的参数
如果把函数的形参声明为指针,调用的时候把实参的地址传进去,形参中存放的是实参的地址,在函数中通过解引用的方法直接操作内存中的数据,可以修改实数的值,这种方法被通俗的称为地址传递或传地址。
值传递:函数的形参是普通变量。
传地址的意义如下:
 可以在函数中修改实参的值。
 减少内存拷贝,提升性能。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

// 调用函数的时候,调用者把数值赋给了函数的参数。
// 实参:调用者程序中书写的在函数名括号中的参数。
// 形参:函数的参数列表。
void func(int *no, string *str) // 向超女表白的函数。
{
cout << “亲爱的” << *no << “号:” << *str << endl;
*no = 8;
*str = “我有一只小小鸟。”;
}

// 写一个函数,从3名超女的身高数据中,选出最高的和最矮的。
void func1(int a, int b, int c, int* max, int* min)
{
*max = a > b ? a : b; // 取a和b中的大者。
*min = a < b ? a : b; // 取a和b中的小者。
*max = *max > c ? max : c; // 取max和c中的大者。
*min = *min < c ? min : c; // 取min和c中的大者。
}

int main()
{
int bh = 3; // 超女的编号。
string message = “我是一只傻傻鸟。”; // 向超女表白的内容。

func(&bh, &message);            // 调用向超女表白的函数。
/*{
	int *no = &bh;          
	string *str = &message; 

	cout << "亲爱的" << *no << "号:" << *str << endl;
	*no = 8;
	*str = "我有一只小小鸟。";
}*/

cout << "亲爱的" << bh << "号:" << message << endl;

// 从3名超女的身高数据中,选出最高的和最矮的。
int a = 180, b = 170, c = 175, m, n;
func1(a, b, c, &m, &n);
cout << "m=" << m << ",n=" << n << endl;

}

53、用const修饰指针
1)常量指针
语法:const 数据类型 *变量名;
不能通过解引用的方法修改内存地址中的值(用原始的变量名是可以修改的)。
注意:
 指向的变量(对象)可以改变(之前是指向变量a的,后来可以改为指向变量b)。
 一般用于修饰函数的形参,表示不希望在函数里修改内存地址中的值。
 如果用于形参,虽然指向的对象可以改变,但这么做没有任何意义。
 如果形参的值不需要改变,建议加上const修饰,程序可读性更好。
2)指针常量
语法:数据类型 * const 变量名;
指向的变量(对象)不可改变。
注意:
 在定义的同时必须初始化,否则没有意义。
 可以通过解引用的方法修改内存地址中的值。
 C++编译器把指针常量做了一些特别的处理,改头换面之后,有一个新的名字,叫引用。
3)常指针常量
语法:const 数据类型 * const 变量名;
指向的变量(对象)不可改变,不能通过解引用的方法修改内存地址中的值。
常引用。

常量指针:指针指向可以改,指针指向的值不可以更改。
指针常量:指针指向不可以改,指针指向的值可以更改。
常指针常量:指针指向不可以改,指针指向的值不可以更改。
记忆秘诀:*表示指针,指针在前先读指针;指针在前指针就不允许改变。
常量指针:const 数据类型 *变量名
指针常量:数据类型 * const 变量名

示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

void func(const int *no, const string *str) // 向超女表白的函数。
{
// *no = 8;
// *str = “我有一只小小鸟。”;
cout << “亲爱的” << *no << “号:” << *str << endl;
}

int main()
{
int a = 3, b = 8;

// 常量指针的语法:const 数据类型* 变量名;
// 不能通过解引用的方法修改内存地址中的值(用原始的变量名是可以修改的)。
/*const int* p = &a;
a = 13;
cout << "a=" << a << ",*p=" << *p << endl;
p = &b;
cout << "b=" << b << ",*p=" << *p << endl;*/

// 指针常量语法:数据类型* const 变量名;
// 指向的变量(对象)不可改变;在定义的同时必须初始化;可以通过解引用的方法修改内存地址中的值。
int* const p=&a;
*p = 13;
cout << "a=" << a << ",*p=" << *p << endl;

//int bh = 3;      // 超女的编号。
//string message = "我是一只傻傻鸟。";          // 向超女表白的内容。
//
//func(&bh, &message);            // 调用向超女表白的函数。

//cout << "亲爱的" << bh << "号:" << message << endl;

}

54、void关键字
在C++中,void表示为无类型,主要有三个用途:
1)函数的返回值用void,表示函数没有返回值。
void func(int a,int b)
{
// 函数体代码。
return;
}
2)函数的参数填void,表示函数不需要参数(或者让参数列表空着)。
int func(void)
{
// 函数体代码。
return 0;
}
3)的形参用void *,表示接受任意数据类型的指针。
注意:
 不能用void声明变量,它不能代表一个真实的变量,但是,用void *可以。
 不能对void 指针直接解引用(需要转换成其它类型的指针)。
 把其它类型的指针赋值给void
指针不需要转换。
 把void *指针赋值给把其它类型的指针需要转换。

示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

// 只关心地址本身,不关心里面的内容,用void *可以存放任意类型的地址。

// 显示变量的十六进制地址的函数:varname-变量名,p-变量的地址。
void func(string varname, void* p)
{
cout << varname<< “的地址是:” << p << endl;
cout << varname << “的值是:” << *(char *)p << endl;
}

int main()
{
int a=89;
char b=‘X’;

cout << "a的地址是:" <<  & a << endl;
cout << "b的地址是:" <<  & b << endl;

func("a", &a);
func("b", & b);

}

55、C++内存模型
在 C++ 中,程序运行时,内存主要分成四个区,分别是栈、堆、数据段和代码段。

栈:存储局部变量、函数参数和返回值。
堆:存储动态开辟内存的变量。
数据段:存储全局变量和静态变量。
代码段:存储可执行程序的代码和常量(例如字符常量),此存储区不可修改。

栈和堆的主要区别:
1)管理方式不同:栈是系统自动管理的,在出作用域时,将自动被释放;堆需手动释放,若程序中不释放,程序结束时由操作系统回收。
2)空间大小不同:堆内存的大小受限于物理内存空间;而栈就小得可怜,一般只有8M(可以修改系统参数)。
3)分配方式不同:堆是动态分配;栈有静态分配和动态分配(都是自动释放)。
4)分配效率不同:栈是系统提供的数据结构,计算机在底层提供了对栈的支持,进栈和出栈有专门的指令,效率比较高;堆是由C++函数库提供的。
5)是否产生碎片:对于栈来说,进栈和出栈都有着严格的顺序(先进后出),不会产生碎片;而堆频繁的分配和释放,会造成内存空间的不连续,容易产生碎片,太多的碎片会导致性能的下降。
6)增长方向不同:栈向下增长,以降序分配内存地址;堆向上增长,以升序分配内存地址。

56、动态分配内存new和delete
使用堆区的内存有四个步骤:
1)声明一个指针;
2)用new运算符向系统申请一块内存,让指针指向这块内存;
3)通过对指针解引用的方法,像使用变量一样使用这块内存;
4)如果这块内存不用了,用delete运算符释放它。
申请内存的语法:new 数据类型(初始值); // C++11支持{}
如果申请成功,返回一个地址;如果申请失败,返回一个空地址(暂时不考虑失败的情况)。
释放内存的语法:delete 地址;
释放内存不会失败(还钱不会失败)。
注意:
 动态分配出来的内存没有变量名,只能通过指向它的指针来操作内存中的数据。
 如果动态分配的内存不用了,必须用delete释放它,否则有可能用尽系统的内存。
 动态分配的内存生命周期与程序相同,程序退出时,如果没有释放,系统将自动回收。
 就算指针的作用域已失效,所指向的内存也不会释放。
 用指针跟踪已分配的内存时,不能跟丢。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

int main()
{
// 1)声明一个指针;
// 2)用new运算符向系统申请一块内存,让指针指向这块内存;
// 3)通过对指针解引用的方法,像使用变量一样使用这块内存;
// 4)如果这块内存不用了,用delete运算符释放它。
// 申请内存的语法:new 数据类型(初始值); // C++11支持{}
// 释放内存的语法:delete 地址;
int* p = new int(5);
cout << “*p=” << *p << endl;
*p = 8;
cout << “*p=” << *p << endl;
delete p;

/*	for (int ii = 1; ii > 0; ii++)
{
	int* p = new int[100000];     // 一次申请100000个整数,这个语法以后再讲。
	cout << "ii="<<ii<<",p=" << p << endl;
}/*

}
57、二级指针
指针是指针变量的简称,也是变量,是变量就有地址。
指针用于存放普通变量的地址。
二级指针用于存放指针变量的地址。
声明二级指针的语法:数据类型** 指针名;
使用指针有两个目的:1)传递地址;2)存放动态分配的内存的地址。
在函数中,如果传递普通变量的地址,形参用指针;传递指针的地址,形参用二级指针。
把普通变量的地址传入函数后可以在函数中修改变量的值;把指针的地址传入函数后可以在函数中指针的值。
示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。

void func(int **pp)
{
*pp = new int(3);
cout << “pp=” << pp << “,*pp=” << *pp << endl;
}

int main()
{
/int ii = 8; cout << “ii=” << ii << “,ii的地址是:” << &ii << endl;
int
pii = ⅈ cout << “pii=” << pii << “,pii的地址是:” << &pii << ",pii=" << pii << endl;
int
ppii = &pii; cout << “ppii=” << ppii << “,ppii的地址是:” << &ppii << “,*ppii=” << ppii << endl;
cout << “**ppii=” << **ppii << endl;
/

int* p=0;
func(&p);
/*{
	int** pp = &p;
	*pp = new int(3);
	cout << "pp=" << pp << ",*pp=" << *pp << endl;
}*/

cout << "p=" << p << ",*p=" << *p << endl;

}

58、空指针
在C和C++中,用0或NULL都可以表示空指针。
声明指针后,在赋值之前,让它指向空,表示没有指向任何地址。
1)使用空指针的后果
如果对空指针解引用,程序会崩溃。
如果对空指针使用delete运算符,系统将忽略该操作,不会出现异常。所以,内存被释放后,也应该把指针指向空。
在函数中,应该有判断形参是否为空指针的代码,目的是保证程序的健壮性。
为什么空指针访问会出现异常?
NULL指针分配的分区:其范围是从 0x00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。空指针是程序无论在何时都没有物理存储器与之对应的地址。为了保障“无论何时”这个条件,需要人为划分一个空指针的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值