《C++_primer5》
《effective C++》
《effectiveSTL》
《STL源码剖析》
《深度探索C++对象模型》
C++基础入门
1 C++初识
1.1 第一个C++程序
编写一个C++程序总共分为四个步骤:
- 创建项目
- 创建文件
- 编写代码
- 运行程序
1.1.1 创建项目
Visual Studio使我们用来编写C++程序的主要工具,先将它打开
1.1.2 创建文件
1.1.3 编写代码
#include<iostream>
using namespace std;
int main() {
cout << "hello word" << endl;
system("pause");
return 0;
}
1.1.4 运行程序
1.2 注释
作用:
在代码中添加一些说明和解释,方便自己或其他人阅读代码
两种格式
- 单行注释:
// 描述信息
通常放在一行代码的上方,或者一条语句的结尾,对该行代码的说明。 - 多行注释:
/* 描述信息 */
通常放在一段代码的上方,对该段代码做整体说明。
提示:编译器在编译代码时,会忽略注释的内容。
1.3 变量
作用
给一段指定的内存空间起名,方便操作这段内存
语法
数据类型 变量名 = 初始值;(int a = 0;)
示例:
#include<iostream>
using namespace std;
int main() {
// 变量的定义
// 变量类型 变量名=初始值;
int a = 2;
cout << "a = " << a << endl;
system("pause");
return 0;
}
1.4 常量
作用
用于记录不可修改的数据
两种定义方式
- #define 宏常量:
#define 常量名 常量值
通常在文件上方定义,表示一个常量 - const修饰的变量:
const 数据类型 常量名 = 常量值;
通常在变量定义前加关键字const,修饰该变量为常量,不可修改。
示例:
#include<iostream>
using namespace std;
// 宏常量
#define Day 7
int main() {
// Day = 14 // 错误,常量不可修改
cout << "一周一共有" << Day << "天" << endl;
const int month = 12;
// month = 24 //错误,const修饰的变量是常量,不可修改
cout << "一年有" << month << "月" << endl;
system("pause");
return 0;
}
1.5 关键字
作用
关键字是C++中预先保留的单词(标识符),在定义变量或者常量的时候,不允许用的。
C++关键字如下:
asm | do | if | return | typedof |
---|---|---|---|---|
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 |
提示:在给变量或者常量起名字的时候,不要用C++的关键字,否则会产生歧义。
1.6 标识符命名规则
作用
- 标识符不能是关键字
- 标识符只能由字母、数字、下划线组成
- 第一个字符必须为字母或者下划线
- 标识符区分大小写
给变量起名的时候,最好能做到见名知意,方便阅读。
2.数据类型
C++规定在创建一个变量或者常量时,必须要指定相应的数据类型,否则无法给变量分配内存。
2.1 整型
作用
整型变量表示的是整数类型的数据
几种方式
数据类型 | 占用空间 | 取值范围 |
---|---|---|
short(短整型) | 2字节 | (-2^15 ~ 2 ^15-1) |
int(整型) | 4字节 | (-2^31 ~ 2 ^15-1) |
long(长整型) | windows为4字节,Linux为4字节(32位),8字节(64位) | (-2^31 ~ 2 ^31-1) |
long long(长长整型) | 8字节 | (-2^63 ~ 2 ^63-1) |
#include<iostream>
using namespace std;
int main() {
// 整型
// 短整型 short (-32768~32767)
short num1 = 10;
// 整型 int
int num2 = 10;
// 长整型 long
long num3 = 10;
// 长长整型 long long
long long num4 = 10;
system("pause");
return 0;
}
2.2 sizeof关键字
作用
利用sizeof可以统计数据类型所占内存大小
语法
sizeof(数据类型/变量)
示例:
#include<iostream>
using namespace std;
int main() {
short num1 = 1;
cout << "short命名空间:" << sizeof(num1) << endl;
cout << "int命名空间:" << sizeof(int) << endl;
cout << "long命名空间:" << sizeof(long) << endl;
cout << "long long命名空间:" << sizeof(long long) << endl;
system("pause");
return 0;
}
2.3 实型(浮点型)
作用
用于表示小数
两种类型
- 单精度float
- 双精度double
两者区别
数据类型 | 占用空间 | 有效数据范围 |
---|---|---|
float | 4字节 | 7位有效数字 |
double | 8字节 | 15~16位有效数字 |
示例
#include<iostream>
using namespace std;
int main() {
// 单精度 float
// 双精度 double
// 默认情况下,输出一个小数,会显示6位有效数字
float f = 3.14f; // f不写就是double类型,需要转换成float类型
double d = 3.14;
cout << "f = " << f << endl;
cout << "d = " << d << endl;
// 统计float和double的内存空间
cout << "float内存空间:" << sizeof(float) << endl;
cout << "double内存空间:" << sizeof(double) << endl;
// 科学计数法
float f2 = 3e2; // 3*10^2
cout << "f2 = " << f2 << endl;
}
2.4 字符型
作用
用于显示单个字符
语法
char ch = ‘a’;
注意1:在显示字符型变量时,用单引号将字符括起来,不要用双引号。
注意2:单引号内只能有一个字符,不可以是字符串。
- C和C++中字符型变量占用1个字节
- 字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放到存储单元
示例
#include<iostream>
using namespace std;
int main() {
// 创建字符类型变量
char ch = 'a';
cout << "ch = " << ch << endl;
cout << "char占用内存空间:" << sizeof(char) << endl;
// char ch2 = "ab"; // 创建字符型类型变量,要用单引号且只有一个字符
// 字符型变量对应的ASCII编码
cout << (int)ch << endl;
system("pause");
return 0;
}
2.5 转义字符
作用
用于表示一些不能显示出来的ASCII字符
常用的转义字符有:\n \\ \t
#include<iostream>
using namespace std;
int main() {
// 换行符 \n
cout << "hello word\n" << endl;
// 反斜杠 \\
cout << "\\" << endl;
// 水平制表符 \t
cout << "hello\tword" << endl;
system("pause");
return 0;
}
2.6 字符串型
作用
用于表示一串字符
两种风格
-
c风格字符串:
char 变量名[] = "字符串值"
-
C++风格字符串:
string 变量名 = "字符串值"
示例:
#include<iostream>
#include<string> // c++风格的字符串需要加头文件
using namespace std;
int main() {
// c风格字符串
char str[] = "hello word"; // 变量名后面要有[], 必须是双引号
cout << str << endl;
// c++风格字符串
string str1 = "hello word"; // 要包含一个头文件 #include<string>
cout << str1 << endl;
system("pause");
return 0;
}
2.7 布尔类型
作用
代表真或者假的值
两个值
- true -----真 (本质是1)
- false-----假(本质是0)
bool类型占用1个字节
2.8 数据的输入
作用
用于从键盘获取数据
关键字:cin
语法:cin >> 变量
示例
#include<iostream>
#include<string>
using namespace std;
int main() {
// 输入整型
int a = 0;
cout << "输入一个整型" << endl;
cin >> a;
cout << "a = " << a << endl;
// 输入浮点型
float f = 3.14f;
cout << "输入一个浮点型数据" << endl;
cin >> f;
cout << "f = " << f << endl;
// 输入布尔类型
bool flag = false;
cout << "输入一个布尔类型" << endl;
cin >> flag;
cout << "flag = " << flag << endl;
system("pause");
return 0;
}
3 运算符
作用
用于执行代码的运算
几类运算符
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
3.1 算术运算符
作用
用于处理四则运算
加减乘除运算符
加 +
减 -
乘 *
除 /
示例
#include<iostream>
#include<string>
using namespace std;
int main() {
// 加减乘除
int a = 10;
int b = 3;
cout << a + b << endl;
cout << a - b << endl;
cout << a * b << endl;
// 两个整数相除,结果依然是整数,将小数部分去除
// 除数不可以为0
cout << a / b << endl;
system("pause");
return 0;
}
取模运算符
% ( 两个小数不可以做取模运算的)
示例
#include<iostream>
#include<string>
using namespace std;
int main() {
// 取模的本质就是取余
int a = 10;
int b = 20;
// 两个小数不可以做取模运算的
cout << a % b << endl;
system("pause");
return 0;
}
递增递减运算符
- 前置递增(++)
a = 2; b = ++ a; //结果a = 3; b=3
- 后置递增(++)
a = 2; b = a++; //结果a = 3; b=2
- 前置递减(–)
a = 2; b = --a; //结果a = 1; b=1
- 后置递减(–)
a = 2; b = a--; //结果a = 1; b=2
示例
#include<iostream>
#include<string>
using namespace std;
int main() {
// 前置递增 先增加后计算
int a = 10;
int a1 = ++a * 10;
cout << a << endl;
cout << a1 << endl;
// 后置递增 先计算后增加
int b = 10;
int b1 = b++ * 10;
cout << b << endl;
cout << b1 << endl;
system("pause");
return 0;
}
3.2 赋值运算
作用
用于将表达式的值赋给变量
几种符号
- =(赋值):
a=2; b=3; //a=2;b=3;
- +=(加等于):
a=0;b+=2; //a=2;
- -=(减等于):
a=5;a-=3 //a=2;
- *=(乘等于):
a=2;a*=2; //a=4;
- /=(除等于):
a=4;a/=2; //a=2;
- %=(模等于):
a=3;a%=2; //a=1;
3.3比较运算符
作用
用于表达式的比较,并返回一个真值或者假值
==(等于)
:4==3 结果:0
!=(不等于)
:4!3 结果:1
<(小于)
:4<3 结果:1
> (大于)
:4>3 结果:1
<= (小于等于)
:4<=3 结果:0
>= (大于等于)
:4>=3 结果1
3.4 逻辑运算符
作用
用于根据表达式的值返回真或者假
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果a为假,则!a为真;如果a为真,则!a为假 |
&& | 与 | a && b | 如果a和b都为真,则结果为真;否则为假 |
|| | 或 | a || b | 如果a和b有一个为真,则结果为真;二者都为假时,结果为假 |
4.流程控制结构
C/C++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构
- 顺序结构:程序顺序执行,不会发生跳转
- 选择结构:依据条件是否满足,有选择的执行相应的功能
- 循环结构:依据条件是否满足,循环多次执行某段代码
4.1 选择结构
4.1.1 if语句
作用
执行满足条件的语句
if语句的三种形式:
- 单行格式if语句
if(条件){ 条件满足执行的语句 }
- 多行格式if语句
if(条件){ 条件满足执行的语句 } else { 条件不足执行的语句 }
- 多条件的if语句
if(条件1){ 条件1满足执行的语句 } else if (条件2) { 条件2满足执行的语句 }... else {都不满足执行的语句}
- 嵌套if语句:在if语句中,可以嵌套if语句
学习案例
三只小猪称体重。有三只小猪ABC,请分别输入三只小猪的体重,并且判断哪只小猪最重?
#include<iostream>
using namespace std;
int main() {
// 三只小猪的体重
float num1 = 0l;
float num2 = 0l;
float num3 = 0l;
cout << "请输入小猪A的体重:";
cin >> num1;
cout << "请输入小猪B的体重:";
cin >> num2;
cout << "请输入小猪C的体重:";
cin >> num3;
//判断哪只小猪体重重
if (num1 > num2) // A比B重
{
if (num1 > num3)
{
cout << "小猪A最重" << endl;
}
else
{
cout << "小猪C最重" << endl;
}
}
else // B比A重
{
if (num2 > num3)
{
cout << "小猪B最重" << endl;
}
else
{
cout << "小猪C最重" << endl;
}
}
}
4.1.2 三目运算符
作用
通过三目运算符实现简单的判断
语法
表达式1 ? 表达式2 : 表达式3
如果表达式1为真,则执行表达式2; 否则执行表达式3;并返回表达式的结果
4.1.3 switch语句
作用
执行多条分支语句
语法
switch(表达式)
{
case 结果1:执行语句;break;
case 结果2:执行语句;break;
...
default: 执行语句;break;
}
switch语句结构清晰,执行效率高
switch语句中表达式类型只能是整型或者字符型
case中没有break,那么程序会一直向下执行
4.2 循环结构
4.2.1 while循环语句
作用
满足循环条件,执行循环语句
语法
while(循环条件){循环语句}
只要循环条件为真,就执行循环语句
注意:在执行循环语句的时候,程序必须提供跳出循环的出口,否则出现死循环
while循环联系案例:猜数字
系统随机生成一个1到100之间的数字,玩家进行猜测;如果猜错,提示玩家数字过大或者过小,如果猜对恭喜玩家胜利,并且退出游戏。
#include<iostream>
using namespace std;
int main()
{
srand((unsigned)time(0)); //time()用系统时间初始化种。为rand()生成不同的随机种子。
//系统随机生成随机数
int num = rand() % 100 + 1; // rand()%100随机生成0-99之间的数字
//玩家尽心猜测
int num1 = 0;
while (1)
{
cout << "请输入1-100之间的数字进行猜测:";
cin >> num1;
//判断玩家的猜测
if (num1 < num)
{
cout << "猜测的数字过小" << endl;
}
else if (num1 > num)
{
cout << "猜测的数字过大" << endl;
}
else
{
cout << "猜测正确" << endl;
// 跳出循环
break;
}
}
system("pause");
return 0;
}
4.2.2 do…while循环语句
作用
满足循环条件,执行循环条件
语法
do{ 循环语句 } while(循环条件);
注意:与while的区别在于do…while会先执行一次循环语句,再判断循环条件
学习案例:水仙花数
案例描述:水仙花数是指一个3位数,它的每个位上的数字3次幂之后等于它本身
例如:1^3 + 5^3 + 3^3 = 153
利用do…while语句,求出所有3位数的水仙花数
#include <iostream>
using namespace std;
int main()
{
// 输出所有三位数的水仙花数
int num = 100;
do
{
int a = num % 10; // 个位
int b = num / 10 % 10; // 十位
int c = num / 100; // 百位
// 判断是否是水仙花数
if (a*a*a + b*b*b + c*c*c == num)
{
// 输出水仙花数
cout << num << endl;
}
num++;
} while (num < 1000);
system("pause");
return 0;
}
4.2.3 for循环语句
作用
满足循环条件,执行循环语句
语法
for(起始表达式;条件表达式;末尾循环体) {循环体};
示例
#include <iostream>
using namespace std;
int main()
{
for (int i = 0; i < 10; i++)
{
cout << i << endl;
}
system("pause");
return 0;
}
学习案例:敲桌子
案例描述:从1开始数到数字100,如果数字个位含有7,或者十位含有7,或者该数字是7的倍数;我们打印敲桌子,其余数字直接打印输出。
#include<iostream>
using namespace std;
int main()
{
// 1-100之间的数字,如果是特殊数字,显示敲桌子
for (int i = 1; i <= 100; i++)
{
// 如果是7的倍数,或者个位是7,或者十位是7
if (i % 7 == 0 || i % 10 == 7 || i / 10 == 7)
{
cout << "敲桌子" << endl;
}
else
{
cout << i << endl;
}
}
system("pause");
return 0;
}
4.2.4 嵌套循环
作用
在循环体中再嵌套一层循环,解决一些实际问题
例如想在屏幕中打印如下图片,就需要利用嵌套循环
#include<iostream>
using namespace std;
int main()
{
// 嵌套循环
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << "* ";
}
cout << endl;
}
system("pause");
return 0;
}
练习案例:乘法口诀表
#include<iostream>
using namespace std;
#include<string>
int main()
{
// 嵌套循环
for (int i = 1; i < 10; i++)
{
for (int j = 1; j <= i; j++)
{
cout << j << "*" << i << "=" << j*i << "\t";
}
cout << endl;
}
system("pause");
return 0;
}
4.3 跳转语句
4.3.1 break语句
作用
用于跳出选择结构或者循环结构
break使用的时机
- 出现在switch条件语句中,作用是终止case并跳出switch
- 出现在循环语句中,作用是跳出当前的循环语句
- 出现在嵌套循环中,作用是跳出最近的内层循环语句
4.3.2 continue语句
作用
在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环
4.3.3 goto语句
作用
可以无条件跳转语句
语法
goto 标记;
解释:如果标记的名字存在,执行到goto语句时,会跳转到标记的位置
注意:在程序中不推荐使用
5.数组
5.1概述
所谓数组,就是一个集合,里面存放了相同类型的数据元素
特点1:数组中的每个数据元素都是相同的数据类型
特点2:数组是由连续内存
位置组成的
5.2 一维数组
5.2.1 一维数组定义方式
一维数组定义的三种方式:
数据类型 数组名[数组长度];
数据类型 数组名[数组长度] = {值1, 值2, ...};
数据类型 数组名[] = {值1, 值2, ...};
5.2.2 一维数组数组名
一维数组名的用途:
- 可以统计整个数组在内存中的长度
- 可以获取数组在内存中的首地址
#include<iostream>
using namespace std;
int main()
{
// 通过数组名统计整个数组占用内存大小
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
cout << "整个数组占用的内存空间" << sizeof(arr) << endl;
cout << "每个元素占用的内存空间" << sizeof(arr[0]) << endl;
cout << "数组中元素个数" << sizeof(arr) / sizeof(arr[0]) << endl;
// 通过数组名查看首地址
cout << "数组首地址" << (int)arr << endl;
cout << "数组第一个元素地址" << (int)&arr[0] << endl;
cout << "数组第二个元素地址" << (int)&arr[1] << endl;
// 数组名是常数,不可以进行赋值操作
// arr = 100;
system("pause");
return 0;
}
5.3 二维数组
二维数组就是在一维数组上,多加一个维度。
5.3.1 二维数组定义方式
二维数组定义的四种方式:
数组类型 数组名[行数][列数];
数组类型 数组名[行数][列数] = {{数据1, 数据2}, {数据3, 数据4}};
数组类型 数组名[行数][列数] = {数据1, 数据2, 数据3, 数据4};
数组类型 数组名[][列数] = {数据1, 数据2, 数据3, 数据4};
建议:以上四种定义方式,利用
第二种更加直观,提高代码可读性
。
5.3.2 二维数组数组名
- 查看二维数组的内存空间
- 获取二维数组的首地址
案例:考试成绩统计
案例描述:有三名同学,在一次考试成绩如下,请分别输出三名同学的总成绩。
语文 数学 英语 张三 100 100 100 李四 90 50 100 王五 60 70 80
#include<iostream>
using namespace std;
int main()
{
//案例-考试成绩统计
int scores[3][3] = {
{100, 100, 100},
{90, 50, 100},
{60, 70, 80}
};
string names[3] = { "张三", "李四", "王五" };
// 统计每个人的总成绩
for (int i = 0; i < 3; i++)
{
int sum = 0; // 每个人的分数总和
for (int j = 0; j < 3; j++)
{
sum += scores[i][j];
}
cout << names[i] << "的总成绩为:" << sum << endl;
}
system("pause");
return 0;
}
6.函数
6.1 概述
作用
将一段经常使用的代码封装起来,减少重复代码;一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
6.2 函数的定义
函数的定义一般分为5个步骤:
- 返回值类型 :一个函数可以返回一个值
- 函数名:给函数起个名字
- 参数列表:使用该函数时,传入的参数
- 函数体语句:花括号内的代码,函数内需要执行的语句
- return 表达式:和返回值类型挂钩,函数执行完后,返回相应的数据
语法
返回值类型 函数名(参数列表)
{
函数体语句;
return 表达式;
}
示例:定义一个加法函数,实现两个数相加
#include<iostream>
using namespace std;
// 加法函数,实现两个整型相加并将返回值返回
int add(int num1, int num2)
{
int sum = num1 + num2;
return sum;
}
int main()
{
system("pause");
return 0;
}
6.3 函数的调用
功能
使用定义好的函数
语法
函数名(参数)
#include<iostream>
using namespace std;
// 加法函数,实现两个整型相加并将返回值返回
// num1,num2是形参
int add(int num1, int num2)
{
int sum = num1 + num2;
return sum;
}
int main()
{
// 调用加法函数,参数是实参
int sum = add(1, 2);
cout << sum << endl;
system("pause");
return 0;
}
6.4 值传递
- 所谓值传递,就是函数调用时,实参将数值传入给形参
- 值传递时,如果
形参发生改变,并不会影响到实参
示例
#include<iostream>
using namespace std;
// 交换函数,实现两个整型数字进行交换
// void是无返回值
void swap(int num1, int num2)
{
int temp = num1;
num1 = num2;
num2 = num1;
// return; // return是可以不需要的
}
int main()
{
int a = 10;
int b = 20;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
// 值传递的时候,形参发生任何改变都不会影响到实参
swap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
system("pause");
return 0;
}
6.5 函数的常见样式
常见的函数样式有4种
- 无参无返 :
void test(){}
- 有参无返 :
void test(int a){}
- 无参有返 :
int test(){reurn 10;}
- 有参有返 :
int test(int a){return a;}
6.6 函数的声明
作用
告诉编译器函数名称以及如何调用函数。函数的实际主体可以单独定义。
函数的声明可以多次,但是函数的定义只能有一次
函数的定义在main函数的后面就需要函数的声明
6.7 函数的分文件编写
作用
让代码结构更加清晰
函数分文件编写一般有4个步骤
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明
- 在源代码中写函数的定义
7 指针
7.1 指针的基本概念
指针的作用
可以通过指针间接访问内存
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
7.2 指针变量的定义和使用
语法
数据类型 * 变量名;
7.3 指针所占用的内存空间
- 32位操作系统,指针占4个内存空间
- 64位操作系统,指针占8个内存空间
7.4 空指针和野指针
空指针
指针变量指向内存中编号为0的空间
用途
初始化指针变量
空指针指向的内存是不可以访问的
野指针
指针变量指向非法的内存空间
空指针和野指针都不是我们申请的空间,因此不要访问。
7.5 const修饰指针
const修饰指针有3种情况
- const修饰指针 ---- 常量指针
- const修饰常量 ---- 指针常量
- const即修饰指针,又修饰常量
技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量
7.1 指针和数组
作用
利用指针访问数组中元素
7.7 指针和函数
作用
利用指针作函数参数,可以修改实参的值
如果不想改变实参就是值传递;如果想改变实参就用地址传递
8 结构体
8.1 结构体基本概念
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
8.2 结构体定义和使用
语法
struct 结构体名{结构体成员列表};
通过结构体创建变量的方式有3种
- struct 结构体名 变量名
- struct 结构体名 变量名 = {成员1值, 成员2值…}
- 定义结构体时顺便创建变量
总结1:定义结构体时的关键字struct,不可忽略;
总结2:创建结构体变量时,关键字struct可以忽略;
总结3:结构体变量利用操作符"."访问成员
8.3 结构体数组
作用
将自定义的结构体放入到数组中方便维护
语法
struct 结构体名 数组名[元素个数] = {{}, {}, ... {}}
8.4 结构体指针
作用
通过指针访问结构体中的成员
利用操作符
->
可以通过结构体指针访问结构体属性
8.5 结构体嵌套结构体
作用
结构体中的成员可以是另一个结构体
例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体
8.6 结构体做函数参数
作用
将结构体