理解C++的指针

本文是新手零基础学习C++对指针、数组和结构的理解和笔记,有些凌乱和语无伦次,只是将想法记录下来,在以后忘了或者概念不清的时候看看。如理解有误,敬请各位请前辈不吝指教,不胜感激。

定义

在C++基础教程中指针一般被定义为:存放地址的变量。
我们可以把指针变量看做一个矢量,它有大小(sizeof 运算符可查字节),有方向(从栈出发,指向堆的一个地址)。声明指针,就是为它指定大小;指针的赋值,就是给它指定方向。指针的大小并不是真的占了多大空间,而是由它的类型来决定大小,例如存放一个字节 char 类型的字符指针,占据的内存空间为 4 字节(32位)。
指针在赋值时用引用 & 加一个变量,所以引用是右值,它仅仅是一个变量的地址;指针是左值也可以是右值,它不仅仅是一个地址,还包括了地址所指数据所占空间的大小。所以,引用可以被看为是半指针,或者叫单位矢量,有方向没大小的指针。

传值、传引用和传指针

理解了指针,在函数的参数传递中,传值、传引用、传指针概念就清楚了。
函数值传递就是右值传递,由被调函数的形参来接收右值,建立主调函数中变量的一个副本,可以理解为形参的“实例化”。有时候右值很大,比如读取一个10MB文件第80个字节处存储的 8 字节数据。在形参实例化时,被调函数将在内存中建立一个10MB文件的拷贝,这将非常浪费时间,此时就需要传引用。传引用只需要将这个文件的首地址传递给被调函数,由函数将这个地址向后偏移80个字节,再读入8字节数据即可。这样操作,程序的开销会非常小,CPU对付的都是字节级别的运算,而不是10MB(十亿字节)的运算。这就是在lisp中用ActiveX对象操作大文件的效率,远低于DWX读入文件效率的原因,因为DWX直接传递地址给Windows API,在被调函数中偏移这个地址即可读入需要的数据。由于传引用没有建立副本,所以如果改变了形参的值,也就改变了实参的值。相当于在主调和被调函数中建立了一个双向数据通道,而值传递是单项的。
引用传递和指针传递容易混淆的地方,他们的效果几乎相同,具有参数传递的双向性,具有参数传递的高效性–传递的内容都是地址。区别是传指针就相当于全局变量,在被调函数对指针的任何操作,和在主调函数中操作变量没有区别;而传引用,仅仅传递的是地址,地址可以进行偏移运算,但不能对主调函数中的变量直接操作,需要时还得按地址载入固定字节的数据,建立副本后进行间接操作,因为引用只是半指针,它没大没小。
另外指针可以为NULL,即有大小没方向;而引用不能为空,它本身没大小,再没有方向就什么也不是了。指针是左值,引用是右值,右值可以赋值给左值,左值不能复制给右值。
栈属于CPU的高速缓存,比内存快1000倍,被优化为两个指令:压入和弹出。它的空间有限,分配给一个线程的空间更加有限。函数指针和引用传递一次,占据了一个单位栈空间,当函数调用完毕原路返回后,才会释放栈空间。但是在递归调用时,未达到递归终止条件前,函数不会原路返回,占用的栈空间也不会释放,所以递归函数嵌套或循环次数超过一定数量,就会出现堆栈溢出的错误。Windows 栈空间一般为 2MB,一个地址占据 8 字节(64位),所以递归循环的次数一般不会超过 200000/8 的上限,栈空间分配给函数的大小可以调整。

数组与结构的遍历

理解了指针,可以用地址的偏移来直接遍历多维数组和结构。数组和结构在内存里是按一维连续存储的,所以指针也是连续的。数组和结构的指针指向第一个数据的地址,这里为什么不说是数组的引用,因为这个地址每增加1,就会指向数组或结构的下一个值,说明这个地址具有大小的属性,那么它就是指针。如果是引用,引用增加1(向右偏移1)只是指向内存的下一个字节,一个 int 类型的数据,占 4 个字节,需要引用 + 4 的操作才能相当于指针 +1,而指针 +1 不必关心数据类型,它总是指向下一个数据单元(堆空间的存储是从低地址到高地址方向,所以读取数据是地址的加法操作。)
下面我用一维 for 循环来遍历多维数组,这样的好处是不必担心数组的越界操作。

#include <iostream>
void main()
{   int iArry[3][4] = {{3,4,5,6},{1,2,3,4},{20,50,90,100}}; //数组初始化
    int* piArry = &iArry[0][0];                //数组的指针
    int lengthArry = sizeof(iArry) / sizeof(piArry); //数组元素个数
    for (int i = 0; i < lengthArry; ++i)  //单层for循环
    {std::cout << * (piArry++) << "  " ;} //指针+1,遍历数组
}

这样,我们不必关心数组的维数以及每一维数组的长度,用指针就可以直接遍历操作,包括数组的读取与存储。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yxp_xa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值