指针是C语言的灵魂,但是在使用的时候,有些纷繁复杂的表达式往往让人头疼,今天就从易到难掰扯一下怎么理解指针的表达式。
定义一个指针指向数组:
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
此时,指针指向数组首地址,a[0],对指针进行解应用,得到的值为100,当想要让指针指向数组中a[1],有两种写法:
ptr = ptr + 1;
或者可以写做:
ptr++;
此时指针指向a[1],对其解引用得到的值为200。
上述指针表达式都是较为常见和常规的,接下来看一些奇怪的,有助于我们对指针进一步的理解和掌握:
*ptr+1;
*(ptr+1)
这两个表达式主要涉及到运算符的优先级问题,在 * ptr+1中,*的优先级高于+,所以先对ptr指针进行解引用操作,取得值以后再进行运算。在 *(ptr+1)中,括号的优先级最高,先进行括号内的运算,ptr+1指向的是指针地址的下一个地址,再对其进行解引用操作。
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
printf("%d\n", (*ptr + 1));
printf("%d\n", *(ptr + 1));
输出结果如下:
101
200
再来看两个指针表达式:
*++ptr;
*ptr++;
这两个表达式也是涉及到运算符的优先级,但是它俩和刚才两兄弟有区别,刚才的表达式,运算符优先级是不同的,这两个表达式的运算符 * 和++都是单目运算符,在C语言中单目运算符优先级相同,一个表达式中同时出现多个单目运算符时,结合方向由右往左。
所以 * ++ptr和*ptr++的结合方式都是相同的,先对指针ptr进行++操作,再进行解引用,从运算顺序上来说,他们的运算顺序一致,但是由于前置++和后置++也有区别,导致两者的结果是不相同的。
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
printf("%d\n", *++ptr);
此时输出结果是200,因为前置++会将操作数的值增加后再用于表达式,而后置++则会将操作数的值先用于表达式,然后再对操作数进行增加,所以*ptr++结果不同:
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
printf("%d\n", *ptr++);
此时输出结果为100。
但是两者对操作数的运算是一致的,所以在表达式执行后,ptr指针指向的位置都是数组a[1],只是由于++位置不同让解引用结果不同。
再看两组相对复杂的指针表达式:
++*++ptr;
++*ptr++;
当掌握了单目运算符优先级原理后,再理解更复杂的也是相同的思路,结合到代码中验证:
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
printf("%d\n", ++*++ptr);
printf("%d\n", *ptr);
++* ++ptr遵从单目运算符优先级从右往左,先计算++ptr,此时指针指向a[1],对指针ptr进行解引用:*++ptr得到a[1]的值,然后还有一个前置++,对a[1]的值自加1,所以输出结果为201,且指针也指向a[1]。输出结果:
201
201
++*ptr++也是一样的计算:
int a[5] = {100, 200, 300, 400, 500};
int *ptr = a;
printf("%d\n", ++*ptr++);
printf("%d\n", *ptr);
从右往左,由于后置++的结果并不会用于当前表达式,所以*ptr++得到的数值为a[0]中的值,然后再对a[0]的值进行自加1,得到的结果为101,指针由于后置++的原因,指向了a[1],输出结果:
101,
200