引用

1. 引用的基本使用

  • 作用:给变量起别名
  • 语法:数据类型 &别名 = 原名
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
using namespace std;
int main() {
int a = 10;
int& b = a;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

cout << "通过引用修改后:" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}

运行结果:

1
2
3
4
5
a = 10
b = 10
通过引用修改后:
a = 10
b = 10

2. 引用注意事项

  • 引用必须初始化
  • 引用在初始化后,不可以修改
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
int main() {
//int& b;//报错,引用必须初始化
int a = 10;
int b = 10;
int& c = a;
c = b;//这是赋值操作,而不是更改引用
cout << "c = " << c << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}

运算结果:

1
2
3
c = 10
a = 10
b = 10

3. 引用做函数参数

  • 作用:函数传参时,可以利用引用的技术让形参修饰实参
  • 优点:可以简化指针修改实参

示例:值传递、地址传递、引用传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<iostream>
using namespace std;
//交换函数
//1、值传递
void Swap01(int a, int b) {
int temp = a;
a = b;
b = temp;
}
//2、地址传递
void Swap02(int* a, int* b) {
int temp = *a;
* a = *b;
* b = temp;
}
//3、引用传递,形参是实参的别名,所以可以将实参数据交换
void Swap03(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}

int main() {
int a = 10;
int b = 20;
//值传递
Swap01(a, b);
cout << "值传递交换" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

//地址传递
cout << "\n地址传递交换" << endl;
Swap02(&a, &b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;

//引用传递
Swap03(a, b);
cout << "\n引用传递交换" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

return 0;
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
值传递交换
a = 10
b = 20

地址传递交换
a = 20
b = 10

引用传递交换
a = 10
b = 20

4. 引用做函数返回值

  • 作用:引用是可以作为函数的返回值存在的
  • 注意:不要返回局部变量引用
  • 用法:函数调用作为左值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
using namespace std;
int& test01() {
int a = 10;//存放在栈区
return a;//返回局部变量的引用
}
int& test02() {
static int a = 10;//静态变量,存放在全局区,在程序结束后由系统释放
return a;
}
int main() {
int& ref = test01();
cout << "ref = " << ref << endl;//第一次输出正确,编译器做了一次保留
cout << "ref = " << ref << endl;//第二次结果错误,因为 a 的内存已经释放

int& ref2 = test02();
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;//输出正确
//函数的返回值是引用,那么函数调用可以作为左值
test02() = 1000;//相当于是 a = 1000,ref2 = 1000
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;//输出正确
return 0;
}

运行结果:

1
2
3
4
5
6
ref = 10
ref = 2056567184
ref2 = 10
ref2 = 10
ref2 = 1000
ref2 = 1000

5. 引用的本质

  • 本质:引用的本质在c++内部实现是一个指针常量。
1
2
3
4
5
6
7
8
9
10
11
#include<iostream>
using namespace std;
int main() {
int a = 10;
//自动转化为 int* const b = &a;指针常量是指针指向不可改,所以引用不可改
int& b = a;
cout << "a = " << a << endl;
b = 20;//内部发现b是引用,自动帮我们转换为:*b = 20;
cout << "b = " << b << endl;
return 0;
}

6.常量引用

  • 作用:常量引用主要用来修饰形参,防止误操作

    在函数形参列表中和,可以加const修饰形参,防止形参改变实参

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
using namespace std;
//打印数据
void show(const int& val) {
//val = 100;//报错,不可以修改,所以加const可以防止误操作
cout << val << endl;
}
int main() {
int a = 10;
cout << "a = " << a << endl;
//int& ref = 10;//报错,引用必须是一块合法的内存空间,栈区或者堆区
const int& ref = 10;//加上const之后,编译器将代码修改为 int temp = 10;const int &ref = temp;
//ref = 20;报错,加入const之后变为只读,不可以修改
show(a);
return 0;
}

内存分区模型

1. 内存分区模型

  • c++程序在执行时,将内存分为四个区域

    代码区:存放函数体的二进制代码,由操作系统进行管理。

    全局区:存放全局变量和静态变量以及常量。

    栈区:由编译器自动分配释放,存放函数的参数值,局部变量等。

    堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

  • 内存四区意义

    不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

2. 程序执行前

在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域

  • 代码区

    存放CPU执行的机器指令

    代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。

    代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令

  • 全局区

    全局区存放全局变量、静态变量、常量

    常量区存放const修饰的全局变量和字符串常量

    该区域的数据在程序结束后由操作系统释放

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
using namespace std;

//全局变量
int g_a = 10;
int g_b = 10;
//全局常量
const int c_g_a = 10;
const int c_g_b = 10;
int main() {
//局部变量
int a = 10;
int b = 10;
cout << "局部变量a的地址" << (int)&a << endl;
cout << "局部变量b的地址" << (int)&b << endl;
//全局变量
cout << "全局变量g_a的地址" << (int)&g_a << endl;
cout << "全局变量g_b的地址" << (int)&g_b << endl;
//静态变量 在普通变量前加static
static int s_a = 10;
static int s_b = 10;
cout << "静态变量s_a的地址" << (int)&s_a << endl;
cout << "静态变量s_b的地址" << (int)&s_b << endl;

//常量
//字符串常量
cout << "字符串常量的地址为:" << (int)&"hello world" << endl;
//const修饰的全局常量
cout << "const修饰的全局常量c_g_a的地址:" << (int)&c_g_a << endl;
cout << "const修饰的全局常量c_g_b的地址:" << (int)&c_g_b << endl;

//const修饰的局部变量
const int c_l_a = 10;
const int c_l_b = 10;
cout << "const修饰的局部常量c_l_a的地址:" << (int)&c_l_a << endl;
cout << "const修饰的局部常量c_l_b的地址:" << (int)&c_l_b << endl;

return 0;

}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
局部变量a的地址-552600588
局部变量b的地址-552600556
全局变量g_a的地址898355200
全局变量g_b的地址898355204
静态变量s_a的地址898355208
静态变量s_b的地址898355212
字符串常量的地址为:898346584
const修饰的全局常量c_g_a的地址:898345904
const修饰的全局常量c_g_b的地址:898345908
const修饰的局部常量c_l_a的地址:-552600524
const修饰的局部常量c_l_b的地址:-552600492

3.程序运行后

  • 栈区

    由编译器自动分配释放,存放函数的参数值、局部变量等

    注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
using namespace std;
int* func() {
int a = 10;//局部变量,存放在栈区,此函数执行完后自动释放
return &a;//返回局部变量的地址
}
int main() {
int* p = func();
cout << *p << endl;//第一次可以正确输出10,编译器做了一次保留
cout << *p << endl;//第二次这个数据就不再保留了
return 0;
}

运行结果:

1
2
10
-858993460
  • 堆区

    由程序员分配释放,若程序员不释放,程序结束时由操作系统回收

    在c++中主要利用new在堆区开辟内存

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
using namespace std;
int b = 10;
int* func() {
//1、利用new关键字,可以将数据开辟到堆区
//2、指针本质也是局部变量,放在栈上,函数执行完自动销毁
//3、如果局部变量的指针指向的数据放在堆区或者全局区,程序执行结束前不会自动回收,所以可以正常输出
int* p = new int(10);
//int* p = &b;
return p;
}
int main() {
int* p = func();
cout << *p << endl;
cout << *p << endl;
return 0;
}

运行结果:

1
2
10
10

3. new操作符

  • c++中利用new操作符在堆区中开辟数据

    堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete

    利用new创建的数据,会返回该数据对应类型的指针

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
int* func() {
int* p = new int(10);
return p;
}
void func2() {
//在堆区开辟数组
int* arr = new int[10];
for (int i = 0;i < 10;i++) {
arr[i] = i;
}
for (int i = 0;i < 10;i++)
{
cout << arr[i] << " ";
}
delete[]arr;
}
int main() {
int* p = func();
cout << *p << endl;
//堆区数据释放
delete p;
//cout << *p << endl;引发异常:读取访问权限冲突
func2();
return 0;
}

运行结果:

1
2
10
0 1 2 3 4 5 6 7 8 9

结构体

1.结构体定义和使用

  • 语法:struct 结构体名 { 结构体成员列表 };

  • 通过结构体创建变量的方式

    (1) struct 结构体名 变量名

    (2) struct 结构体名 变量名 = { 成员1值,成员2值…. };

    (3) 定义结构体时顺便定义结构体变量

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include <cstring>
using namespace std;
struct student
{
string name;
int age;
}stu3;//定义结构体时顺便定义结构体变量
int main() {
//(1) struct 结构体名 变量名
struct student stu1;
stu1.age = 19;
stu1.name = "hanxiaoxuan";
cout << "stu1的信息:" << endl;
cout << "name:" << stu1.name << "\tage:" << stu1.age << endl;
//(2) struct 结构体名 变量名 = { 成员1值,成员2值.... };
struct student stu2 = { "hxx",19 };
cout << "stu2的信息:" << endl;
cout << "name:" << stu2.name << "\t\tage:" << stu2.age << endl;

//(3) 定义结构体时顺便定义结构体变量
stu3.age = 20;
stu3.name = "hhh";
cout << "stu3的信息:" << endl;
cout << "name:" << stu3.name << "\t\tage:" << stu3.age << endl;
return 0;
}

运行结果:

1
2
3
4
5
6
stu1的信息:
name:hanxiaoxuan age:19
stu2的信息:
name:hxx age:19
stu3的信息:
name:hhh age:20

2. 结构体数组

  • 作用:将自定义的结构体放入到数组中方便维护
  • 语法:struct 结构体名 数组名[元素个数] = { {},{},{}…. };

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<cstring>
using namespace std;
struct student
{
string name;
int age;
};
int main() {
struct student arr[2] =
{
{"hxx",19},
{"hxs",20}
};
for (int i = 0;i < 2;i++) {
cout << "学生" << arr[i].name << "的年龄是" << arr[i].age << endl;
}
return 0;
}

运行结果:

1
2
学生hxx的年龄是19
学生hxs的年龄是20

3. 结构体指针

  • 作用:通过指针访问结构体中的成员
  • 利用 -> 操作符,可以通过结构体指针访问结构体属性

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
#include<cstring>
using namespace std;
struct student
{
string name;
int age;
};
int main() {
student arr[2] =
{
{"hxx",19},
{"hxs",20}
};
student* p = arr;
for (int i = 0;i < 2;i++) {
cout << "学生" << p->name << "的年龄是" << p->age << endl;
p++;
}
return 0;
}

运行结果:

1
2
学生hxx的年龄是19
学生hxs的年龄是20

4. 结构体嵌套结构体

  • 作用:结构体中的成员可以是另一个结构体

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<iostream>
#include<cstring>
using namespace std;
struct student
{
string name;
int age;
};
struct teacher
{
int id;
string name;
int age;
struct student stu;
};
int main() {
teacher t;
t.id = 1000;
t.name = "老王";
t.age = 45;
t.stu.age = 19;
t.stu.name = "小王";
cout << "老师姓名:" << t.name << " 老师编号:" << t.id<< "老师年龄:" << t.age
<< "\n辅导的学生姓名:" << t.stu.name << "年龄:" << t.stu.age << endl;
return 0;
}

运行结果:

1
2
老师姓名:老王 老师编号:1000老师年龄:45
辅导的学生姓名:小王年龄:19

5. 结构体做函数参数

  • 作用:将结构体作为参数向函数中传递
  • 传递方式:值传递、地址传递

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include<cstring>
using namespace std;
struct student
{
int age;
string name;
};
void print(student s);
void print1(const student* p);//将函数中的形参改为指针,可以减少内存,而且不会复制一个新的副本
int main() {
student stu;
stu.age = 19;
stu.name = "韩晓璇";
//值传递
print(stu);
cout << "在main函数中打印 姓名:" << stu.name << "年龄:" << stu.age << endl;
//地址传递
print1(&stu);
cout << "在main函数中打印 姓名:" << stu.name << "年龄:" << stu.age << endl;
return 0;
}
void print(student s) {
s.age = 22;
cout << "在子函数中打印 姓名:" << s.name << "年龄:" << s.age << endl;
}
void print1(const student* p) {
//p->age = 22;//加入const之后,一旦修改就会报错,防止误操作
cout << "在子函数2中打印 姓名:" << p->name << "年龄:" << p->age << endl;
}

运行结果:

1
2
3
4
在子函数中打印 姓名:韩晓璇年龄:22
在main函数中打印 姓名:韩晓璇年龄:19
在子函数2中打印 姓名:韩晓璇年龄:22
在main函数中打印 姓名:韩晓璇年龄:22

指针

1. 指针定义和使用

  • 每一个变量都有一个内存地址,每一个内存地址都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。

  • 指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。使用指针之前需要先对其声明。指针变量的声明形式为:

    数据类型 *指针名。

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
int main() {
//1、定义指针,数据类型 *指针名
int a = 10;
int* p;
p = &a;//让指针记录a的地址

//int *p = &a;

cout << "a的地址为:" << &a << endl;
cout << "指针p为:" << p << endl;

//2、使用指针
//可以使用解引用的方式来找到指针所指的数据
*p = 1000;
cout << "a = " << a << endl;
cout << "*p = " << *p << endl;
return 0;
}

运行结果为:

1
2
3
4
a的地址为:0096FC40
指针p为:0096FC40
a = 1000
*p = 1000

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
int main() {
int* p = (int *)0x1100;//随意指定一个内存地址为0x1100
//将地址0x1100保存在指针p中,即p = 0x1100
//(int *)表示将地址强制转换成int指针类型,这样对p操作时就会以int方式存储
cout << p << endl;

int a = 10;
int* pc = &a;
int* pp = (int *)&a;

cout << "pc = " << hex << pc << endl;
cout << "pp = " << hex << pp << endl;
return 0;
}

运行结果:

1
2
3
00001100
pc = 00DCFE18
pp = 00DCFE18

2. 指针所占内存空间

​ 指针的值是一个代表内存地址的十六进制数,所占空间大小在32位操作系统下,占用四个字节;64位操作系统中占用8个字节。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
int main() {
int a = 10;
int *p = &a;

cout << "sizeof(p) = " << sizeof(p) << endl;
cout << "sizeof(int *) = " << sizeof(int *) << endl;
cout << "sizeof(float *) = " << sizeof(float *) << endl;
cout << "sizeof(double *) = " << sizeof(double *) << endl;
cout << "sizeof(char *) = " << sizeof(char *) << endl;

return 0;
}

运行结果:

1
2
3
4
5
sizeof(p) = 4
sizeof(int *) = 4
sizeof(float *) = 4
sizeof(double *) = 4
sizeof(char *) = 4

3. 空指针

空指针:指针变量指向内存中编号为0的空间

用途:初始化指针变量

注意:空指针指向的内存不可以访问,0~255之间的内存编号是系统占用的,因此不可以访问。

示例:

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
int main() {
int* p = NULL;
cout << p << endl;
//cout << *p << endl;//引发了异常: 读取访问权限冲突。p是nullptr。
return 0;
}

运行结果:

1
00000000

4. 野指针

野指针:指针变量指向非法的内存空间

示例:

1
2
3
4
5
6
7
#include <iostream>
using namespace std;
int main() {
int* p = (int *)0x1100;//随意指定一个内存地址为0x1100
//cout << *p << endl;引发了异常: 读取访问权限冲突。p是0x1100。
return 0;
}

5. const修饰指针

  • 常量指针:const修饰指针

    特点:指针的指向可以修改,但是不可以通过指针来修改它指向的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 10;
const int* p;
p = &a;
cout << "*p = " << *p << endl;
p = &b;
cout << "*p = " << *p << endl;
//*p = 10;错误,不可以修改常量指针指向的值的内容
a = 20;
cout << "*p = " << *p << endl;
return 0;
}

运行结果:

1
2
3
*p = 10
*p = 10
*p = 10
  • 指针常量:const修饰常量

    特点:指针本身是常量,不可以修改,但是指针指向的值可以修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
//int* const pp;//报错,常量需要设定初始值
int* const p = &a;
//p = &b;//报错,指针是常量,不可以修改
*p = 20;

cout << "*p修改前"<<endl<<"a = " << a << endl;
cout << "*P修改后" << endl;
cout << "*p = " << *p << endl;
cout << "a = " << a << endl;
return 0;
}

