如题,本篇博客主要解决2个疑点:指针类型的用处,指针如何运算。
1.指针类型
C语言中的指针类型,在X86环境下大小是4个字节,在X64环境下大小是8个字节。既然指针的大小和指针类型无关,那么指针类型究竟有什么用呢?
事实上,指针类型决定看待内存的视角,具体是以下2点:
- 指针“走一步”能走多远。
- 指针解引用时,访问的权限。
1.1 决定步长
先说第一点。假设给一个int*类型的指针和一个char*类型的指针+1,分别跳过几个字节呢?
#include <stdio.h>
int main()
{
int a = 100;
int* pa = &a;
char c = 'f';
char* pc = &c;
printf(" pa = %p\n", pa);
printf("pa + 1 = %p\n", pa + 1);
printf(" pc = %p\n", pc);
printf("pc + 1 = %p\n", pc + 1);
return 0;
}
输出结果:
有意思的是,int*类型的指针+1会跳过4个字节,而char*类型的指针+1会跳过1个字节。
这是为什么呢?在整型指针眼里,内存中的数据都是int类型的,如果+1,自然跳过一个int,也就是跳过了4个字节。同理,在字符指针眼里,内存中的数据都是char类型的,如果+1,自然跳过一个char,也就是跳过了1个字节。
那+2,+3,-1呢?如果是整型指针,+2就应该跳过2个整型,也就是向后跳8个字节。而-1就应该向前跳过1个整型,也就是向前跳4个字节。其实,这就是指针的运算之一:指针±整数。
综上所述:指针的类型,决定了指针±整数时,向前/后走的步长。具体来说,对于一个type*
类型的指针,±n后,会向后/前跳过n*sizeof(type)
个字节。
1.2 决定访问权限
如果对一个int*类型的指针解引用,在整型指针眼里,内存中的数据都是整型,解引用后,会向后看4个字节,并且认为这4个字节中,存储的数据是整型。如果对一个char*类型的指针解引用,在字符指针眼里,内存中的数据都是字符,解引用后,会向后看1个字节,并且认为这1个字节中,存储的数据是字符。
如何验证这一点呢?可以这样做:假设内存中存储了一个16进制数字:
int a = 0x11223344;
如果我把它的地址给一个int*类型的指针,再解引用会发生啥?
int* pa = &a;
*pa = 0;
如果大家对指针有一定的了解,应该知道,pa里存的是a的地址,对pa解引用,就能访问a,并且把a给改了,a的值就变成了0。而a是4个字节的数据,这一改,其实把这4个字节都改成了0,这就证明了int*类型的指针解引用会访问4个字节。
那如果是char*类型的指针呢?
char* pc = &a;
*pc = 0;
我们来观察一下内存。这是修改前:
由于我的环境是小端字节序,在内存中是倒着存储的。此时如果执行*pc = 0;
,会发生啥?
第一个字节的数据被改成了0!也就是说,对一个char*类型的指针解引用,只会访问一个字节的数据。
综上所述:指针类型决定了访问的权限,即解引用后能访问几个字节。一个type*
类型的指针,解引用后能访问sizeof(type)
个字节。
2.指针运算
指针有4中常见运算,分别是:
- 解引用。
- ±整数。
- 指针-指针。
- 指针之间的大小比较。
下面分别详细讲解。
2.1 指针的解引用
对一个指针解引用,会先在内存中找到指针变量中存放的地址处,再根据指针变量的类型决定访问的权限。
比如,一个很基础的代码:
int a = 10;
int* pa = &a;
*pa = 20;
在int* pa = &a;
这句代码中,会把a的地址存放到pa中。而*pa = 20;
这句代码会如何执行呢?
- 首先,在pa中取出前面存放的a的地址。
- 在内存中,找到该地址。
- 根据pa的类型是int*,决定了看待内存的视角:一次访问4个字节的空间,且这4个字节的空间内存储的类型是int。
- 以存储的地址为首地址,向后访问4个字节,认为这4个字节存储的数据是int数据,并且把这个数据改成20。
2.2 指针±整数
指针±整数,这个整数是几,就会根据指针的类型,向后/前跳过几个该类型的元素,其中“加”就向后跳,“减”就向前跳。
一个很经典的例子,就是使用指针访问数组。
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int* p = arr;
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
{
printf("%d ", *(p+i));
}
这里的p+i,就会从p指向的位置开始,向后跳i个int类型的数据,其实就相当于找到了数组下边为i的元素,此时解引用就能拿到这个元素。
咦,有没有发现,*(p+i)似乎作用就相当于arr[i]?而我们前面写了int* p = arr;
是不是可以理解为,p就等价于arr,也就是说,下面这4个玩意是等价的:
*(p+i) <—> *(arr+i) <—> arr[i] <—> p[i]
所以,用下标访问数组,如arr[i]的形式,其实本质上就是指针±整数和指针的解引用的结合!
2.3 指针-指针
指针-指针,得到的是指针之间的元素个数。比如:
int arr[10];
int n = &arr[9] - &arr[0];
上述代码中,n就是9,因为arr[9]和arr[0]都是int类型的数据,取出地址后,会得到2个int*类型的指针。它们的差,就是arr[9]和arr[0]相差了几个int类型的数据,显然是9个,所以答案是9。注意,如果写成&arr[0] - &arr[9]
,得到的就是-9。
其实,根据前面的讲解,a[i]就等价于*(a+i)。那么,下面的等式成立(这是一个不太严谨的理解):
&arr[9]-&arr[0] = &*(arr+9) - &*(arr+0) = (arr+9) - (arr+0) = 9
是不是很有意思?
2.4 指针之间的大小比较
这个就很简单了,单纯是比较指针变量存储的地址之间的大小。
比如,随着数组下标的增长,地址是由低到高变化的,所以就有:&arr[0] < &arr[9]。文章来源:https://www.toymoban.com/news/detail-425391.html
总结
- 指针的类型决定了看待内存的视角。具体决定了指针±整数时的步长,以及解引用时访问的权限。
- 指针主要有4种运算,分别是:解引用,±整数,指针-指针以及指针的关系运算。
感谢大家的阅读!文章来源地址https://www.toymoban.com/news/detail-425391.html
到了这里,关于C语言指针2大问题:指针类型有什么用?指针如何运算?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!