目录
第二部分 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函数重载
C++在程序执行时,将内存大方向划分为4个区域
划分的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
未执行该程序前分为两部分
代码区:
存放CPU执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可(.exe文件每次执行都是这一段代码)
代码区是只读的,使其只读的原因是防止程序意外地修改了他的指令 (.exe文件不能被修改)
全局区:
全局变量和静态变量存放在此
全局区还包括了常量区,字符串常量和其它变量也存放在此(常量区包括:const修饰的全局常量和字符串常量)
该区域的数据在程序结束后由操作系统释放(只要是局部定义的都不在全局区,不论是字符串还是字符)
如下一段程序代码运行结果:
#include
#include
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;
}
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
注:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放,所以当自定义函数使用过后,局部变量就会被自动释放
int *ap(int a)
{
a = 1;
int b = 2; //局部变量,放在栈上,函数执行,栈区的数据就被释放了
return &a(或者return &b); //返回局部变量地址,只能保留一次该数据
}
此时不论返回a的地址还是b的地址,都会出错,因为形参也是局部变量,所以当这个函数运行过后,都会被自动释放。
#include
#include
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; 堆区的数据不会被释放
}
C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开始,手动释放,释放利用操作符delete
语法:new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
int *p = new int(10); //堆区开辟一个数据
delete p; //释放该数据int *q = new int[10]; //堆区开辟一个数组
delete[] q; //释放该数组
作用:给变量起别名(两个变量的地址一样)
语法:数据类型 &别名=原名
int a = 10;
int &b = a;
int a = 10, aa = 20;
int &b = a;
int &c; //错误,引用必须初始化
&b = aa;//错误,初始化后,不可改变
b = aa;//赋值操作
作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参(可以参照值传递和地址传递)
void swap(int &a, int &b) //引用传递交换两数的值
{
int x = a;
a = b;
b = x;
}
#include
#include
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;
}
作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量的引用(和不要返回局部变量地址类似)
用法:函数调用作为左值
int &test1()
{
int a = 10; //错误,局部变量,系统只保存一次
return a;
}int &test2()
{
static int b = 10; //正确,全局变量
return b;
}
特殊赋值方法,因为函数返回的是一个引用,所以仍然可以赋值:eg:test2() = 111;
引用的本质在C++内部实现是一个指针常量
int &a = b; //转换为 int *const a=&b;
a = 10; //转换为 *a=10;
作用:常量引用主要用来修饰形参,防止误操作
在函数形参列表中,可以用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
#include
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;
}
在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;
}
C++中函数的形参列表里可以有占位参数,用来占位,调用函数时必须填补该位置
语法:返回值类型 函数名(数据类型){}
void test1(int a, int)
{
cout << "占位参数" << endl;
}
作用:函数名可以相同,提高复用率
满足条件:
返回值类型不可以作为函数重载的条件
我的另一篇关于重载的博客链接: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) //因为包含默认参数,所以不能构成重载