学习记录——day38 C++ bool类型 引用 结构体 堆

目录

一、bool类型相关概念

二、引用(reference)

1、引用相关

2、引用的定义格式

 3、引用的注意事项

4、常引用 const

5、引用与指针的关系

6、引用作为函数的参数

7、引用作为函数的返回值

8、数组的引用

1)不支持引用数组

2)支持数组的引用

3)示例

9、右值引用

10、指针和引用的区别

三、堆区空间的申请和释放

3、new/delete 和 malloc/free 的区别

四、C++中的结构体

五、使用结构体封装顺序表


一、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 = &num;      //定义指针变量指向普通变量
    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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值