运行结果:

1
2
3
4
5
*p修改前
a = 20
*P修改后
*p = 20
a = 20
  • const既修饰指针,又修饰常量

    特点:指针指向的值、指针的指向均不可以改变

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
const int* const p = &a;
//p = &b;//报错,不可修改
//*p = 10;//报错,不可修改
return 0;
}
  • 记忆技巧

    (1) const = 常量,* = 指针。

    (2) const 紧挨谁,谁不能修改。

    如:const int* p :常量指针,const 紧挨 int*,所以 *p 不可以改。

    ​ int* const p :指针常量,const紧挨 p,所以 p 不可以修改。

6.指针和数组

  • 作用:利用指针访问数组

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
using namespace std;
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//利用指针访问数组中的元素
//创建int型指针
int* p = arr;//arr是数组的首地址
cout << "数组首地址:" << arr << endl;
cout << "p = " << p << endl;
cout << "arr[0] = " << *p << endl;
p++;//指针向后偏移四个字节
cout << "指针加一后" << endl;
cout << "p = " << p << endl;
cout << "arr[1] = " << *p << endl;

//利用指针遍历数组
p = arr;
for (int i = 0;i < 10;i++) {
cout << *p << " ";
p++;
}
cout << endl;
return 0;
}

运行结果:

1
2
3
4
5
6
7
数组首地址:0057F9C4
p = 0057F9C4
arr[0] = 1
指针加一后
p = 0057F9C8
arr[1] = 2
1 2 3 4 5 6 7 8 9 10

