指针
我们要知道,计算机只处理内存,再编程过程中,内存就是一切。当我们运行程序时,所有程序会载入内存,CPU就这样访问程序并开始执行指令。
所以,当创建一个变量,计算机会从磁盘加载数据,然后将所有的都存储在内存中。
那么,在这个当中,指针就发挥着管理和操纵内存的作用。
【理解指针和内存】
内存就像一条街道上的一排排房子,而房子上都会有一个号码和地址,指针就是房子的地址。指针告诉我们房子在哪里
指针只是一个整数,一种存储内存地址的数字,与类型无关,所有类型的指针都是保存内存地址的整数。
例子:
void* ptr = 0; // 0不是一个有效的内存地址;意味着这个指针是无效的,程序会崩溃
void* ptr = NULL;
void* ptr = nullptr;
【每个变量都有一个内存地址】
每个变量都需要一个地方来存储,可以用&来获取变量的内存地址
int var = 8;
void* ptr = &var;
var的地址为:0x0057FB7C, var的地址可以用&来获取,可以将内存地址赋值给指针变量ptr
【指针类型转换】
int var = 8;
double* ptr = (double*)&var;
【逆向引用】
假设有一个指针指向某个数据,然而现在想写入或读取这个数据。
如何访问这些数据,靠逆向引用。(指针的*符号通常被称为dereference运算符)
int var = 8;
int* ptr = &var;
*ptr = 10;
指针并不知道变量的内存大小,不知道指针指向的数据有多大
【char*指针】
char* buffer = new char[8];
memset(buffer, 0, 8);
delete [] buffer;
一个字符占一个字节,分配了8个字节的内存;并返回指向那片内存的地址的第一个
memset(buffer, 0, 8); 用指定的数据来填充内存,接收一个指针,指针将会是内存块开始的指针,取值0; 取内存的大小为8
**delete [] buffer;**可以使用memset来申请堆内存,当用完之后,应该删掉
【双指针】
指针本身也是类型,这些变量也存储在内存中, 所以,可以得到双指针: 指向指针的指针
char* buffer = new char[8];
memset(buffer, 0, 8);
char** ptr = &buffer;
delete [] buffer;
ptr指向的变量是buffer的内存地址
指针有点像字典:{键:值}, 键是变量的地址,值是变量存储的数据
引用
引用是指针的扩展;计算机用引用和指针做的事情是一样的;只是在书写上有点区别;
- 引用是指针的伪装;
- 引用是在指针上的语法糖,更容易阅读,更容易理解;
- 引用是一种引用现有变量的方式
- 引用必须引用现有的变量,引用本身不是新的变量,不占用内存
int a = 5;
int& ref = a;
ref不是一个真正的变量,只存在源代码中,编译的时候,不会得到两个变量a和ref,而是只有a
a和ref是一样的,同一个变量
【函数引用】
void Increment(int value)
{
value++;
}
int a = 5;
Increment(a);
LOG(a);
如果直接传入a变量,由于函数的参数会新建一个变量value,所以value++不会影响到外部变量a的值,打印还是a=5
如何通过将变量a传递到函数中来修改它
可以把变量a的内存地址传递进函数
- 指针法:
void Increment_ptr(int* value)
{
(*value)++;
}
需要传递指针,然后再逆向引用指针
- 引用法:
void Increment_ref(int& value)
{
value++;
}
代码更简洁
【不能改变引用的东西】
int c = 5;
int d = 8;
int& ref = c;
ref = d;
LOG(ref);
没有发生实际的引用改变,而是只是将c的值变成了8(即d的值)而已,ref的引用还是c
- 修改了c = 10, ref也会变成10
int c = 5;
int d = 8;
int& ref = c;
ref = d;
LOG(ref);
c = 10;
LOG(ref);
【更改引用】
只能用指针
int e = 5;
int f = 8;
int* m_ref = &e;
*m_ref = 2;
m_ref = &f;
*m_ref = 1;
LOG(e);
LOG(f);
先引用e,更新m_ref的值为2, 同时e的值更新为2; 然后修改引用为&f,更新m_ref的值为1, 同时f的值更新为1