C++学习笔记(6):内存四区、引用、函数高级


本博文是学习黑马程序员C++视频时做的笔记,记录一下只是方便温故知新,不做其他用途。

一、内存四区

程序运行前

1.1 全局区

(1)用于存放全局变量和静态变量;
(2)里面细分有一个常量区,字符串常量和其它常量也存放在此。
(3)该区域是在程序结束后由操作系统释放。

1.2代码区

(1)存放CPU执行的机器指令;
(2)代码区是共享的,频繁执行的程序只需要内存中的一份代码;
(3)代码是只读的,防止意外修改。

程序运行后

1.3 栈区

(1)由编译器自动分配释放,存放函数的形参、局部变量等。
(2)注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。

1.4 堆区

一般由程序员手动分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收。

new操作符
作用:在堆区开辟数据;
delete操作符
作用:手动释放堆区开辟的数据。

二、引用

2.1 引用的基本语法

语法:数据类型 &别名 = 原名

#include<iostream>
using namespace std;

int main()
{
//    基本语法
//数据类型 &别名 = 原名
    int a = 10;
    int &b = a;
    cout<<"a="<<a<<endl;//10
    cout<<"b="<<b<<endl;//10

//因为操作的是同一块内存
    b = 100;
    cout<<"a="<<a<<endl;//100
    cout<<"b="<<b<<endl;//100
}

2.2 引用的注意事项

1 引用必须初始化
2 引用在初始化后,不可以改变

#include<iostream>
using namespace std;

int main()
{
    int a = 10;
//    1 引用必须初始化
//    int &b;
    int &b = a;
    cout<<"b="<<b<<endl;//10

//  2 引用在初始化后,不可以改变
    int c = 20;
    b = c;//赋值操作,而不是更改引用

    cout<<"a="<<a<<endl;//20,指向同一块内存,所以a也发生改变
    cout<<"b="<<b<<endl;//20
    cout<<"c="<<c<<endl;//20
}

2.3 引用做函数参数

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

通过值传递、地址传递、引用传递进行对比

#include<iostream>
using namespace std;

void MySwap01(int a,int b)
{
    int temp = a;
    a = b;
    b = temp;
    cout<<"01a1="<<a<<endl;//20
    cout<<"01b1="<<b<<endl;//10
}
void MySwap02(int *a,int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
    cout<<"02a1="<<*a<<endl;//20
    cout<<"02b1="<<*b<<endl;//10
}

void MySwap03(int &a,int &b)
{
    int temp = a;
    a = b;
    b = temp;
    cout<<"03a1="<<a<<endl;//20
    cout<<"03b1="<<b<<endl;//10
}

int main()
{
    int a1 = 10;
    int b1 = 20;
//值传递:可以想象改变的只是实参的“替身”的值,而实参本身不会被改变
    MySwap01(a1,b1);
    cout<<"a1="<<a1<<endl;//10
    cout<<"b1="<<b1<<endl;//20
//地址传递 通过指针实现
    int a2 = 10;
    int b2 = 20;
    MySwap02(&a2,&b2);
    cout<<"a2="<<a2<<endl;//20
    cout<<"b2="<<b2<<endl;//10
//引用传递 通过引用实现
    int a3 = 10;
    int b3 = 20;
    MySwap03(a3,b3);
    cout<<"a3="<<a3<<endl;//20
    cout<<"b3="<<b3<<endl;//10
}

2.4 引用做函数返回值

1 不要返回局部变量的引用;
2 函数的调用可以作为左值。

#include<iostream>
using namespace std;

//1 不要返回局部变量的引用
int& test01()
{
    int a = 10; //局部变量存放在栈区
    return a;
}
//2 函数的调用可以作为左值
int& test02()
{
    static int a = 10;//静态变量存放在全局区
    return a;
}
int main()
{
    int &ref = test01();
    cout<<"ref="<<ref<<endl;//10,第一次结果正确,是因为编译器做了保留
    cout<<"ref="<<ref<<endl;//0,a的内存已经释放

    int &ref2 = test02();
    cout<<"ref2="<<ref2<<endl;//10
    cout<<"ref2="<<ref2<<endl;//10
}

