c++学习[03] 基础知识(下)
内存分区
四区
- 代码区:函数体二进制代码,由操作系统进行管理
- 全局区:全局变量、静态变量、常量
- 栈区:编译器自动分配释放,存放函数的参数值,局部变量
- 堆区:程序员分配和释放,拖程序员不释放,程序结束时由操作系统回收
程序运行前
编译后,生成exe可执行程序,未执行该程序前,分为两个区域:
1.代码区
存放CPU执行的机器指令
共享、只读
2.全局区
该区域的数据在程序结束后由操作系统释放
全局区中存放:
- 全局变量
- 静态变量(static)
- 常量
常量区:全局区里的一个特定子区域,专门存放编译期间就能确定的常量值。
存放:const修饰的全局变量和字符串常量
程序运行后
3.栈区
由编译器自动分配释放
存放:
- 函数的参数值
- 局部变量
注意不要返回局部变量 的地址,栈区开辟的数据由编译器自动释放!
返回后编译器会保留一次,但再访问就会出错,因为栈区数据已经释放了
4.堆区
由程序员分配内存,若程序员不释放,则程序结束时由操作系统回收
new 开辟内存
利用new关键字,可以将数据开辟到堆区
int * p = new int(10); // 堆区数据**的地址**用栈区指针保存
new返回的是该数据类型的指针
new和delete
堆区数据由管理员开辟和释放
释放堆区数据,利用关键字 delete
int * func()
{
int *p = new int(10); // new 开辟到堆区 在堆区创建整型数据
return p; // 返回指针
}
void test()
{
int *p = func(); // new p
cout<< *p <<endl;
cout<< *p <<endl;
cout<< *p <<endl; // 由管理员释放
delete p; // delete p 释放
cout<< *p <<endl; // 内存已释放,**非法**访问 报错,且打印不出来
}
// 在堆区用new开辟数组
void test2()
{
int * arr = new int[10]; // 10个元素的数组,返回首地址
for(int i=0;i<10;i++){
arr[i] = i+1 // 赋值;
}
// 释放堆区数组
delete[] arr; // []
}
引用
作用:给变量取别名
语法:数据类型 &别名 = 原名(即变量名)
注意事项
- 引用必须初始化
- 引用初始化后不能更改
int a = 10;
int b = 20;
// int &c; 错误
int &c = a;
c = b; // 赋值操作,不是更改引用(c是a的别名,两者共用一个内存空间)
引用做函数参数(引用传递)
让形参修饰实参
优点:可以简化指针修改实参
(值传递,地址传递都学过了)
引用传递:
void swap(int& a, int& b){
int temp = a;
a = b;
b = temp;
}
int main(){
int a = 10;
int b = 20;
swap(a,b);
cout<<a<<endl<<b<<endl;
return 0;
}
效果和地址传递相同,只是语法更清楚简单
引用做函数返回值
引用可以作为函数返回值
注意:不要返回局部变量引用 (栈区 编译器自动释放)
函数调用可作左值
int& test1(){
int a = 10; // 局部变量存放在**栈区**
return a;
}
![![[函数调用作左值.png]]](https://i-blog.csdnimg.cn/direct/9376f3e1af684f5988ed3f6864142a15.png)
![![[函数调用作左值输出.png]]](https://i-blog.csdnimg.cn/direct/4eb2f9ca8e0b4c3d948392208080ac52.png)
test调用完,返回引用(变量)
相当于 a = 1000;
ref2就是a的别名
如果函数的返回值是引用,这个函数调用可作左值
引用的本质
引用在c++内部实现是一个指针常量
// 发现是引用,转换为 int* const ref = &a;
指针常量:指向不能变,值可以变
这也就是了为什么引用在初始化后不能更改,而可以赋值
![![[引用的本质.png]]](https://i-blog.csdnimg.cn/direct/f0b6bb84c5b4496d88e69ad346bf91eb.png)
编译器扛下了所有~
常量引用
作用:主要用来修饰形参,防止误操作
在函数参数列表中,加const修饰形参,防止形参改变实参
// int & ref = 10; // 非法
// 引用必须引一块**合法的内存空间**
// 10、3.14、'a' 这样的**纯字面量**,是直接嵌入在机器指令的**立即数**中的。**没有独立的内存地址**。
const int & ref = 10; // 加上const
// 编译器将代码改为:
int temp = 10;
const int & ref = temp;
// 编译器帮你取原名
const 只读,不允许修改
void showValue(int &val){
val = 1000; // 引用传递=地址传递 更改了实参
cout<<val<<endl;
}
int main(){
int a = 100;
showValue(a);
cout<< a <<endl; // 1000
return 0;
}
// 防止误操作
void showValue(const int &val){ // 加const修饰
// 不能修改,报错
}
函数的默认参数
函数的参数列表中的形参可以有默认值
语法:返回值类型 函数名 (参数 = 默认值) {}
1.从右往左不能有跳过的
2.函数声明有默认值,则函数实现就不能有默认参数
函数的占位参数
![![[占位参数.png]]](https://i-blog.csdnimg.cn/direct/d030121525044c0b97205904c7319aa9.png)
函数重载

注意事项:![![[函数重载.png]]](https://i-blog.csdnimg.cn/direct/a21924bd81df4e67ba29c165f2089bde.png)
![![[函数重载注意事项.png]]![[函数重载注意事项2.png]]](https://i-blog.csdnimg.cn/direct/7adb5f503f0d4532bd293050f8565bd1.png)
结语
关于引用、默认参数、函数重载,还有一些补充的概念,推荐学习这几篇博客:
命名空间、输入输出:
c++入门(上)——lvy
缺省参数(默认参数)、函数重载、引用:
c++入门(中)——lvy
引用vs指针、内联函数、auto关键字、范围for:
c++入门(下)——lvy
终于,我们将来到类和对象~也是c++的核心思想:面向对象
更多推荐

所有评论(0)