目录
3、new/delete 和 malloc/free 的区别
一、bool类型相关概念
1、C语言不支持bool类型,有关bool类型的操作,C语言中使用的都是整型
2、bool类型的值只有两个:true(1)(真)、false(0)(假)。ture和false都是关键字,不可当作标识符
3、在所有整型中,非0为真,0为假
4、bool类型的数据,默认是使用数字表示真假的,如果要使用单词表示真假,需要使用关键字 boolalpha 。如果还想继续使用数字表示真假,则需要使用关键字 noboolalpha 进行转换
5、bool类型只需1位(bit),但是计算机分配内存的最小单位为字节,所以bool类型所占内存大小为1字节
#include <iostream>
using namespace std;
int main()
{
//使用数字为bool类型赋值
bool b0 = 0;
cout << b0 << endl;//0
bool b1 = 10;
cout << b1 << endl;//1
bool b2 = -10;
cout << b2 << endl;//1
//使用bool类型变量用单词赋值
bool b3 = true;
cout << b3 << endl;//1
bool b4 = false;
cout << b4 << endl;//0
//使用单词表示bool类型
cout<<boolalpha<<b0<<endl;//false
cout<<b1<<endl;//true
//使用数字表示bool类型
cout<<noboolalpha<<b0<<endl;//false
cout<<b1<<endl;//true
return 0;
}
二、引用(reference)
1、引用相关
1)在C语言中,进行数据传递的方式有两种:值传递、地址传递,对于接收方,需要定义载体,间接访问数据
2)在C++中,引用没有值传递和地址传递的区分,直接传递数据本身,接收方可以直接使用数据
3)引用相当于给内存空间起一个别名(C++中允许一个内存空间拥有多个名字)
2、引用的定义格式
类型名 &引用名 = 目标名
例:
int num = 303;
int &ref = num; //定义一个引用,指向num
3、引用的注意事项
1)引用的使用与引用目标相同
2)引用定义时,必须初始化
3)引用和引用目标类型可以不一致(多态)
4)引用一旦对象执行对象后,不能再更改
5)一个目标可以定义多个引用,多个引用指向同一地址
4、常引用 const
1、于变量而言,可以时普通变量,也可以时常变量
2、引用也有普通引用和常引用
3、四种引用与目标的搭配
#include <iostream>
using namespace std;
int main()
{
//普通变量 普通引用
int num0 = 502;
int &ref0 = num0;
//常变量 普通引用 不能使用
//const int num1 = 502;
//int &ref1 = num1;
//普通变量 常引用 能使用
int num2 = 502; //变量对数据可读可写
const int &ref2 = num2;//引用对数据只读
//常变量 常引用 能使用
const int num3 = 502; //变量对数据只读
const int &ref3 = num3;//引用对数据只读
return 0;
}
5、引用与指针的关系
指针变量也是变量,可以定义一个指针变量的引用,但一般不使用
#include <iostream>
using namespace std;
int main()
{
int num = 520; //普通变量
int *ptr = # //定义指针变量指向普通变量
int * &ref = ptr; //定义了一个指针变量的引用
cout<<"num = "<<num<<endl; //使用值
cout<<"*ptr = "<<*ptr<<endl; //使用指针变量
cout<<"*ref = "<<*ref<<endl; //使用指针的引用
return 0;
}
6、引用作为函数的参数
传递的是实参本身
#include <iostream>
using namespace std;
//定义交换函数1,完成值传递
void swap1(int num, int key)
{
int temp = num;
num = key;
key = temp;
cout<<"swap1:: num = "<<num<<" key = "<<key<<endl;
}
//定义交换函数2,接受地址进行操作
void swap2(int *p, int *q)
{
int *t = p;
p = q;
q = t;
cout<<"swap1:: *p = "<<*p<<" *q = "<<*q<<endl;
}
//定义交换函数3,接受地址进行操作
void swap3(int *p, int *q)
{
int t = *p;
*p = *q;
*q = t;
cout<<"swap1:: *p = "<<*p<<" *q = "<<*q<<endl;
}
//定义交换函数4,完成地址传递,形参使用引用接受
void swap4(int &num, int &key)
{
int temp = num;
num = key;
key = temp;
cout<<"swap1:: num = "<<num<<" key = "<<key<<endl;
}
int main()
{
int num = 520;
int key = 1314;
//调用交换函数1
swap1(num, key); //1314 520
cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314
cout<<"**************************************************"<<endl;
//调用交换函数2
swap2(&num, &key); //1314 520
cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314
cout<<"**************************************************"<<endl;
//调用交换函数3
swap3(&num, &key); //1314 520
cout<<"main:: num = "<<num<<" key = "<< key<<endl; //1314 520
cout<<"**************************************************"<<endl;
//调用交换函数4
swap4(num, key); //520 1314
cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314
cout<<"**************************************************"<<endl;
return 0;
}
7、引用作为函数的返回值
1)引用作为函数的返回值,返回的是一个左值
2)跟指针作为函数的返回值一样,必须返回一个生命周期比较长的变量
3)能够返回的类型
1、一定不能返回局部变量
2、全局变量
3、静态局部变量
4、堆区申请的空间中的值
#include <iostream>
using namespace std;
//引用作为函数的返回值,返回的是一个左值
int &fun()
{
//int num = 520;
//return num; //返回局部变量的空间是不合法的
static int key = 520;
return key; //返回生命周期比较长的数据
}
int main()
{
fun() = 1314; //引用函数作为左值使用
cout<<"fun() = "<<fun()<<endl; //1314
int &ref = fun(); //相当于给函数中的key又在主函数中起个别名
ref = 666;
cout<<"fun() = "<<fun()<<endl; //666
return 0;
}
8、数组的引用
1)不支持引用数组
//不支持
int arr[5] = {0};
int &rarr[5] = arr[5];
error: 'rarr' declared as array of references of type 'int &'
错误: 'rarr' 声明为类型 'int &' 的引用数组
2)支持数组的引用
void fun(int (&arr)[5], int n)
{
cout<<sizeof (arr)<<endl;//20
for(int i = 0; i < n ; i++)
{
cout << arr[i] << " ";
}
cout<<endl;
}
3)示例
#include <iostream>
using namespace std;
void fun0(int arr[], int n)
{
cout<<sizeof (arr)<<endl;//8
for(int i = 0; i < n ; i++)
{
cout << arr[i] << " ";
}
cout<<endl;
}
void fun1(int *arr, int n)
{
cout<<sizeof (arr)<<endl;//8
for(int i = 0; i < n ; i++)
{
cout << arr[i] << " ";
}
cout<<endl;
}
void fun2(int (&arr)[8], int n)
{
cout<<sizeof (arr)<<endl;//20
for(int i = 0; i < n ; i++)
{
cout << arr[i] << " ";
}
cout<<endl;
}
int main()
{
int arr[5] = {8,5,9,2,8};
//int &rarr[5] = arr[5];
fun0(arr,5);
fun1(arr,5);
fun2(arr,5);
return 0;
}
9、右值引用
1)上面描述的引用都是左值引用
2)左值:有内存空间的容器称为左值,表现形式有变量、堆区空间、字符串常量
右值:没有内存空间的数据,表现形式有常量、表达式的结果、值返回函数的返回值、将亡值
3)右值引用的定义格式:数据类型 &&引用名 = 引用目标;
4)左值引用的目标必须是一个左值,右值引用的目标必须是一个右值
5)可以通过函数 move将左值转变成右值
#include <iostream>
using namespace std;
int main()
{
int num = 520; //其中num为左值 520为右值
int &ref1 = num; //定义左值引用引用左值的空间
int &&ref2 = 520; //定义右值引用引用右值的空间
//int &ref3 = 520; //左值引用不能绑定右值
//int &&ref4 = num; //右值引用不能绑定一个左值
int &ref5 = ref2; //定义一个左值引用,引用一个右值的引用
int &&ref6 = move(num); //将左值移动成右值,进行使用
return 0;
}
10、指针和引用的区别
1)定义时,指针使用 * , 引用使用 &
2)使用时,指针取值需要 * 取值,引用的使用与引用目标一致
3)内存相关,指针是一个变量,占用8字节;引用不占用新内存,使用的是引用目标的内存
4)指针有二级指针,引用没有二级引用
5)有空指针,没有空引用
6)指针进行偏移运算时是对内存地址的偏移;对引用偏移是,是对目标值的偏移
7)指针可以改变指向,引用不能更改目标
8)指针定义可以不初始化(野指针),引用定义时必须初始化
9)指针不能指向右值,右值引用的目标可以是右值
10)指针有数组指针,引用不能定义引用数组
11)指针的类型关系到偏移量,引用的类型关系到作用域(多态)
三、堆区空间的申请和释放
1、概述
1)在C语言中,对于堆区空间的申请和释放,使用的时malloc和free,C++可以继续使用
2)在C++中,提供了操作更加方便的关键字 new和 delete用于堆区空间的申请和释放
2、 堆区空间的申请和释放 new delete
1、单个空间的申请和释放
申请: 数据效率 *指针名 = new 衔接类型
释放: delete 指针名
#include <iostream>
using namespace std;
int main()
{
int *p0 = new int;
cout<<*p0<<endl; //值随机
*p0 = 2024;
cout<<*p0<<endl; //2024
double *p1 = new double(3.14);//
cout<<*p1<<endl; //3.14
delete p0;
delete p1;
return 0;
}
2、连续空间的申请和释放
申请:随机连续 *指针名 = new 数据类型
释放:delete []指针名
int *p2 = new int[5];
for(int i = 0;i < 5; i++)
{
cout<<p2[i]<<" ";
}
cout<<endl;
int *p3 = new int[5]{0,2,5,4,6};
for(int i = 0;i < 5; i++)
{
cout<<p3[i]<<" ";// 0 2 5 4 6
}
cout<<endl;
delete []p2;
delete []p3;
3、new/delete 和 malloc/free 的区别
1)new/delete是关键字;malloc/free是函数,需要包含相关的库
2)使用new申请空间后,申请什么类型就是什么类型的地址;malloc申请的结果是void*
3)new申请空间是,可以初始化,malloc申请空间时不能初始化
4)new和delete在申请和释放空间时,单个空间和连续空间的操作是不同的,而malloc不区分
5)new申请空间是,以数据效率为单位,而malloc申请空间时以字节为单位
6)new申请空间时会自动计算所需空间的大小,而malloc申请空间时需要手动计算大小
7)new关键字中封装了malloc函数,delete关键字中封装了free函数
8)new在申请对象的空间时会调用该类的构造函数,malloc不会
9)delete在释放对象空间时,会自动调用该类的析构函数,free不会
四、C++中的结构体
1、C语言中的结构体仅仅只是属性的聚合体,只能封装变量
2、C++中的结构体,可以包含:变量、函数、类型
3、C语言中结构体定义变量时需要加上struct,而C++中不需要加struct
4、C语言中的结构体在声明时,是不允许给成员变量初始值的, 而C++中的结构体可以
5、C语言中的结构体时不能继承的,C++中的结构体可以继承
6、C语言中的结构体中所有成员变量都是公共的,外界可以通过结构体变量进行访问,而C++中的结构体中的成员变量是可以加访问权限的,分为公共权限、受保护权限、私有权限。只有公共权限的外界能够访问
7、示例
#include <iostream>
using namespace std;
struct Person
{
//成员属性
string name;
int age = 20;//C++中的结构体内成员,定义时可以初始化
//C++中的结构体,可以封装函数,称为成员函数
void speaker();//结构体内声明,结构体外定义
//如果不给权限,则默认为公共权限
private: //该关键字后的成员权限为 私有
string msg = "NULL";
public: //该关键字后的成员权限为 公共
void set_msg(string m);//msg的公共接口,用于更改 msg 的内容
void set_msg();
void msg_show();//msg的公共接口,用于打印 msg 的内容
protected: //受保护的属性 外部不能直接访问
string txt = "real NULL";
};
//结构体外定义成员函数
void Person::speaker()
{
cout<<name<<":hello world"<<" "<<msg<<endl;
}
void Person::msg_show()
{
cout<<msg<<endl;
}
void Person::set_msg(string m)
{
msg = m;
}
//函数重载:C++中允许函数重名,在使用时会根据实参匹配形参对应的函数
void Person::set_msg()
{
getline(cin,msg);
}
/**********************结构体继承**************************/
//结构体Child 完全拥有Person的成员 可直接使用公共成员、受保护的成员 但不能使用私有成员
struct Child : Person
{
//子结构体可以拥有自己的成员
string cname;
};
int main()
{
//使用结构体类型定义变量
//struct Person p1;
Person p1;//定义结构体变量时可以不加struct
p1.name = "zzy";
p1.speaker();
//cout<<p1.msg<<endl;
//main.cpp:34:14: error: 'msg' is a private member of 'Person'
//main.cpp:17:12: note: declared private here
//私有成员外部无法直接访问,需要在结构体中提供公共的接口来操作
p1.set_msg();
p1.msg_show();
//cout<<p1.txt<<endl;
//main.cpp:49:14: error: 'txt' is a protected member of 'Person'
//main.cpp:23:12: note: declared protected here
//受保护的属性在外部无法直接访问,但是,在结构体内和子结构体中可以访问
Child p2;
p2.name = "change name";
cout<<p1.name<<endl;//zzy
cout<<p2.name<<endl;//change name
//子结构体从父结构体继承的成员仅是名字相同,并不是同一个成员
return 0;
}
五、使用结构体封装顺序表
#include <iostream>
using namespace std;
//类型重命名
using datatype = int; //typedef int datatype;
#define MAX 30
struct SeqList
{
private:
datatype *data; //顺序表的数组
int size = 0; //数组的大小
int len = 0; //顺序表实际长度
public:
//初始化函数
void init(int s)
{
size = s; //当前数组的最大容量
data = new datatype[size]; //在堆区申请一个顺序表容器
}
//判空函数
bool empty();
//判满函数
bool full();
//添加数据函数
bool add(datatype e);
//求当前顺序表的实际长度
int length();
//任意位置插入函数
bool insert_pos(int pos, datatype e);
//任意位置删除函数
bool delete_pos(int pos);
//访问容器中任意一个元素 at
datatype &at(int index);
//二倍扩容
void expend();
//打印
void show();
//返回数组大小
int show_size();
};
//判空函数
bool SeqList::empty()
{
return !len;
}
//判满函数
bool SeqList::full()
{
return size == len;
}
//添加数据函数
bool SeqList::add(datatype e)
{
if(full())
{
expend();
}
data[len] = e;
len++;
return 1;
}
//求当前顺序表的实际长度
int SeqList::length()
{
return len;
}
//任意位置插入函数
bool SeqList::insert_pos(int pos, datatype e)//缺少对不正确位置的判断
{
if(full())
{
expend();
}
for(int i = len-1; i >= pos-1; i--)
{
data[i+1] = data[i];
}
data[pos-1] = e;
len++;
return 1;
}
//任意位置删除函数
bool SeqList::delete_pos(int pos)//缺少对不正确位置的判断
{
if(empty())
{
return 0;
}
for(int i = pos -1; i < len; i++)
{
data[i] = data[i + 1];
}
len--;
return 1;
}
//访问容器中任意一个元素 at
datatype &SeqList::at(int index)//缺少对不正确位置的判断
{
return data[index];
}
//打印
void SeqList::show()
{
if(empty())
{
return;
}
for(int i = 0;i < len;i++)
{
cout<<data[i]<<" ";
}
cout<<endl;
return;
}
//二倍扩容
void SeqList::expend()
{
//更新size值
size*=2;
//定义中间数组
datatype *temp;
//创建新空间
temp = new datatype[size];//参数 datatype 类型数据 个数
//拷贝数据
memcpy(temp,data,size*4);//参数3 单位 位
//释放原空间
delete data;
//原数组名重定向
data = temp;
//中间指针(数组)置空
temp = NULL;
}
//返回数组大小
int SeqList::show_size()
{
return size;
}
int main()
{
int size = 5;
SeqList sl;
sl.init(size);
for(int i = 0;i < 8; i++)
{
sl.add(5);
cout<<"len = "<<sl.length()<<endl;;
sl.show();
cout<<"size = "<<sl.show_size()<<endl;
}
sl.show();
sl.insert_pos(2,2);
sl.show();
sl.insert_pos(1,1);
sl.show();
sl.delete_pos(1);
sl.show();
sl.delete_pos(1);
sl.show();
for(int i = 0;i < sl.show_size(); i++)
{
sl.delete_pos(1);
cout<<"len = "<<sl.length()<<endl;;
sl.show();
cout<<"size = "<<sl.show_size()<<endl;
}
return 0;
}