内存
程序中最重要的一件事,就是内存。当启动一个程序的时候,所有的代码都被载入到内存当中,内存中的所有的二进制指令都在告诉计算机你的代码需要做什么。
没有内存,计算机什么都做不了,而指针对于管理和操纵内存十分重要。
什么是指针
指针是一个整数,一种存储内存地址的数字。(类型与这无关)
简单解释:假如只有一条街道和一排的房子,这就是计算机中的内存;这条街上的每一个房子都是一个内存字节,而每一栋房子都有门牌号,这就是这个字节对应的地址。假如你想上门送/取货,即读写内存字节,门牌号(指针)就告诉了我们需要送/取货的房子(对应内存字节)在哪。
程序演示
空指针
我们可以知道,类型不会改变一个指针的实质:指针的实质就是一个内存地址,是一个整数。
下面是一份完整的空指针代码:
点击查看代码
#include <iostream>#define LOG(x) std::cout << x << std::endl;int main()
{void* ptr = nullptr;std::cin.get();return 0;
}
运行结果
这里可以看到空指针存储的内存地址值为x0x0000...
指针赋值
这里将会用指针赋值的方式来演示指针究竟是什么,以及其根本上有什么作用:
点击查看代码
#include <iostream>#define LOG(x) std::cout << x << std::endl;int main()
{int var = 1;int* ptr = &var;*ptr = 8;std::cin.get();return 0;
}
运行结果
从结果中我们可以看到,指针ptr存储了var的地址&var,此时ptr = &var
程序中我们使用了 " * " 来反引用指针ptr,并将这个内存地址上的值修改为了100。
由于ptr = &var
,通俗来说,我们作为为快递员,通过指针ptr
得到了门牌号(地址),知道了我们要送/取货的房子(内存字节),并使用 " * " 来敲门(反引用),将货物(值)送入了房子当中,进而将变量var
的值给改变了。
内存
通过内存就可以很清晰的看见,此地址下的内存被改变成了8。
上面的例子创建了一个整数,而一个整数是4字节的内存,所以我们知道指针指向的内存是4个字节。
但实际上,我们并不知道指针指向的数据有多大,因为指针并不包含数据,它只包含了内存地址。
通过new来创建指针
之前都是在栈上创造的内存,现在使用new可以在堆上创造内存。
点击查看代码
#include <iostream>#define LOG(x) std::cout << x << std::endl;int main()
{char* buf = new char[8];memset(buf, 0, 8);delete[] buf;std::cin.get();return 0;
}
运行结果
让我们看看在删除buf之前的值:
我们给指针分配了8个字节,用来存储数据的指针,指向数据开头。
内存
多重指针
还有另一点,指针同时也是变量,其存储的地址的值也会存储在某一内存地址中,那么就可以引申出用双重指针或三重指针等等,即指向指针的指针:
点击查看代码
#include <iostream>#define LOG(x) std::cout << x << std::endl;int main()
{char* buf = new char[8];memset(buf, 0, 8);char** ptr = &buf;delete[] buf;std::cin.get();return 0;
}
// 变量 <- 指针1存储变量的内存地址的值到某一内存地址中
// 指针1 <- 指针2存储指针1的内存地址的值到某一内存地址中
// 指针2 <- 指针3存储指针2的内存地址的值到某一内存地址中
运行结果
内存
二重指针ptr内存地址:
单重指针buf内存地址:
总结
指针只是存储内存地址的整数。