7. 指针和函数

  • 作用:利用指针做函数参数,可以修改实参的值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>
using namespace std;
void Swap(int* a, int* b);
int main() {
int a = 10;
int b = 20;
cout << "交换前:" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

Swap(&a, &b);//地址传递
cout << "交换后:" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

return 0;
}
void Swap(int* a, int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}

运行结果:

1
2
3
4
5
6
交换前:
a = 10
b = 20
交换后:
a = 20
b = 10

8.指针、函数、数组案例

  • 封装一个函数,利用冒泡排序,实现对整型数组的升序排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
void BubbleSort(int *arr,int len);
int main() {
int arr[10] = { 2,1,4,3,6,5,7,9,8,10 };
int len = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, len);
for (int i = 0;i < len;i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
void BubbleSort(int* arr, int len) {
int* p = arr;
int temp;
for (int i = 0;i < len;i++) {
p = arr;//每趟排序都从头开始
for (int j = 0;j < len - 1 - i;j++) {
//相邻两个元素比较
if (*p > *(p+1)) {
temp = *p;
*p = *(p+1);
*(p+1) = temp;
}
//指针后移
p++;
}
}
}

运行结果:

1
1 2 3 4 5 6 7 8 9 10

c++初始记录

1. 常量

使用define或者const来定义常量。
示例1:#define 宏常量

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
#define DAY 7
int main(){
//DAY = 14; //报错,DAY是常量,一旦修改会出现错误。
cout << "一周共有:" << DAY << "天" << endl;
return 0;
}

示例2:const修饰

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
int main() {
const int month = 12;
//month = 1; //报错,常量不可修改
cout << "一年有" << month << "月" << endl;
return 0;
}

2. 数据类型

2.1 整型

  • short 2字节
  • int 4字节
  • long windows为4字节,Linux:4字节(32位),8字节(64位)
  • long long 8字节

2.2 实型(浮点型)

  • float 4字节 7位有效数字
    float f2 = 3.14f;//不加f 默认3.14是double型,然后将其转化为float。
  • double 8字节 15~16位有效数字
  • 此处有效数字范围不区分小数点前后,默认情况下输出一个小数时显示6位数字。

2.3 科学计数法

  • float f4 = 3e2;//3*10^2;
    float f5 = 3e-2;//3 * 0.1^2

2.4 字符型

  • 存放一个字符时将该字符对应的ASCII码放入内存单元,如’a’ = 97,’A’ = 65。

2.5 转义字符

  • 换行符 \n
  • 反斜杠 \
  • 水平制表符 \t 占八个位置,用于整齐的输出数据。
1
2
3
cout << "aaa\thello world!" << endl;
cout << "aa\thello world!" << endl;
cout << "aaaaa\thello world!" << endl;

2.6 字符串

字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。

  • c语言风格 char 变量名[] = “字符串”。

示例:

1
2
3
//声明和初始化创建一个"Hello"字符串。
char str1[6] = {'H','e','l','l','o'};//数组长度要计算null字符。
char str2[] = {'H','e','l','l','o'};
  • c++关于以null结尾的字符串的函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;
#include <cstring>
#define DAY 7

int main() {
cout << "hello world!" << endl;
char str1[11] = "hello";
char str2[11] = "world";
char str3[11];
int len;
int equal;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;

cout << "strlen(str1):" << strlen(str1) << endl;
cout << "strlen(str2):" << strlen(str2) << endl;

//复制 str1 到 str3
//vs2019中认为strcpy函数是危险的,所以改进为strcpy_s()
strcpy_s(str3, str1);
cout << "strcpy_s(str3, str1): " << str3 << endl;

//连接 str1 和 str2
//vs2019中认为strcat函数是危险的,所以改进为strcat_s()
strcat_s(str1, str2);
cout << "strcat_s(str1, str2): " << str1 << endl;

//字符串长度
len = strlen(str1);
cout << "strlen(str1+str2)" << strlen(str1) << endl;

//strcmp(s1, s2);如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。
equal = strcmp(str1, str2);
cout << "strcmp(str1, str2): " << equal << endl;
cout << "strcmp(str1, str1): " << strcmp(str1, str1) << endl;

//strchr(s1, ch);返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
cout << "strchr(str1,e): " << strchr(str1, 'e') << endl;
//cout << "strchr(str1,x): " << strchr(str1, 'x') << endl;

//strstr(str1,str2);
//函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。
cout << "strstr(str1,str1)" << strstr(str1, str1) << endl;
system("pause");
return 0;
}

运行结果为:

1
2
3
4
5
6
7
8
9
10
11
12
hello world!
str1: hello
str2: world
strlen(str1):5
strlen(str2):5
strcpy_s(str3, str1): hello
strcat_s(str1, str2): helloworld
strlen(str1+str2)10
strcmp(str1, str2): -1
strcmp(str1, str1): 0
strchr(str1,e): elloworld
strstr(str1,str1)helloworld
  • c++语言风格 string 变量名 = “字符串”。

2.7 布尔类型

  • true 真 1
    false 假 0

3. 运算符

  • c++中两个整数相除结果依然是整数,小数部分去除。
  • 两个小数不可以做取模运算
  • 自增++,自减–

示例:

1
2
3
4
int d4 = 10;
cout << d4++ << endl;//先输出,在加一,输出 10
cout << d4 << endl; //输出11
cout << ++d4 << endl;//先加一,后输出,输出 12
  • 三目运算符 表达式1?表达式2:表达式3

示例:

1
2
3
4
5
6
7
8
9
10
11
int a = 10;
int b = 2;
int c = 0;
c = (a > b ? a : b);
cout << "c = " << c << endl;
cout << (a > b ? a : b) << endl;

//在c++中三目运算符返回的是变量,可以继续赋值
(a > b ? a : b) = 100;//结果将100赋值给大的数
cout << "a = " << a << endl;
cout << "b = " << b << endl;

4. 程序结构

4.1 break

跳出选择结构或循环结构。

  • 出现在switch语句中,终止case并跳出switch。
  • 出现在循环语句中,跳出最近的循环语句。

4.2 continue

在循环语句中,跳过本次循环中余下尚未执行的语句,继续进行下一次循环。
示例:

1
2
3
4
5
6
7
for (int i = 0;i < 100;i++) {
//奇数输出
if (i % 2 == 0) {
continue;
}
cout << i << endl;
}

4.3 goto

goto 标记

  • 如果标记存在,执行带goto语句时,会跳转到标记的位置。

示例:

1
2
3
4
5
6
    cout << "1" << endl;
goto FLAG;
cout << "3" << endl;
FLAG:
cout << "2" << endl;
//不会打印3

5. 数组

5.1 一维数组

  • 一维数组定义方式
    1、数据类型 数组名[数组长度];
    2、数据类型 数组名[数组长度] = {值1,值2…};
    3、数据类型 数组名[] = {值1,值2….};

  • 一维数组名
    1、统计整个数组在内存中的长度
    2、获取数组在内存中的首地址

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//统计整个数组在内存中的长度
cout << "整个数组所占内存空间为:" << sizeof(arr) << endl;
cout << "每个数组元素所占内存空间为:" << sizeof(arr[0]) << endl;
cout << "数组元素个数为:" << sizeof(arr)/sizeof(arr[0]) << endl;

//获取数组在内存中的首地址
//将int的变量以16进制形式输出 cout << hex << 变量名;
cout << "数组首地址为:" << hex << (int)arr << endl;
cout << "数组中第一个元素的地址为:" << &arr[0] << endl;
cout << "数组中第一个元素的地址为:" << &arr[1] << endl;
//数组名是常量,是首地址,不可以赋值操作
return 0;
}

