C++ Pointer指针
众所周知,C++是一门高级语言,但却是一门比较贴近底层的高级语言,今天,让我们一起来学习一下C++和C语言中最重要的一个语言特性——指针(Pointer)
我自己的C++学习小群(尽管现在只有我一个人(或许现在有两个人)):洛谷的团队向着胜利奔赴 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
引入
下面让我们看一个非常经典的例子:swap(交换)。
当我们有两个变量a,b时,我们要在函数里交换它们的值,你会怎么做呢?
如果你不知道指针,你会这样做:
#include<bits/stdc++.h>
using namespace std;int swap(int a, int b)
{int tmp = a;a = b;b = tmp;
}int main()
{int a, b;cin >> a >> b;swap(a, b);cout << a << ' ' << b;
}
恭喜你,当你运行这段代码时,结果是:
[in]
11 12
[out]
11 12
答案很明显是错误的。
此时你会发现,其实两个变量的值并没有交换,为什么呢?因为传进函数的值其实是一个副本,当你交换两个变量时,交换的并不是并不是原来的变量,而是两个副本,自然交换结束后,也就是函数结束后,原来变量的值是没有改变的。
相当于你传进去的是一个const int常量,而常量是不可以修改的,于是他又创建了一个int,而这个int已经不是原本的int了,而你在main函数中使用的是原来未经修改的const int。
那么怎么做呢?
指针是什么
指针存放的是另一个变量的内存地址
指针就是内存地址,指针变量就是用来存放内存地址的一个变量
指针的基础操作
声明指针
type* pointer = &var;
其中,var是数据,“&”代表取变量地址,它的意思,就是让pointer的地址设为var的地址。
指针类型:“type*”
取地址
获得一个变量的内存地址,其实刚刚我们已经讨论过了,就是通过“&”运算符,来获取对应变量的地址。
cout << &11;
这个代码输出的并不是11,而是11的内存地址,因为“&11”表示的是11的内存地址(16进制表示),而不是11。
输出指针
int* p = &11;
cout << p;
现在你应该对指针有一点了解了,我觉得,你可能能猜到这段代码输出的是什么。其实他输出的和上一段代码是一样的,它只是增加了一个中间变量而已,输出的同样是11所在的内存地址。
取数据
指针存储的是一个变量的内存地址,如果他无法返回它存储的变量的话,那么它的存在就没有意义了,那么怎么取数据呢?
*pointer
在C++中,“*”既可以用来声明指针变量,也可以用来取数据,比如说
int p = &11;
cout << *p;
这段代码会输出什么呢?答案是11,因为第一步它把11的地址赋给了p,让后输出了p指针存放的数据,也就是取出了11(不是11的内存地址),因此输出11。
交换两个变量
现在我们应该知道如何交换两个变量的值了,我们先声明一个swap函数,而它的参数是两个指针,这就可以保证尽管传进来的是两个不同的指针,但是他们指向的内存地址是相同的。
int swap(int* a, int* b);
而下面交换变量就可以交换两个指针变量存储的数据的值了:
int swap(int *a, int *b)
{int tmp = *a;*a = *b;*b = tmp;
}
而main主函数中,传入的参数并不是int类型,而是int*指针类型:
int main()
{int a, b;cin >> a >> b;swap(&a, &b);cout << a << ' ' << b;
}
[in]
11 12
[out]
12 11
这样就可以得到一个准确的结果。
当然你也可以通过和scanf一样的方法,在函数里传引用,但实际上,如果你查看汇编代码就会发现,引用的底层和指针时同一种东西。具体用指针还是用引用,就是一个仁者见仁智者见智的问题了。
动态数组
众所周知,在数组长度可能很大时,开静态数组是很占空间的;但如果在主函数里根据n(长度)的值视情况开数组,又有可能会栈空间超限。因此我们可以有两种解决方式:
链表
链表的实现相对而言比较复杂,因此我单独写了一篇文章介绍链表:
C++ 链表详解_嘉定世外的JinJiayang的博客-CSDN博客
相对而言我认为还是比较详细的(看完记得点赞!)。
当然链表当中也会大量运用到指针的知识,所以最好在学会指针后再学习链表。
指针实现
一维数组模拟
我们可以声明一个数组
int *p = new int[len];
并将数组的首地址赋给p,然后就可以像普通数组一样进行操作了,这样就既可以让数组的大小是动态的,又操作简单
#include<bits/stdc++.h>
using namespace std;
int main()
{int n; cin >> n;int* p = new int[n+2];for(int i=1; i<=n; i++) cin >> p[i];for(int i=1; i<=n; i++) cout << p[i] << " ";
}
二维数组模拟
那如果我们希望一个二维数组怎么办?比如说我要打印一张乘法表。
我们同样可以用刚刚的方法进行模拟。
首先同样有一个指针p,但是它的值不再是new int[n+2],而是new int*[n+2],它指向的数组里面存储的是指针;在给一个个值进行赋值的时候,我们再将p指针里的每个指针(即每一行)都像一维数组那样进行声明,p[i] = new int[n+2],那么然后再将p指针指向的数组里面的指针指向的数组里面的值赋值,比如说赋我们需要的乘法表的值(i*j)。
注意:现在p指针存储的是一个二维数组,因此它是一个指向指针的指针——双重指针,需要写两个“*”号
如果刚刚那句话有一点难理解,没关系,你想一想p指针这个数组里面是什么,是不是也是指针(数组),因此它是双重的,是指向指针的;你也可以理解为,它就是一个数组,一个二维数组,那它自然是一个双重指针了。同理,如果你要一个三维数组,就需要一个三重指针,因为它是一个指向一个指向指针的指针的指针。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{cin.tie(), cout.tie();int n;int **p;cin >> n;p = new int*[n+2];for(int i=1; i<=n; i++){p[i] = new int[n+2];for(int j=1; j<=n; j++)p[i][j] = i*j; }for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) cout << p[i][j] << ' ';cout << endl;}
}
指针总结
C++的指针是非常灵活,同时也是功能非常强大的,它可以让一段程序变得简洁,或易于扩展,比其它语言具有更大的优势,比如说Python中就没有指针,只能通过
import ctypesvar = ctypes.py_object
var.value = ...pointer = ctypes.POINTER(var)
来使用指针,但其实内部也是通过C/C++实现。
但是指针如果用不好,更容易引发各种各样的问题,如内存泄漏等。
作为一位C++的Programmer,学习指针是非常有必要的。当然,如果你是一位初学者,立刻完全掌握指针是毫无可能的,我们更要多练习。
如果你已经完全掌握了这一部分内容的话,推荐你看我的这篇文章,关于C++的链表和链式存储:
C++ 链表详解_嘉定世外的JinJiayang的博客-CSDN博客
Time to 点赞
看完后,别忘了
点赞!
收藏!
Thanks……
C++ Pointer指针相关推荐
- Golang unsafe.Pointer指针
相较于 C 而言,Go 语言在设计时为了使用安全给指针在类型和运算上增加了限制,这让Go程序员既可以享受指针带来的便利,又避免了指针的危险性.除了常规的指针外,Go 语言在 unsafe 包里其实还通 ...
- Pointer 指针
Pointer 指针 利用指针访问对象,指针指向一个对象,允许使用解引用符(操作符*)来访问对象int ival = 42; int *p = &ival;//p存放变量ival的内存地址,p ...
- plc的指针和c语言指针,关于STEP7 Pointer指针的问题
buffer声明为pointer输入变量,DB_ID声明为word临时变量 L 最佳答案 1:首先需要了解 POINTER 的结构 POINTER是一个类似于C语言中指向指针的指针 见图1 POINT ...
- js this pointer 指针
this JavaScript的函数内部如果调用了this,那么这个this到底指向谁? 答案是,视情况而定! 如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的 ...
- 内存管理-定时器循环、内存布局、tagged pointer、weak指针、copy、自动释放池
先上代码,我们平时用的定时器,cadisplaylink.nstimer,CADisplayLink.NSTimer会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用 ...
- 第七章 右左法则----复杂指针解析
首先看看如下一个声明: int* ( *( *fun )( int* ) )[10]; 这是一个会让初学者感到头晕目眩.感到恐惧的函数指针声明.在熟练掌握C/C++的声明语法之前,不学习一定的 ...
- 右左法则----复杂指针解析
首先看看如下一个声明: int* ( *( *fun )( int* ) )[10]; 这是一个会让初学者感到头晕目眩.感到恐惧的函数指针声明.在熟练掌握C/C++的声明语法之前,不学习一定的规则,想 ...
- 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop...
重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop 原文:重新想象 Window ...
- 指针01 - 零基础入门学习C语言41
第八章:指针01 让编程改变世界 Change the world by program 指针啥玩意?似乎很神秘? 指针是C语言中的一个重要的概念,也是C语言的一个重要特色. 正确而灵活地运用它,可以 ...
最新文章
- quadTree 论文Real-Time Generation of Continuous吃透了
- linux+sed+-i替换路径,sed替换与别名配置
- Android中使用WebChromeClient显示Openlayers加载本地GeoJson文件显示地图(跨域问题解决)
- HTML基础-张晨光-专题视频课程
- 五大板块(2)—— 指针
- 4.3英寸屏双核 LG Prada K2通过FCC认证
- 当学术大家遇到技术大拿,如何攻克数据库应用头号难题?数位产学研大咖这样解读
- php动态交叉表,PHP Array交叉表实现代码
- SAP License:PS中比较常用的事务代码
- java中使用nextLine(); 没有输入就自动跳过的问题?
- Linux 多线程压缩/解压缩
- asp.net identity 学习1
- 在CentOS上安装Git(转)
- java生成pdf的流_Java 文件输出流.pdf
- 计算机留言板毕业论文摘要,留言板系统设计(毕业论文)
- 期货交易常用术语中英文对照表
- c语言:数组插入处理
- matlab演奏《起风了》代码
- CAN总线通信学习笔记
- sqlserver 电话号3-8位用*号代替