C语言指针(二)

大家好,我是小张同学!今天继续来学习指针。

目录

1. 指针运算

1.1 指针和整数进行加减运算

1.2 指针相减

1.3 关系运算

2. 指针表达式

2.1 运算符的优先级和结合性

2.2 分析指针表达式


1. 指针运算

指针变量保存的是地址,指针变量可以进行部分运算。

1.1 指针和整数进行加减运算

指针可以加上或减去一个整数,指针的这种运算和通常意义上的数值运算是不一样的。

举个例子:

int a[20];
int *p = a;
p++;

在上面这个例子中,指针 p 的类型是 int*,当执行 p++时,编译器的处理方法是将指针 p 加上 sizeof(int),在32位系统中,指针p就被加上了4,那这样的话,p就指向了 a[1],以此类推,p再加1,就指向了a[2]......

指针在和一个整数进行运算时,会在执行运算前根据合适大小进行调整,这个合适的大小就是指针所指类型的大小,如果将一个 char* 指针加1,实际上就是增加 sizeof(char),如果将一个 float* 指针加1,实际上就是增加sizeof(float),其他类型也是如此。

指针加上或减去一个整数的结果是另一个指针,我们需要注意的一个问题是,运算结果产生的指针指向哪里。

比如对于一个普通int变量,指针p指向此变量,对此指针进行加减运算,虽然不会报错,但是没什么意义,因为 p+1指向的内容大概率是杂乱数据。

但是在数组中,指针与整数的加减运算就有了现实的意义,因为数组中的所有元素在内存中是连续排列的,指针加一就指向数组的下一个元素,减一就指向上一个元素。

编译器不会判断运算结果产生的指针是否指向有效值,是否越界等,因此,当使用指针运算时,必须非常小心,确保结果指针指向有意义的东西。

1.2 指针相减

两个指针可以相减,一般用在数组方面。

只有当两个指针都指向同一个数组中的元素时,才允许两个指针相减,相减得到的结果是两个指针在内存中的距离。

两个指针相减,编译器的做法是将结果除以数组元素类型的长度,所以结果是以数组元素的长度为单位,而不是以字节为单位。

1.3 关系运算

指针变量还可以进行比较运算,如果两个指针相等,那么两个指针就指向同一份数据,否则就指向不同的数据。

如果两个指针都指向同一个数组中的元素,它们之间的比较可以用于判断元素在数组中的相对位置。

2. 指针表达式

int a[20];
int *p = a;

如果指针p指向数组a,那么来看一下以下这些表达式表示什么意义吧:

&p
*p
*p+1
*(p+1)
++p
p++
*++p
*p++
++*p
(*p)++
++*++p

晕了吗,反正我是晕了。

2.1 运算符的优先级和结合性

其实上面这些表达式之所以让人头晕,实际就是搞不清先计算谁后计算谁的问题,下面先来看一下运算符的优先级和结合性。

所谓优先级,就是当一个表达式中出现多个运算符时,先计算谁的问题。在C语言中,有很多运算符,要记住这些运算符的优先级是挺难的,而且实际在编程的时候,如果搞不清优先级,加一个括号就可以了,加括号后,优先级就一目了然,别人读起来也更方便。

结合性,就是当运算符的优先级相同的时候,应该先计算谁,如果结合性是从左到右,那么当优先级相同时,就按从左到右的顺序计算,如果结合性是从右到左,那么就按从右到左的顺序计算。

优先级运算符含义结合方向说明
1[]数组下标左到右
1()圆括号左到右
1.成员选择左到右
1->成员选择左到右
2-负号右到左单目运算符
2(类型)强制类型转换右到左
2++自增运算符右到左单目运算符
2--自减运算符右到左单目运算符
2*解引用运算符右到左单目运算符
2&取地址运算符右到左单目运算符
2逻辑非运算符右到左单目运算符
2~按位取反运算符右到左单目运算符
2sizeof长度运算符右到左
3/左到右双目运算符
3*左到右双目运算符
3%取余左到右双目运算符
4+左到右双目运算符
4-左到右双目运算符
5<<左移左到右双目运算符
5>>右移左到右双目运算符
6>大于左到右双目运算符
6>=大于等于左到右双目运算符
6<小于左到右双目运算符
6<=小于等于左到右双目运算符
7==等于左到右双目运算符
7!=不等于左到右双目运算符
8&按位与左到右双目运算符
9^按位异或左到右双目运算符
10|按位或左到右双目运算符
11&&逻辑与左到右双目运算符
12||逻辑或左到右双目运算符
13?:条件运算符右到左三目运算符
14=赋值运算符右到左
14/=除后赋值右到左
14*=乘后赋值右到左
14%=取模后赋值右到左
14+=加后赋值右到左
14-=减后赋值右到左
14<<=左移后赋值右到左
14>>=右移后赋值右到左
14&=按位与后赋值右到左
14^=按位异或后赋值右到左
14|=按位或后赋值右到左
15,逗号运算符左到右

2.2 分析指针表达式

搞清楚了运算符的优先级和结合性,那就开始分析一下这些表达式吧。

&p:对p这个指针变量取地址,即指向指针的指针,表达式的值为指针变量p的地址

*p:解引用 p,得到其指向的值 a[0]

*p + 1:* 的优先级高于 +,所以先执行 *p 得到的值是a[0],然后将结果加1,即最终得到 a[0]+1,p指向位置不变

*(p + 1)和上面的例子相比,加了一个括号,这样就先执行加法运算,p+1得到 a[1] 的地址,然后再使用 * 得到这个地址处的值,最终得到 a[1],p指向位置不变

++p:++和--操作符在指针变量中使用的很频繁,先将p指针加1,然后返回新的p,最终得到指向 a[1] 的指针,p指向a[1]

p++返回p的当前值,即a[0]的地址,然后p自增1,最终得到指向a[0]的指针,p指向a[1]

*++p:* 和 ++的优先级相同,且结合性都是从右向左,因此先将p加1,然后解引用新的p,最终得到 a[1],p指向a[1]

*p++* 和 ++ 的优先级相同,并且结合性都是从右向左,这意味着,在这个表达式中,首先考虑++运算符,后置++会先返回当前p,即a[0]的地址,然后p自增1,然后考虑 * 运算符,应用于p++的返回值,所以最终得到a[0],p指向a[1]

*p++* 和 ++ 的优先级相同,并且结合性都是从右向左,这意味着,在这个表达式中,首先考虑++运算符,后置++会先返回当前p,即a[0]的地址,然后p自增1,然后考虑 * 运算符,应用于p++的返回值,所以最终得到a[0],p指向a[1]

(*p)++先解引用p的值,返回该值a[0],然后对a[0]自增,最终得到a[0],p指向位置不变,a[0]的值被改变

++*++p:先将p自增,再解引用新的p值,然后对其值自增,最后得到a[1]+1,p指向a[1],a[1]的值被改变

++*p++首先计算后置++,返回当前p值,p指向a[1],然后解引用自增前的p值,然后对原解引用的值自增,最终得到a[0]+1,p指向a[1],a[0]的值被改变

看得懂吗?多看几遍就行了(doge)

本篇文章结束,下回接着讲指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值