运行结果为:

1
2
3
4
5
6
整个数组所占内存空间为:40
每个数组元素所占内存空间为:4
数组元素个数为:10
数组首地址为:4ff758
数组中第一个元素的地址为:004FF758
数组中第一个元素的地址为:004FF75C

5.2 二维数组

  • 二维数组定义方式:
1
2
3
4
5
6
二维数组定义方式:
1、数据类型 数组名 [行数][列数];
2、数据类型 数组名 [行数][列数] = {{数据1,数据2、},{数据3,数据4}};
3、数据类型 数组名 [行数][列数] = {数据1,数据2,数据3};
4、数据类型 数组名 [][列数] = {数据1,数据2,数据3};
以上四种定义方式,第二种更加直观,提高代码的可读性
  • 二维数组名
    1、查看二维数组所占内存空间
    2、获取二维数组首地址

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
int main() {
int arr[2][3] =
{
{1,2,3},
{4,5,6}
};
//1、查看内存空间
cout << "二维数组所占内存空间为" << sizeof(arr) << "个字节" << endl;
cout << "二维数组第一行所占内存空间为" << sizeof(arr[0]) << "个字节" << endl;
cout << "二维数组第一个元素占用内存为" << sizeof(arr[0][0]) << "个字节" << endl;

cout << "二维数组行数:" << sizeof(arr) / sizeof(arr[0]) << endl;
cout << "二维数组列数:" << sizeof(arr[0]) / sizeof(arr[0][0])
<< endl;

//2、地址
cout << "二维数组首地址:" << (int)arr << endl;
cout << "二维数组第一行首地址:" << (int)arr[0] << endl;
cout << "二维数组第一个元素的首地址:" << (int)&arr[0][0] << endl;
cout << "二维数组第二行首地址:" << (int)arr[1] << endl;

return 0;
}

