原始指针 raw pointer 非智能指针 smart pointer
指针是一个整数,一个数字,它存储一个内存地址。
创建指针:void* ptr = 0;
void指针表明不关心指针存储地址的数据类型。给该指针一个为0的内存地址,0其实不是一个有效的内存地址,没有办法读取或写入地址为0的内存。0无效意味着该指针无效。对指针来说,无效是可以接受的。指针为0也可以是NULL,# define NULL 0。C++中一个关键字叫做nullptr。
#include <iostream>
int main()
{
void* ptr = nullptr;//该指针完全没有类型,内存地址为0
std::cin.get();
}
程序中创建一个整数变量,该变量有一个内存地址,内存地址存储该变量。若要知道变量的存储地址,可以通过“&”运算符来实现。得到变量的存储地址存储在一个指针中。
#include <iostream>
int main()
{
int var = 8;
void* ptr = &var;//将变量var的内存地址作为指针赋给ptr变量
std::cin.get();
}
设置断点查看值
将ptr的值进行复制,然后调试-窗口-内存-内存1
该窗口将显示程序内的所有内存,将复制来的ptr的地址输入然后回车,就搜索到该地址。
该内存地址有8,因为我们创建了那个变量并且设置为8。该指针存放的地址里面的值为8。
指针是一个包含地址的变量。
指针可能是一个32、16、64位的整数。如果指针是void指针,计算机不会知道这个指针指的内存是几个字节,也就没有办法向这个内存中存入数据,此处就要牵涉到指针类型了。
#include <iostream>
#define LOG(x) std::cout << x << std::endl
int main()
{
int var = 8;
int* ptr = &var;//将变量var的内存地址作为指针赋给ptr变量
*ptr = 10;//解引用指针,访问指针的内存数据,读取或写入
LOG(var);
std::cin.get();
}
通过解引一个指针并写入它,实际就是在访问该块数据,写入该块内存。在实际的指针中,并没有说内存有多大。只有创建数组的时候会记录大小。以上创建的指针都是存内存的stack部分创建它,也可以在heap上创建变量。
向计算机申请指定大小的内存:char* ,char是一个字节。char* buffer = new char[8];//申请八个字节的内存,并返回指向这块内存的开始地址的指针
使用memset:用指定数据填充一块内存,接受一个指针buffer,该buffer指针指向这块内存的开始处。然后接受一个值,比如0。之后是填充字节,此处为8字节。memset(buffer,0,8);
#include <iostream>
#define LOG(x) std::cout << x << std::endl
int main()
{
char* buffer = new char[8];
memset(buffer,0,8);
std::cin.get();
}
由于使用了new这个关键字,所以该数据是分配在heap上的。 new[]和delete[]都是在heap上操作内存,最后还可以用buffer = nullptr;回收指针
指针的指针,一个变量存储着一个内存地址,它指向一个变量,这个变量也存储着一个内存地址。
创建一个double pointer(指针的指针)
int main()
{
char* buffer = new char[8];
memset(buffer,0,8);
char** ptr = &buffer;//ptr属于指针的指针,
delete[] buffer;//使用的是new[]来分配的,应该使用delete[]来删除
std::cin.get();
}
设置断点。根据ptr的地址搜索,然后,搜索到的地址由于电脑是小端的所以要逆序排,
(例如此处按照指针的指针搜索到的指针的地址是60 f6 bf 00,按照指针的地址搜索指针指向的值的时候就要输入00 bf f6 60进行搜索,得到指针指向的地址存储的buffer的值0)
到达buffer的内存位置。
16
Reference 引用 指针的扩展
在计算机如何处理两种关键字的角度看,指针和引用基本上是一回事。
引用:是指对某个已存在的变量的引用。对于指针来说可以创建指针变量并赋值nullptr或者其他等于0的量,但是引用不能。“引用变量”必须引用一个已存在的变量,它本身不是一个新的变量,并不真正占用内存,只是其他变量的引用。
引用时,创建变量类型+&,中间不加任何符号包括空格,例“int&”,&符号实际上是变量类型的一部分。
#include <iostream>
#define LOG(x) std::cout << x << std::endl
int main()
{
int a = 5;//创建变量
int& ref = a;//创建变量的引用
ref = 2;
LOG(a);//a的值变为2
std::cin.get();
}
创建了一个别名,因为这个ref“变量”不是变量,而是别称。ref变量并不真正存在,只存在于我们的源码里。ref可以与a一样使用。
在任何情况下,ref就是a,只是给a创建了一个别名。此处的引用并不是一个指针,只是在源码中的一种操作,如果我们希望给某个变量一个别名,引用更方便写代码。
假设想要一个函数使输入的整数递增。
#include <iostream>
#define LOG(x) std::cout << x << std::endl
void Increment(int value)
{
value++;
}
int main()
{
int a = 5;
Increment(a);//传值调用,调用过程中程序会拷贝参数值5到这个函数中
LOG(a);//a的值没有发生改变,value的值发生改变
std::cin.get();
}
结果是5,值没有改变。
由于想要引用传递(passing by reference) 这个变量来让他递增,故要改变a的值。通过向Increment函数中不是传递5、而是传递a这个变量的地址。通过函数找到这个变量的地址,找到变量的值5,然后加以更改。把内存地址传进函数,通过内存地址完成写入。做法:把函数的形参变成一个指针。在调用函数时会将a的内存而不是a本身传递给函数。
#include <iostream>
#define LOG(x) std::cout << x << std::endl
void Increment(int* value)//函数的形参变成一个指针
{
(*value)++;//改为解引用的形式从而改变地址存储的数值,而不是地址本身。递增符号优先级高于引用
}
int main()
{
int a = 5;
Increment(&a);//在调用函数时会将a的内存而不是a本身传递给函数。
LOG(a);
std::cin.get();
}
输出值为6
另一种方法,直接引用:
#include <iostream>
#define LOG(x) std::cout << x << std::endl
void Increment(int& value)//将指针形参改为引用的形式
{
value++;//不需要使用解引用形式
}
int main()
{
int a = 5;
Increment(a);//只需要传递a
LOG(a);
std::cin.get();
}
结果仍然是6
一旦声明了一个引用,就不能更改它所引用的对象;声明一个引用时,必须将一个实际变量赋值给它,不能只声明不赋值。
17
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)