在开始说前, 先给大家导入一个思想, 其实所有的程序, 在运行之前, 系统都要把程序的代码和数据导入到内存之中.
不知道大家有没有开过外挂,外挂的原理就是去修改内存.
举个例子:
你在玩一个游戏,你的角色的攻击力是1(因为你没充钱), 你想把它改成10000, 但是你又不想充钱,那你要怎么做呢?
答: 假如这个游戏中攻击力对应的变量是x, 那你就要找到x的内存地址, 把这个地址中的值改为10000, 那你就会发现, 你的攻击力变成了10000了!
进入正题!!!
重要的几点
- 每个变量都有对应的内存地址和对应的值 (不理解没关系, 下面有图)
- 变量声明的时候都会开辟新的内存地址 (引用的时候不会开辟新的内存地址, 引用不清楚没关系,下文的鲁迅会教你的!)
- 接下来的代码, 我都会把输出内容写在main函数最后的注释中.
&符号
先来看一段简单代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
}
我们定义了一个变量a,把5赋值给了a, 那么现在内存中是怎么样的呢?
现在的内存是这样的, 那我们现在怎么去取出a所对应的内存地址呢?
答: 在a变量前加取址符号"&"
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
cout<<&a<<endl;
// 输出
// 0x71fe4c
}
那现在我们可以得出,a在内存中就是
你可能会问:"0x71fe4c"是什么意思呢?
答: "0x71fe4c"表示一个16进制数,在这里,它是a的内存地址
OK~接下来来看这个代码!
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int &b = a;
}
纳尼? 变量声明 + 取地址符号, 晕了晕了...
其实, 这个时候"&"符号的作用不再是"取地址"了, 它现在的作用是"引用".
怎么理解"引用"呢? 我们接下来来看个图
其实咧, 鲁迅和周树人指的都是一个人!!! 那我们可以说, 鲁迅是周树人的引用, 或者周树人是鲁迅的引用, 2个名称指的都是同一个人!!! 所以抓捕周树人就是抓鲁迅呀.
现在我们看看上面的代码
int &b = a, 这表示我们声明一个引用变量b, b是a的别名.(这个时候不会为b开辟新的内存地址)
那么这个时候, a,b的内存地址和值都是一样的.
不信? 我们输出一下他们的地址和值.
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int &b = a;
cout<<"a,b的地址:"<<&a<<" "<<&b<<endl; // 在这里&是取指符号
cout<<"a,b的值:"<<a<<" "<<b<<endl;
// 输出
// a,b的地址:0x71fe34 0x71fe34
// a,b的值:5 5
}
现在内存如下:
这时候, 假如我们修改了b的值, 那a的值会变吗?
答: 会! 看下面代码.
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int &b = a;
b = 100;
cout<<"a,b的地址:"<<&a<<" "<<&b<<endl; // 在这里&是取指符号
cout<<"a,b的值:"<<a<<" "<<b<<endl;
// 输出
// a,b的地址:0x71fe34 0x71fe34
// a,b的值:100 100
}
可以看出, 修改了b的值,a和b的值都变了. (本质上就是修改内存中的值嘛)
接下来我们来总结一下 "&"这个符号
1. 在变量声明的时候, "&"表示该变量是一个引用类型的变量.(必须有另外一个变量赋值给该变量,否则不给编译!)
2. 不在变量声明的时, "&"表示取出该变量的内存地址
*符号
我们现在已经可以取出a的地址了, 那我们是否可以存储这个地址呢?
答: 可以! 我们可以声明一个指针变量来存储a的地址, 把a的地址赋值给它
你可能又会问, 什么是指针变量呢?
答: 指针变量就是指: 该变量的值是一个地址.
接下来上代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int *p;
p = &a;
cout<<p<<endl;
// 输出
// 0x71fe44
}
int *p 表示声明一个变量p, p是一个int类型的指针.
首先, 你可能会问: p是一个int类型的指针是什么意思呢?
答: 它表示p的值是一个地址,而且这个地址对应的值是一个int类型的. (不理解没关系,下面有图可以让你理清关系).
而p = &a, 表示把a的地址赋值给p, 那现在p的值就是a的地址.
如果此时我们要取p的值(内存地址)对应的值, 我们应该怎么做呢? (不理解没关系,下面有图)
答: 用"*p" (注意现在这个*和int *p这的*功能不一样喔)
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int *p;
p = &a;
cout<<*p<<endl;
// 输出
// 5
}
问: 怎么得到p对应的内存地址呢?
答: 用上面所学的"&", "&p"就可以取出变量p的内存地址.
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 5;
int *p;
cout<<&p<<endl;
// 输出
// 0x71fe40
}
OK,接下来我画个图, 看看a和p在内存中是怎么样的
这应该很直观了吧~ (为了把a和p的关系看得更清楚, 我自己画了个箭头)
接下来我们来总结一下 *这个符号
1. 在变量声明的时候, *表示该变量是一个指针变量.
2. 不在变量声明时, *表示取出内存地址中的值 (通常是把内存地址赋值给一个指针类型的变量, 然后通过" *变量名 "来取出内存地址的值)
综合实例(交换2个变量的值)
我们来看这一段代码, 看看它究竟能不能交换2个数的值
#include<bits/stdc++.h>
using namespace std;
void swap(int x,int y){
int t = x;
x = y;
y = t;
}
int main(){
int a,b;
a = 1;
b = 2;
cout<<"交换前的值 a,b : "<<a<<","<<b<<endl;
swap(a,b);
cout<<"交换后的值 a,b : "<<a<<","<<b<<endl;
// 输出
// 1 2
// 1 2
}
答案是不能!!! 为什么呢?
答: 因为在调用函数swap(a,b)的时候, 进入swap函数时, x,y会开辟新的内存地址. 不信我们输出一下a,b,x,y的内存地址.
#include<bits/stdc++.h>
using namespace std;
void swap(int x,int y){
int t = x;
x = y;
y = t;
cout<<"x的地址: "<<&x<<endl;
cout<<"y的地址: "<<&y<<endl;
}
int main(){
int a,b;
a = 1;
b = 2;
cout<<"a的地址: "<<&a<<endl;
cout<<"b的地址: "<<&b<<endl;
swap(a,b);
// 输出
// a的地址: 0x71fe4c
// b的地址: 0x71fe48
// x的地址: 0x71fe20
// y的地址: 0x71fe28
}
可以看出,a的内存地址不等于x的内存地址, b的内存地址也不等于y的内存地址.
那如果要让a和x的内存地址一样,b和y的内存地址一样,我们要怎么做呢?以及为什么我们要这样做呢?
答: 我们可以用上面教的"&"符号来表示引用. 这样我们就可以通过操作x,y变量来改变a,b变量的值 (因为x,y和a,b的内存地址是一样的).
#include<bits/stdc++.h>
using namespace std;
// 之前是swap(int x,int y)
void swap(int &x,int &y){
int t = x;
x = y;
y = t;
cout<<"x的地址: "<<&x<<endl;
cout<<"y的地址: "<<&y<<endl;
}
int main(){
int a,b;
a = 1;
b = 2;
cout<<"a的地址: "<<&a<<endl;
cout<<"b的地址: "<<&b<<endl;
cout<<"交换前的值 a,b : "<<a<<","<<b<<endl;
swap(a,b);
cout<<"交换后的值 a,b : "<<a<<","<<b<<endl;
// 输出
// a的地址: 0x71fe3c
// b的地址: 0x71fe38
//交换前的值 a,b : 1,2
// x的地址: 0x71fe3c
// y的地址: 0x71fe38
// 交换后的值 a,b : 2,1
}
可以看出, 这个时候a和x的内存地址是一样的, x和y的内存地址是一样的.而且我们也交换成功了!
假如我们现在不用引用, 我们是否有另外的方法交换2个变量的值呢?
答: 肯定可以呀. 我们接下来用指针的方式.
#include<bits/stdc++.h>
using namespace std;
// 之前是swap(int x,int y)
// swap(int &x,int &y)
void swap(int *x,int *y){
int t = *x;
*x = *y;
*y = t;
}
int main(){
int a,b;
a = 1;
b = 2;
cout<<"交换前的值 a,b : "<<a<<","<<b<<endl;
swap(&a,&b);
cout<<"交换后的值 a,b : "<<a<<","<<b<<endl;
// 输出
// 交换前的值 a,b : 1,2
// 交换后的值 a,b : 2,1
}
可以看出交换成功了, 为什么呢?
答: 因为我们把a的地址传递给了x, b的地址传递给了y, 然后再对这2个内存地址进行操作, 我又来画图了! (截屏不够大,我只能把这个图片分为2次发哈~)
很直观吧!!!
OK,接下来我们来看这一段代码.
#include<bits/stdc++.h>
using namespace std;
int main(){
int a = 10;
int* p1 = &a;
int* &p2 = p1;
}
这里面 int* &p2 是什么东西啊?
我们运用一下总结的 * 和 & 的作用.
int* &p2 中的 * 和 & 都用在变量声明, 所以 int* 表示p2是一个指向int类型的指针, 而&p2, 表示p2是一个引用.
那现在我再画个图,你们就知道啦~
如何证明呢? 我们来输出他们的值和地址.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a = 10;
int* p1 = &a;
int* &p2 = p1;
cout<<"a的地址: " <<&a<<" "<<"a的值:"<<a<<endl;
cout<<"p1的地址: " <<&p1<<" "<<"p1的值:"<<p1<<endl;
cout<<"p2的地址: " <<&p2<<" "<<"p2的值:"<<p2<<endl;
// 输出
// a的地址: 0x71fe34 a的值:10
// p1的地址: 0x71fe28 p1的值:0x71fe34
// p2的地址: 0x71fe28 p2的值:0x71fe34
}
搞定!!!
最后
如果有不正确的地方, 欢迎各位指出哈,如果你们觉得有收获, 就给我点个赞哈~