运行结果为:

1
2
3
4
5
6
7
8
9
二维数组所占内存空间为24个字节
二维数组第一行所占内存空间为12个字节
二维数组第一个元素占用内存为4个字节
二维数组行数:2
二维数组列数:3
二维数组首地址:4126964
二维数组第一行首地址:4126964
二维数组第一个元素的首地址:4126964
二维数组第二行首地址:4126976

函数的分文件编写

1.创建.h头文件

在.h文件中写函数声明。

1
2
3
4
5
6
//文件名为swap.h
#include <iostream>
using namespace std;

//函数声明,两个数相加
int add(int a, int b);

2.创建.c源文件

在.c文件中写函数定义。

1
2
3
4
5
6
//引用函数声明所在的.h文件
#include "swap.h"

int add(int a, int b) {
return a + b;
}

3.主程序调用函数

在主程序或者其他.cpp文件中调用add函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>  
using namespace std;

//引用函数声明所在的头文件
#include "swap.h"

int main() {
int a = 4;
int b = 2;

//调用add函数
cout << a << "+" << b << "=" << add(a, b) << endl;

return 0;
}

C++随机数

1.rand()函数

c++库中提供rand()函数,每次调用后返回一个非负整数值,程序中包含的头文件为cstdlib。但是,该函数返回的数字是伪随机数。因为rand()函数采用线性同余法实现,生成的数并不是真正意义上的随机数,每次运行都会产生相同的数字流。