2.5 引用的本质

本质:在C++内部实现一个指针常量

#include<iostream>
using namespace std;
//发现是引用转换为int* const ref = &a
void func(int& ref)
{
    ref = 100;
}
int main()
{
    int a = 10;

    int& ref = a;
    ref = 20;

    cout<<"a:"<<a<<endl;//20
    cout<<"ref:"<<ref<<endl;//20

    func(a);
    cout<<"ref:"<<ref<<endl;//100
    return 0;
}

2.6 const 修饰引用形参

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

#include<iostream>
using namespace std;
//打印数据
//用const修饰形参
void func(const int &a)
{
//    a = 1000;//报错,就是为了防止误操作
    cout<<"01a="<<a<<endl;
}
int main()
{
//常量引用
//使用场景,用来修饰形参,防止误操作
//    int a = 10;
//    加上const后,编译器相当于int temp = 10; int &ref = temp;
//    int &ref = 10;//报错,应改为下面
//    const int &ref = 10;//引用必须引一块合法对的内存空间
//    ref = 20;//报错,加入const变成只读,不可修改

    int a = 100;
    func(a);
    cout<<"a="<<a<<endl;//100
    return 0;
}

三、函数高级

3.1 函数默认参数

如果传入了数据,那么就用传入的数据,否则就用默认参数

#include<iostream>
using namespace std;
//打印数据
int func(int a,int b=20 ,int c=30)
{
    return a+b+c;
}
int main()
{
//    如果传入了数据,那么就用传入的数据,否则就用默认参数
    cout<<func(10,30)<<endl;//70
}

注意:1 如果某个位置有了默认参数,那么从左到右必须有默认参数。

int func(int a,int b=20 ,int c);错误
int func(int a,int b=20 ,int c=30);正确

2 如果函数声明有默认参数,那么函数实现就不能有默认参数

int func(int a=10,int b=20 ,int c=30)int func(int a,int b ,int c)
{
    return a+b+c;
}

3.2 函数占用参数

形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置。

#include<iostream>
using namespace std;
//语法:返回值类型 函数名(数据类型){}
void func(int a,int)
{
    cout<<"this is func!"<<endl;
}
int main()
{
//    调用时需要把参数写全
    func(10,30);
}

3.3 函数重载

作用:函数名相同,提高复用性
条件:
(1)同一作用域下;
(2)函数名称相同;
(3)函数参数类型不同 或者 个数不同 或者顺序不同。

#include<iostream>
using namespace std;

void func()
{
    cout<<"func()!"<<endl;//70
}

void func(int a)
{
    cout<<"func(int a)!"<<endl;//70
}

void func(double a)
{
    cout<<"func(double a)!"<<endl;//70
}

int main()
{
    func();//func()!
    func(10);//func(int a)!
    func(3.14);//func(double a)!
}

函数重载的注意事项:
(1)引用作为重载条件
(2)函数重载碰到函数默认参数

#include<iostream>
using namespace std;

//1 引用作为重载条件
void func(int &a)//int &a = 10;不合法
{
    cout<<"func(int &a)!"<<endl;
}

void func(const int &a)//const int &a = 10;合法,const让编译器创建临时空间
{
    cout<<"func(const int &a)!"<<endl;
}
//2 函数重载碰到默认参数
void func2(int a,int b = 10)
{
    cout<<"func(int a,int b = 10)!"<<endl;
}
void func2(int a)
{
    cout<<"func(int a,int b = 10)!"<<endl;
}

int main()
{
    int a = 10;
    func(10);//func(const int &a)!
    func(a);//func(int &a)!
//    func2(a);//当函数重载碰到默认参数,出现二义性,报错
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值