本文主要是介绍day43——C++对C的扩充,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
四、bool类型
1> C语言是不支持bool类型的,有关bool类型的操作,C语言中使用的都是整型。但是C++中支持bool类型
2> bool类型的值只有两个 一个是真 true(1)表示和假false(0)表示。这里true和false都是关键字,不可以当做标识符
3> 在所有整数中,所有非0数字都表示真,只有0表示假
4> bool类型的数据,默认是使用数字表示真假的,如果要使用单词表示真假,需要使用关键字 boolalpha 。如果还想继续使用数字表示真假,则需要使用关键字 noboolalpha 进行转换
5> bool类型所占内存的大小为1字节,本质上使用1bit表示就足够了,但是计算机分配内存的基本单位是字节,所以bool占1字节的内存
#include <iostream>
using namespace std;
int main()
{bool b1 = -10;bool b2 = 0;bool b3 = 10;//bool类型的数据默认使用数字表示真假cout<<"b1 = "<<b1<<endl; // 1cout<<"b2 = "<<b2<<endl; // 0cout<<"b3 = "<<b3<<endl; // 1cout<<"***************************************"<<endl;//对bool类型的变量用单词赋值bool b4 = true;bool b5 = false;cout<<"b4 = "<<b4<<endl; // 1cout<<"b5 = "<<b5<<endl; // 0cout<<"***************************************"<<endl;//使用单词表示bool类型cout<<boolalpha<<"b1 = "<<b1<<endl; // 1cout<<"b2 = "<<b2<<endl; // 0cout<<"b3 = "<<b3<<endl; // 1cout<<"***************************************"<<endl;//继续使用数字表示真假cout<<noboolalpha<<"b1 = "<<b1<<endl; // 1cout<<"b2 = "<<b2<<endl; // 0cout<<"b3 = "<<b3<<endl; // 1cout<<"***************************************"<<endl;return 0;
}
五、引用(reference)
5.1 引用的引入
1> 在C语言中,进行数据传递的方式有两种,分别是值传递和地址传递,对于数据的传递都需要在被调函数中设置一个载体,对主调函数中的数据进行间接访问
2> 在C++中引入的引用的概念,就没有值传递和地址传递的区分了,直接传递的就是主调函数中的实参本身,并且被调函数中不需要申请载体的空间,直接对实参的值进行操作
3> 引用相当于给内存空间起个别名。
5.2 引用的定义格式
类型名 &引用名 = 目标名;
例如:int num = 520;
int &ref = num; //定义一个引用,并指向一个num目标
对&又进一步使用,&的使用方式
1、&表示单目运算符,取地址运算,后面紧跟一个变量
2、&&表示双目运算符逻辑与运算
3、&表示双目运算符,按位与运算
4、&表示定义引
5.3 引用的注意事项
1、引用的使用跟普通变量的使用一样,跟引用的目标一样正常使用
2、引用在定义时,必须用目标对其进行初始化,否则会报错
3、引用和目标的类型必须保持一致(也可以不一致,后期继承和多态时讲父类指针或引用可以指向子类对象时)
4、引用一旦定义并指向目标后,后期就不能再更改目标了
5、一个目标可以定义多个引用,多个引用与目标都是同一个东西
#include <iostream>using namespace std;int main()
{int num = 520; //在内存中申请4个字节,存储数据为520int &ref = num; //此时给num定义一个引用,后期这两个都是同一个东西//int &r; //定义引用不初始化会直接报错//string &re = num; //定义引用时,类型必须与目标保持一致cout<<"num = "<<num<<" ref = "<<ref<<endl; //值相同cout<<"&num = "<<&num<<" &ref = "<<&ref<<endl; //地址相同num = 1314; //对num进行改变cout<<"num = "<<num<<" ref = "<<ref<<endl; //值相同ref = 666;cout<<"num = "<<num<<" ref = "<<ref<<endl; //值相同int &ref2 = ref; //给引用定义一个引用int &ref3 = num; //给一个目标定义多个引用cout<<"num = "<<num<<" ref = "<<ref<<" ref2 = "<<ref2<<" ref3 = "<<ref3<<endl; //值相同cout<<"&num = "<<&num<<" &ref = "<<&ref<<" &ref2 = "<<&ref2<<" &ref3 = "<<&ref3<<endl; //值相同cout<<"sizeof(num) = "<<sizeof(num) <<" sizeof(ref) = "<<sizeof(ref)<<endl; //大小相同//验证引用的目标一旦指定,就不能再更改int key = 12345;//ref = key; //? 该语句是将key的值赋值给ref也就是赋值给num,并不是将ref重新指向key //&ref = key; //? 报错,&ref是取得ref的地址,不能对地址常量赋值//int ref = key; //? 报错 ref引用重复定义return 0;
}
5.4 常引用 const
1> 对于变量而言,可以是普通变量,也可以是常变量
2> 对应的引用也可以是普通引用和常引用
3> 有四种引用与目标的搭配
1、普通引用 普通变量
2、普通引用 常变量
3、常引用 普通变量
4、常引用 常变量
#include <iostream>
using namespace std;
int main()
{//普通引用目标为普通变量没有问题int num = 520; //普通变量 对数据可读可写int &ref1 = num; //普通引用 对数据可读可写/******************************************///由于目标本身具有常属性,而引用是一个变量,所以报错,不能将普通引用目标为常变量const int key = 1314; //常变量 对数据可读不可写//int &ref2 = key; //普通引用/******************************************///常引用的目标可以是普通变量int value = 666; //普通变量 变量自身对数据可读可写const int &ref3 = value; //常引用 引用对数据的处理可读不可写cout<<"ref3 = "<<ref3<<endl; //可读//ref3 = 999; //不可写/******************************************///常引用可以引用的目标为常变量const int number = 999; //常变量 对数据可读不可写const int &ref4 = number; //常引用 对数据可读不可写return 0;
}
5.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;
}
5.6 引用作为函数的参数
1> 引用作为函数的参数,传递的是实参本身,没有值传递和地址传递之说
#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;//调用交换函数1swap1(num, key); //1314 520cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314cout<<"**************************************************"<<endl;//调用交换函数2swap2(&num, &key); //1314 520cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314cout<<"**************************************************"<<endl;//调用交换函数3swap3(&num, &key); //1314 520cout<<"main:: num = "<<num<<" key = "<< key<<endl; //1314 520cout<<"**************************************************"<<endl;//调用交换函数4swap4(num, key); //520 1314cout<<"main:: num = "<<num<<" key = "<< key<<endl; //520 1314cout<<"**************************************************"<<endl;return 0;
}
5.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; //1314int &ref = fun(); //相当于给函数中的key又在主函数中起个别名ref = 666;cout<<"fun() = "<<fun()<<endl; //666return 0;
}
5.8 数组的引用
1> C++中不支持引用数组
2> C++中支持数组的引用
3> 定义格式: 数据类型 (&引用名) [数组长度] = 数组名;
#include <iostream>
using namespace std;
//定义fun1函数
void fun1(int arr[], int n)
{cout<<sizeof(arr)<<endl; //8cout<<"数组目前中的数据为:";for(int i=0; i<n; i++){cout<<arr[i]<<" ";}cout<<endl;}//定义fun2函数
void fun2(int *arr, int n)
{cout<<sizeof(arr)<<endl; //8cout<<"数组目前中的数据为:";for(int i=0; i<n; i++){cout<<arr[i]<<" ";}cout<<endl;}//定义fun3函数
void fun3(int (&arr)[8], int n)
{cout<<sizeof(arr)<<endl; //32cout<<"数组目前中的数据为:";for(int val:arr){cout<<val<<" ";}cout<<endl;}int main()
{int arr[8] = {1,3,5,8,7,6,4,2};//调用函数传递该数组fun3(arr, 8);return 0;
}
5.9 右值引用
1> 上面描述的引用都是左值引用
2> 左值:有内存空间的容器称为左值,表现形式有变量、堆区空间、字符串常量
右值:没有内存空间的数据,表现形式有常量、表达式的结果、值返回函数的返回值、将亡值
3> 右值引用的定义格式:数据类型 &&引用名 = 引用目标;
4> 左值引用的目标必须是一个左值,右值引用的目标必须是一个右值
#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;
}
5.10 指针和引用的区别
1> 指针定义时需要使用*号,引用定义时需要使用&
2> 指针取值需要使用*号运算符完成,引用使用时直接跟目标使用方式一致
3> 指针定义时,需要给指针分配内存空间8字节,引用定义时不需要分配内存空间,引用使用的是目标的空间
4> 指针初始化后,可以改变指针的指向,但是引用初始化后,不能在改变目标了
5> 指针有二级指针,但是引用没有二级引用
6> 有空指针,但是没有空引用
7> 指针进行偏移运算时是对内存地址的偏移,而引用进行偏移时,就是对目标值的偏移
8> 指针不能指向右值,但是右值引用的目标可以是右值
9> 指针定义时可以不初始化(野指针),引用定义时必须初始化
10> 指针可以有指针数组,但是引用不能定义引用数组
六、堆区空间的申请和释放
6.1 概述
1> 在C语言中,对于堆区空间的申请和释放,使用的是malloc和free函数,C++中也可以继续使用
2> 在C++中,提供了更加操作方便的关键字 new和delete用于堆区空间的申请和释放
6.2 new和delete
1> new和delete申请和释放堆区空间时,分为单个空间的申请和释放以及连续空间的申请和释放
2> 单个空间的申请和释放
申请: 数据类型 * 指针名 = new 数据类型;
释放: delete 指针名;
#include <iostream>using namespace std;int main()
{//从堆区申请一个int类型的空间数据int *p1 = new int;cout<<"*p1 = "<<*p1<<endl; //随机值*p1 = 520; //使用堆区空间cout<<"*p1 = "<<*p1<<endl; //520// 从堆区空间申请double类型的数据double *p2 = new double(3.14);cout<<"*p2 = "<<*p2<<endl; //3.14//释放堆区空间delete p1;delete p2;return 0;
}
3> 连续空间的申请和释放
申请: 数据类型 *指针名 = new 数据类型[元素个数];
释放:delete []指针名;
#include <iostream>using namespace std;int main()
{//从堆区申请一个int类型的空间数据int *p1 = new int;cout<<"*p1 = "<<*p1<<endl; //随机值*p1 = 520; //使用堆区空间cout<<"*p1 = "<<*p1<<endl; //520// 从堆区空间申请double类型的数据double *p2 = new double(3.14);cout<<"*p2 = "<<*p2<<endl; //3.14//释放堆区空间delete p1;delete p2;cout<<"***********************************************"<<endl;//连续申请5个空间的int类型int *p3 = new int[5]; //没有初始化,默认都是随机值for(int i=0; i<5; i++){cout<<p3[i]<<" ";}cout<<endl;//连续申请空间并初始化int *p4 = new int[5]{3,7,2,1,6};for(int i=0; i<5; i++){cout<<p4[i]<<" ";}cout<<endl;//释放空间delete []p3;delete []p4;return 0;
}
练习:要求使用new和delete完成,在堆区申请一个空间,存储8名学生的成绩,完成这些学生的成绩录入、输出、升序排序等操作
#include <iostream>
using namespace std;
void inputScores(int *scores, int size) {cout << "请输入" << size << "名学生的成绩:" << endl;for (int i = 0; i < size; i++) {cin >> scores[i];}
}
void outputScores(int *scores, int size) {cout << "学生的成绩为:" << endl;for (int i = 0; i < size; i++) {cout << scores[i] << " ";}cout << endl;
}
void sortScores(int *scores, int size) {for (int i = 0; i < size - 1; i++) {for (int j = i + 1; j < size; j++) {if (scores[j] < scores[i]) {int temp = scores[j];scores[j] = scores[i];scores[i] = temp;}}}
}
int main() {int size = 8;int *scores = new int[size];inputScores(scores, size);outputScores(scores, size);sortScores(scores, size);cout << "排序后的学生成绩为:" << endl;outputScores(scores, size);delete[] scores;return 0;
}
引入算法库的相关使用
#include <iostream>
#include<algorithm>using namespace std;void stu_input(int *stu)
{for(int i=0;i<8;i++){cout<<"请输入第"<<i+1<<"位学生的成绩"<<endl;cin>>stu[i];}
}
void stu_output(int *stu)
{for(int i=0;i<8;i++){cout<<"第"<<i+1<<"位学生的成绩为:"<<stu[i]<<endl;}
}//定义全局函数当做排序的策略
int compare(int a, int b)
{return a>b;
}int main()
{int *stu=new int[8];stu_input(stu);stu_output(stu);//调用算法库中的相关函数,默认是降序排序sort(stu, stu+8, compare); //加了排序策略的排序函数cout<<"排序后结果为:"<<endl;stu_output(stu);return 0;
}
6.3 new\delete与malloc\free的区别
1> new和delete是关键字,而malloc和free是函数,需要包含相关的库
2> 使用new申请空间后,申请什么类型就是什么类型的地址,而malloc申请的结果是void*需要具体转换
3> new申请空间时,可以初始化,malloc申请空间时不能初始化
4> new和delete申请和释放空间时,单个和连续的操作是不同的,而malloc和free是不区分单个和连续申请释放的
5> new申请空间时以数据类型为单位,而malloc申请空间时以字节为单位
6> new申请空间时会自动计算所需空间的大小,而malloc申请空间时需要手动计算大小
7> new关键字中封装了malloc函数,delete关键字中封装了free
9> new在申请对象的空间时会调用该类的构造函数,malloc不会
10> delete在释放对象空间时,会自动调用该类的析构函数,free不会
七、C++中的结构体
1> C语言中的结构体仅仅只是属性的聚合体,都只能封装一些变量
2> C++中的结构体,可以包罗万象(变量、函数、类型)
3> C语言中结构体定义变量时需要加上struct,而C++中不需要加struct
4> C语言中的结构体在声明时,是不允许给成员变量初始值的, 而C++中的结构体可以
5> C语言中的结构体时不能继承的,C++中的结构体可以继承
6> C语言中的结构体中所有成员变量都是公共的,外界可以通过结构体变量进行访问,而C++中的结构体中的成员变量是可以加访问权限的,分为公共权限、受保护权限、私有权限。只有公共权限的外界能够访问
#include <iostream>using namespace std;
struct Person
{//如果不给设置权限,默认都是公共权限string name; //姓名int age = 100; //年龄//C++中的结构体,可以封装函数void speaker(); //结构体内声明,结构体外定义private: //该关键字后面的变量或者函数属于私有权限int money = 10000;public:void set_money(int m); //结构体内声明protected:string skill = "C++"; //技能
};//结构体外定义成员函数
void Person::speaker()
{cout<<"name = "<<name<<" age = "<<age<<" money = "<<money<< " skill = "<<skill<<endl;
}void Person::set_money(int m)
{money = m;
}/***************************************上面是person的结构体的内容*************************************************/
struct Student : Person //定义一个学生结构体,继承自Person结构体
{
private:double score; //学生类型扩充的私有成员public:void study(){cout<<"good good study day day up!!!!"<<" I am studding "<<skill<<endl;//cout<<"money = "<<money<<endl;}
};int main()
{//使用结构体类型定义变量//struct Person p1;Person p1; //定义结构体变量时可以不用加structp1.age = 20;p1.name = "zhangpp";p1.speaker();//cout<<p1.money<<endl; //私有成员外部无法直接访问,需要在结构体中提供公共的接口来操作p1.set_money(111111111);p1.speaker();//cout<<p1.skill<<endl; //受保护的属性在外部无法直接访问,但是,在结构体内和子结构体中可以访问cout<<"*******************************************************"<<endl;Student s1; //定义一个学生类型的结构体变量s1.name = "zhangsan";s1.speaker();s1.study();return 0;
}
作业:
使用C++手动封装一个顺序表,包含成员数组一个,成员变量N个
#include <iostream>
using namespace std;//类型重命名
using datatype = int;
#define MAX 30struct SeqList
{private:datatype *data; //顺序表的数组int size = 0; //数组的大小int len = 0; //顺序表实际长度public://初始化函数void init(int s){size = s; //当前数组的最大容量data = new datatype[size]; //在堆区申请一个顺序表容器}//判空函数bool empty(){return len == 0;}//判满函数bool full(){return len == size;}//添加数据函数bool add(datatype e){if (full())//如果满了,则扩充{expend();}data[len++] = e;return true;}//求当前顺序表的实际长度int length(){return len;}//任意位置插入函数bool insert_pos(int pos, datatype e){if (pos < 0 || pos > len){cout << "插入失败" << endl;return false;}if (full()){expend();}for (int i = len; i > pos; --i){data[i] = data[i - 1];}data[pos] = e;len++;return true;}//任意位置删除函数bool delete_pos(int pos){if (pos < 0 || pos >= len){cout << "删除失败" << endl;return false;}for (int i = pos + 1; i < len; ++i){data[i - 1] = data[i];}len--;return true;}//访问容器中任意一个元素 atdatatype &at(int index){if (index < 0 || index >= len){throw out_of_range("无法找到该位置的值");//抛出异常}else{return data[index];}}//君子函数:二倍扩容void expend(){int newSize = size * 2;datatype *newData = new datatype[newSize];for (int i = 0; i < size; ++i){newData[i] = data[i];}delete[] data;data = newData;size = newSize;}
};
int main() {SeqList list;int choice;list.init(30); // 初始化顺序表,最大容量为10while(1){cout << "请选择操作:" << endl;cout << "1、添加数据" << endl;cout << "2、插入数据" << endl;cout << "3、删除指定位置的数据" << endl;cout << "4、查看指定位置的数据" << endl;cout << "5、查看当前顺序表的实际长度" << endl;cout << "请输入>>>>>>>";cin >> choice;switch (choice) {case 1: {int value;cout << "请输入要添加的数据:";cin >> value;list.add(value);break;}case 2: {int pos, value;cout << "请输入要插入的位置和数据:";cin >> pos >> value;list.insert_pos(pos, value);break;}case 3: {int pos;cout << "请输入要删除的位置:";cin >> pos;list.delete_pos(pos);break;}case 4: {try {int pos;cout << "请输入要查看的位置:";cin >> pos;list.at(pos);//判断是否有错,若有错则直接输出错误原因cout << "位置" << pos << "的数据是:" << list.at(pos) << endl;} catch (const out_of_range& e) {cerr << "错误:" << e.what() << endl;//捕获异常}break;}case 5: {cout << "当前顺序表的实际长度是:" << list.length() << endl;break;}default: {cout << "无效的选择,请重新输入。" << endl;break;}}}return 0;
}
这篇关于day43——C++对C的扩充的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!