示例

1
2
3
4
5
6
7
8
9
10
#include<iostream>
#include <cstdlib>
using namespace std;
int main() {
int num = 0;//初始化随机数字
//产生1~100之间的随机数
num = rand() % 100 + 1;
cout << num << endl;
return 0;
}

2.srand()函数

要在每次运行产生不同的随机数字流,则必须为随机数生成器提供一个种子。c++中通过调用srand函数实现。在rand函数调用之前,srand要先调用一次,并且在整个程序中仅调用一次。

示例一

这种用法需要用户输入种子值,当值不同时产生的随机数不同,若再次使用同样的种子值时,也会产生相同的随机数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include <cstdlib>
using namespace std;
int main() {
int num = 0;//初始化随机数字
unsigned int seed;
cout << "请输入种子值:";
cin >> seed;
srand(seed);
num = rand() % 100 + 1;
cout << num << endl;
return 0;
}

示例二

获取种子值的另一种方法:调用time函数,它是c++标准库中的一部分。time函数返回从1970年1月1日午夜开始到现在逝去的秒数,因此在每次运行时都会产生不同的种子值。程序中包含的头文件为ctime。

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
#include<ctime>
#include <cstdlib>
using namespace std;
int main() {
int num = 0;//初始化随机数字
//使用time函数提供种子
srand((unsigned int)time(0));
num = rand() % 100 + 1;
cout << num << endl;
return 0;
}