指针学习(新手)

指针(大佬轻点喷)
一、指针的概念

要知道指针的概念,要先了解变量在内存中如何存储的。在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为指针,就像酒店的门牌号一样。
在这里插入图片描述

比如上图的x和y,如果存放这两个变量,那么必须给他内存(空间),然后计算机要找到x和y就要知道名字(地址)。
在这里插入图片描述

比如这段代码,x和y就是这个相应地址存放的内容,可以理解为酒店里房间存放的东西
&x和&y相当于门牌号
在这里插入图片描述

在了解地址等相关内容后,指针就相当于钥匙(房卡)
在这里插入图片描述

这张图里,相当于我定了一个房间a,房间a里面放的东西是数字20,房间的房门号就是&a(下图会展示)。这个时候 int *p就相当于定义了一个p指针,相当于p是房卡,但是不知道是哪个房间的,而&a就相当于a的房间号(地址),让p=&a,就相当于这个房卡指向a的房间号,也就可以打开a的房间号,*p看到里面的20,所以执行以后的内容是
其中20就是a里面存放的东西,p就是a的房间号(地址),*p就相当于打开了房门,看到了里面的20.
在这里插入图片描述

比如这一串代码,6487564就是a的房间号,6487560就是b的房间号。
此时我们做下改动
在这里插入图片描述

猜猜发生什么变化
在这里插入图片描述

我们看到p1,p2都没变,但是 * p1,* p2,a,b变了,那是因为p1就是a房间里的内容,我们把p1=30,就相当于把房间里的东西换成了30,然后p1指向的a房间,所以a也变成了30.
同理,b也是如此。

二、指针类型

  1. int p; 这是一个普通的整型变量
  2. int * p; 首先从P 处开始,先与*结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
  3. int p[3]; 首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
  4. int * p[3]; 首先从P 处开始,先与[]结合,因为其优先级比高,所以P 是一个数组,然后再与结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组
  5. int (* p)[3]; 首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
  6. int **p; 首先从P 开始,先与结合,说是P 是一个指针,然后再与结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
  7. int p(int); 从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
  8. Int (* p)(int); 从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
  9. int * (* p(int))[3]; 可以先跳过,不看这个类型,过于复杂从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的结合,说明函数返回的是一个指针,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.

看完上面的解释,下面放张图让大家好好理解一下
在这里插入图片描述

请问这张图中输出的五项分别是什么意思呢?
首先a肯定是20,pa就是a的地址,*pa也是20.
* &a可以看成 * (&a),就相当于 * p,所以也是20.
&*pa可以看成&(*p),就相当于a的地址。
所以说a= * pa= *&a,pa=&a=&*pa
在这里插入图片描述

三、指针运算
指针变量保存的是地址,而地址本质上是一个整数,所以指针变量可以进行部分运算,例如加法、减法、比较等,请看下面的代码:
在这里插入图片描述

可以看出:pa、pb、pc 每次加 1,它们的地址分别增加 4、8、1,正好是 int、double、char 类型的长度;
这很奇怪,指针变量加减运算的结果跟数据类型的长度有关,而不是简单地加 1 或减 1,这是为什么呢?
以 a 和 pa 为例,a 的类型为 int,占用 4 个字节,pa 是指向 a 的指针,如下图所示:
在这里插入图片描述

刚开始的时候,pa 指向 a 的开头,通过 *pa 读取数据时,从 pa 指向的位置向后移动 4 个字节,把这 4 个字节的内容作为要获取的数据,这 4 个字节也正好是变量 a 占用的内存。
如果pa++;使得地址加 1 的话,就会变成如下图所示的指向关系:
在这里插入图片描述

这个时候 pa 指向整数 a 的中间,*pa 使用的是红色虚线画出的 4 个字节,其中前 3 个是变量 a 的,后面 1 个是其它数据的,把它们“搅和”在一起显然没有实际的意义,取得的数据也会非常怪异。
如果pa++;使得地址加 4 的话,正好能够完全跳过整数 a,指向它后面的内存,如下图所示:
在这里插入图片描述

2.指针-指针
 只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。两个指针相减的结果的类型是 ptrdiff_t,它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。举个例子:

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	int *p1=&a[1];
	int *p2=&a[6];
	int ans=p2-p1;
	printf("%d",ans);
}

很显然,p2-p1就是a[5],所以输出的值为5.
在这里插入图片描述
四、指针与数组
我们可以用 a[0]、a[1]、…、a[9] 来表示这个数组中的10个元素,这10个元素是存储在一段连续相邻的内存区域中的。
同样的,我们也知道对指针进行自增操作的话,指针会指向下一个元素。所以说,数组的下标和指针是一一对应的关系。而根据定义,数组类型的变量或表达式的值是该数组第 1 个元素的地址,且数组名所代表的的就是该数组第 1 个元素的地址。所以说* p=&a[0]可以写成*p=a(a是数组名字)。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	int *p=a;
	printf("a的地址为%p\n",a);
	printf("*p的地址为%p\n",&*p);
	printf("a[0]的地址为%p\n",&a[0]);
}

运行结果:
在这里插入图片描述
可以看出,这三个是一样的。
但是
在这里插入图片描述
这两个虽然值是一样的,但是这两个意义却不一样。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	int *p=a;
	printf("a=%p\n",a);
	printf("&a=%p\n",&a);
	printf("a=%p\n",a+1);
	printf("&a=%p\n",&a+1);
}

在这里插入图片描述
可以看到&a+1和&a刚好差了40,所以说&a表示的是整个数组的地址,而不是数组首元素的地址。a表示数组首元素的地址。数组的地址+1,跳过整个数组的大小,所以 &a+1 相对于 &a 的差值是40

接下来,我们一起看一个小小的例子:

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a[10]={0,1,2,3,4,5,6,7,8,9};
	int *p=a;
	p=p+5;
	printf("%d",*p);
}

聪明的你应该一下子就猜出来运行结果了吧:
在这里插入图片描述

接下来看看字符数组:字符数组归根结底还是一个数组,上节讲到的关于指针和数组的规则同样也适用于字符数组。更改上面的代码,使用指针的方式来输出字符串:在这里插入图片描述
注:字符指针方式区别于字符数组方式,字符数组不能通过数组名自增操作,但是字符指针是指针,可以自增操作。自增自减少会实现什么效果大家可以自己尝试运行一下。
除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:
在这里插入图片描述
做个简单题,把a字符串复制到b字符串在这里插入图片描述
未完待续

  • 11
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值