C++基础

目录

思维导图:

学习内容:

1. 引用(reference)

1.1 引用的引入

1.2 引用的定义格式

1.3 引用的注意事项 

1.4 常引用 const 

1.5 引用与指针的关系 

1.6 引用作为函数的参数 

1.7 引用作为函数的返回值

1.8 数组的引用 

1.9 右值引用(了解) 

1.10 指针和引用的区别(重要)

2. 堆区空间的申请和释放

2.1 概述

2.2 new和delete

2.3 new\delete与malloc\free的区别 

3. C++中的结构体

课外作业:

使用C++手动封装一个顺序表,包含成员数组一个,成员变量N个


思维导图:


学习内容:

1. 引用(reference)

1.1 引用的引入

        1> 在C语言中,进行数据传递的方式有两种,分别是值传递和地址传递,对于数据的传递都需要在被调函数中设置一个载体,对主调函数中的数据进行间接访问

        2> 在C++中引入的引用的概念,就没有值传递和地址传递的区分了,直接传递的就是主调函数中的实参本身,并且被调函数中不需要申请载体的空间,直接对实参的值进行操作

        3> 引用相当于给内存空间起个别名。

1.2 引用的定义格式

     类型名  &引用名  =  目标名;
      例如:int num = 520;
            int &ref = num;      //定义一个引用,并指向一个num目标
    对&又进一步使用,&的使用方式
        1、&表示单目运算符,取地址运算,后面紧跟一个变量
        2、&&表示双目运算符逻辑与运算
        3、&表示双目运算符,按位与运算
        4、&表示定义引用

1.3 引用的注意事项 

1、引用的使用跟普通变量的使用一样,跟引用的目标一样正常使用

2、引用在定义时,必须用目标对其进行初始化,否则会报错

3、引用和目标的类型必须保持一致(也可以不一致,后期继承和多态时讲父类指针或引用可以指向子类对象时)

4、引用一旦定义并执行目标后,后期就不能再更改目标了

5、一个目标可以定义多个引用,多个引用与目标都是同一个东西

#include <iostream>


using namespace std;


int main()
{
    int num = 520;        //在内存中申请4个字节,存储数据为520


    int &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;
}

1.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;
}

1.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;
}

1.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;


    //调用交换函数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;
}

1.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;
}

1.8 数组的引用 

        1> C++中不支持引用数组

        2> C++中支持数组的引用

        3> 定义格式: 数据类型 (&引用名) [数组长度] = 数组名;

#include <iostream>


using namespace std;


//定义fun1函数
void fun1(int arr[], int n)
{
    cout<<sizeof(arr)<<endl;          //8
    cout<<"数组目前中的数据为:";
    for(int i=0; i<n; i++)
    {
        cout<<arr[i]<<" ";
    }
    cout<<endl;


}


//定义fun2函数
void fun2(int *arr, int n)
{
    cout<<sizeof(arr)<<endl;          //8
    cout<<"数组目前中的数据为:";
    for(int i=0; i<n; i++)
    {
        cout<<arr[i]<<" ";
    }
    cout<<endl;


}


//定义fun3函数
void fun3(int (&arr)[8], int n)
{
    cout<<sizeof(arr)<<endl;          //32
    cout<<"数组目前中的数据为:";
    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;
}

1.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;
}

1.10 指针和引用的区别(重要)

1> 指针定义时需要使用*号,引用定义时需要使用&

2> 指针取值需要使用*号运算符完成,引用使用时直接跟目标使用方式一致

3> 指针定义时,需要给指针分配内存空间8字节,引用定义时不需要分配内存空间,引用使用的是目标的空间

4> 指针初始化后,可以改变指针的指向,但是引用初始化后,不能在改变目标了

5> 指针有二级指针,但是引用没有二级引用

6> 有空指针,但是没有空引用

7> 指针进行偏移运算时是对内存地址的偏移,而引用进行偏移时,就是对目标值的偏移

8> 指针不能指向右值,但是右值引用的目标可以是右值

9> 指针定义时可以不初始化(野指针),引用定义时必须初始化

10> 指针可以有指针数组,但是引用不能定义引用数组

2. 堆区空间的申请和释放

2.1 概述

        1> 在C语言中,对于堆区空间的申请和释放,使用的是malloc和free函数,C++中也可以继续使用

        2> 在C++中,提供了更加操作方便的关键字 new和delete用于堆区空间的申请和释放

2.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;
}

2.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不会

3. 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;                //定义结构体变量时可以不用加struct
    p1.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;

struct Seqlist
{
    private:
            datatype *data;
            int len = 0;
            int size = 0;


    public:
            void init(int s);

            bool empty();

            bool full();

            bool add(datatype e);

            int length();

            bool insert_pos(datatype e,int pos);

            bool delete_pos(int pos);

            datatype &at_pos(int index)
            {
                return data[index];
            }

            void expend();

            void delete_list();
};

//申请空间函数
void Seqlist::init(int s)
{
    size = s; // 设置顺序表的大小
       data = new datatype(size); // 新建一个具有指定大小的数据存储空间
}

//表判空函数
bool Seqlist::empty()
{
    return (len == 0);
}

//表判满函数
bool Seqlist::full()
{
    return (len == size);
}

//添加表的数据函数
bool Seqlist::add(datatype e)
{
    if(full())      
    {
        expend();     //如果满了就申请两倍的空间
    }
    data[len]=e;      //赋值给data
    len++;             //长度加1
    return true;
}

int Seqlist::length()
{
    return len;        //返回表的长度
}

//插入函数
bool Seqlist::insert_pos(datatype e,int pos)
{
    // 检查插入位置是否有效,如果位置无效或列表已满,则插入失败
        if (pos < 0 || pos > len || full())
        {
            return false;
        }
    
        // 为插入的新元素腾出空间,需要将插入位置之后的元素依次后移
        for (int i = len - 1; i > pos; i--)
        {
            data[i + 1] = data[i];
        }
    
        // 在指定位置插入新元素
        data[pos] = e;
        // 更新列表长度
        len++;
        // 插入成功
        return true;
}

//删除函数
bool Seqlist::delete_pos(int pos)
{
    // 检查删除位置是否有效,如果位置无效或列表为空,则插删除失败
    if(pos<0 || pos>len || empty())
    {
        return false;
    }
    // 找到删除的位置,从后往前覆盖对应的值
    for(int i=pos;i<len-1;i++)
    {
        data[i]=data[i+1];
    }
    //更新列表长度
    len--;
    return true;
}

//扩充空间函数
void Seqlist::expend()
{
    size *=2;      //空间乘2
    datatype *newdata = new datatype(size);    //申请新的空间
    for(int i=0;i<len;i++)
    {
        newdata[i] = data[i];      //将旧空间的值插入到新空间内
    }
    delete [] data;               //删除旧列表数据
    data = newdata;
}

void Seqlist::delete_list()
{
    delete [] data;
}
int main()
{
        // 创建一个Seqlist对象q
        Seqlist q;
        
        // 初始化链表q,设置初始容量为4
        q.init(4);
        // 向链表中添加元素
        q.add(4);
        q.add(6);
        q.add(8);
        q.add(12);
        q.add(12);
        
        // 在索引3处插入数值20
        q.insert_pos(20,3);
        
        // 删除索引为2的元素
        q.delete_pos(2);
        
        // 输出链表的当前长度
        cout<<"链表长度: "<<q.length()<<endl;
        
        // 输出索引为3的元素值
        cout<<"第3个位置数据为"<<q.at_pos(3)<<endl;
        
        // 清空整个链表
        q.delete_list();
        

        return 0;
}

  • 28
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值