C++阶段总结第二部分

第二部分 C++核心编程一

目录

第二部分 C++核心编程一

1,内存分区模型

1.1程序运行前

1.2程序运行后

1.2new操作符

2.引用

2.1引用的基本使用

2.2注意事项

2.3引用做函数参数

2.4引用做函数返回值

2.5引用的本质

2.6常量引用

3,函数的提高

3.1函数的默认参数

3.2函数占位参数

3.3函数重载


1,内存分区模型

C++在程序执行时,将内存大方向划分为4个区域

  • 代码区:存放函数体的二进制代码,由操作系统进行管理的
  • 全局区:存放全局变量和静态变量以及常量
  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

划分的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

1.1程序运行前

未执行该程序前分为两部分

代码区:

    存放CPU执行的机器指令

     代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可(.exe文件每次执行都是这一段代码)

     代码区是只读的,使其只读的原因是防止程序意外地修改了他的指令  (.exe文件不能被修改)

全局区:

      全局变量和静态变量存放在此

      全局区还包括了常量区,字符串常量和其它变量也存放在此(常量区包括:const修饰的全局常量和字符串常量)

      该区域的数据在程序结束后由操作系统释放(只要是局部定义的都不在全局区,不论是字符串还是字符)

如下一段程序代码运行结果:

#include<iostream>
#include<string>
using namespace std;

int aa = 10;
int bb = 11;

const int c_a_1 = 10;
const int c_b_1 = 10;

int main()
{
	int a = 10;
	int b = 11;

	static int a_1 = 10;
	static int b_1 = 10;

	string a_2 = "dasfaf";
	string b_2 = "hjkjhh";

	const int c_a_2 = 10;
	const int c_b_2 = 10;

	cout << "局部a=" << (int)&a << endl;
	cout << "局部b=" << (int)&b << endl << endl;

	cout << "全局aa=" << (int)&aa << endl;
	cout << "全局bb=" << (int)&bb << endl << endl;
	
	cout << "静态a_1=" << (int)&a_1 << endl;
	cout << "静态b_1=" << (int)&b_1 << endl << endl;

	cout << "常字符串=" << (int)&"adssasdf" << endl;
	cout << "常字符串=" << (int)&"dsaassaa" << endl << endl;

	cout << "局部字符串a_2=" << (int)&a_2 << endl;
	cout << "局部字符串b_2=" << (int)&b_2 << endl << endl;

	cout << "全常c_a_1=" << (int)&c_a_1 << endl;
	cout << "全常c_b_1=" << (int)&c_b_1 << endl << endl;

	cout << "局常c_a_2=" << (int)&c_a_2 << endl;
	cout << "局常c_b_2=" << (int)&c_b_2 << endl << endl;
	system("pause");
	return 0;
}

1.2程序运行后

栈区:由编译器自动分配释放,存放函数的参数值,局部变量等

注:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放,所以当自定义函数使用过后,局部变量就会被自动释放

int *ap(int a)
{
    a = 1;
    int b = 2;        //局部变量,放在栈上,函数执行,栈区的数据就被释放了
    return &a(或者return &b);        //返回局部变量地址,只能保留一次该数据
}

此时不论返回a的地址还是b的地址,都会出错,因为形参也是局部变量,所以当这个函数运行过后,都会被自动释放。

#include<iostream>
#include<string>
using namespace std;

int b = 1;
int *ap()
{
	int a = 1;        //局部变量,放在栈上,函数执行完,栈区的数据就被释放了
	return &a;        //返回局部变量地址
}

int *aq()
{
	return &b;        //返回全局变量地址
}

int main()
{
	int *p = ap();
	cout << "p=" << *p << endl;      //第一次可以打印正确数据,编译器做了保存
	cout << "p=" << *p << endl;      //第二次这个数据就不被保存了
	
	int *q = aq();
	cout << "q=" << *q << endl;      //因为返回的是全局变量的地址,所以不会被自动释放,只有程序结束后才会被释放
	cout << "q=" << *q << endl;      
	
	system("pause");
	return 0;
}

堆区:由程序员分配释放,如果程序员不释放,则程序结束时由操作系统回收

在C++中主要利用new在堆区开辟内存

指针本质上也是局部变量,放在栈上,指针保存的数据是放在堆区

int *ap()
{
    int *b = new int;        //定义堆区数据
    *b = 10;
    return b;        堆区的数据不会被释放
}

1.2new操作符

C++中利用new操作符在堆区开辟数据

堆区开辟的数据,由程序员手动开始,手动释放,释放利用操作符delete

语法:new 数据类型

利用new创建的数据,会返回该数据对应的类型的指针

    int *p = new int(10);     //堆区开辟一个数据
    delete p;       //释放该数据

    int *q = new int[10];     //堆区开辟一个数组
    delete[] q;     //释放该数组

2.引用

2.1引用的基本使用

作用:给变量起别名(两个变量的地址一样)

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

    int a = 10;
    int &b = a;

2.2注意事项

  • 引用必须初始化
  • 引用在初始化后,不可改变

    int a = 10, aa = 20;
    int &b = a;
    int &c; //错误,引用必须初始化
    &b = aa;//错误,初始化后,不可改变
    b = aa;//赋值操作

2.3引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针修改实参(可以参照值传递地址传递

void swap(int &a, int &b)         //引用传递交换两数的值
{
    int x = a;
    a = b;
    b = x;
}

#include<iostream>
#include<string>
using namespace std;

void swap(int &a, int &b)
{
	int x = a;
	a = b;
	b = x;
}

int main()
{
	int a = 10, b = 20;
	swap(a, b);
	cout << a << "  " << b << endl;
	system("pause");
	return 0;
}

2.4引用做函数返回值

作用:引用是可以作为函数的返回值存在的

注意:不要返回局部变量的引用(和不要返回局部变量地址类似)

用法:函数调用作为左值

int &test1() 
{
    int a = 10;       //错误,局部变量,系统只保存一次
    return a;
}

int &test2()
{
    static int b = 10;    //正确,全局变量
    return b;
}

特殊赋值方法,因为函数返回的是一个引用,所以仍然可以赋值:eg:test2() = 111;

2.5引用的本质

引用的本质在C++内部实现是一个指针常量

    int &a = b;     //转换为 int *const a=&b;
    a = 10;         //转换为 *a=10;

2.6常量引用

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

在函数形参列表中,可以用const修饰形参,防止形参改变实参

    const int &a = 10;    //转换为int b=10; const int &a=b;

const使用场景,在当作形参时使用,防止数据被误操作

void show(const int &a)
{
    //a = 20;    //错误,因为传递时为const所以不能改变
    cout << a << endl;
}

#include<iostream>
#include<string>
using namespace std;

void show(const int &a)
{
	//a = 20;    //错误,因为传递时为const所以不能改变
	cout << a << endl;
}

int main()
{
	int a=10;
	show(a);
	system("pause");
	return 0;
}

3,函数的提高

3.1函数的默认参数

在C++中,函数的形参列表中的形参可以是有默认值的

语法:返回值类型 函数名(参数=默认值){}

int test(int a = 1, int b = 2, int c = 3)
{
    return a + b + c;
}

注1:如果某个位置已经有了默认值,那么从这个位置往后,从左到右都必须有默认值
int test(int a = 1, int b, int c)       //错误

注2:如果函数声明有默认参数,函数实现就不能有默认参数‘(声明和实现只能有一个默认参数)

int test(int a = 1, int b = 2, int c = 3);
int test(int a = 1, int b = 2, int c = 3)        //错误,声明时,函数已经有参数了,所以实现不能有参数
{
    return a + b + c;
}

3.2函数占位参数

C++中函数的形参列表里可以有占位参数,用来占位,调用函数时必须填补该位置

语法:返回值类型 函数名(数据类型){}

void test1(int a, int)
{
    cout << "占位参数" << endl;
}

3.3函数重载

作用:函数名可以相同,提高复用率

满足条件:

  • 同一个作用域下
  • 函数名称相同
  • 函数参数不同或者个数或者顺序不同

返回值类型不可以作为函数重载的条件

我的另一篇关于重载的博客链接:https://blog.csdn.net/qq_46423166/article/details/106594280

函数重载的注意事项

  • 引用作为重载条件
  • 函数重载碰到函数默认参数

void test(int &a)
void test(const int &a)   //这两个可以构成重载

void test(int a)
void test(int a, int b = 10)    //因为包含默认参数,所以不能构成重载

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章