自增運算符++有前綴和後綴兩種,在搭配間接訪問運算符*時,因為順序、括號和結合關系的影響,很容易讓人產生誤解,產生錯誤的結果,這篇文章來詳細分析一下這幾種運算符的不同搭配情況。
++、--和*的優先級順序
在C語言運算符的優先級順序中,後綴的++和--運算符運算優先級16,結合關系是從左到右;簡介訪問運算符*、前綴++和--運算符運算優先級15,結合關系是從右到左。根據這個關系,可以分析出不同情況下的應用。為了更直觀的體現,有以下的例子。
舉例說明
有數組a[5],值分別為10,11,12,13,14;有指針p指向a[0];另有指針q和整數b。這裡注意的是,每段代碼開始前,a數組的值和p指針都會回復初始狀態。(在一開始寫這些測試代碼時,忽視了回復初值的問題,導致很多奇怪的錯誤,比如p已經不再指向a[0],或者a[0]本身已經改變了。)
1.後綴++
p = a; q = p++;
p指向a[1]值為11,q指向a[0]值為10。說明後綴自增運算符,返回的是自增前的值。
2.前綴++
p = a; q = ++p;
p指向a[1]值為11,q指向a[1]值為11。說明前綴自增運算符,返回的是自增後的值。
3.*p++
p = a; b = *p++;
p指向11,b值為10。此時先執行p++,p自增,指向a[1]。p++的值為自增前的值,即a[0]的地址,a[0]的值賦給b。
4.*(p++)
p = a; b = *(p++);
結果與3相同。*與++運算符優先級相同,運算順序是自右向左。
5.(*p)++
p = a; b = (*p)++;
此時雖然結果與3相同,但這時是先取p指向的值即a[0],a[0]自增即a[0]的值變成11,自增是後綴的,返回自增前的值,即10。結果相同,但原理還有很大的差別。
6. *++p
p = a; b = *++p;
p指向11,b值為11。先執行++p,p自增,指向a[1],++p的值為自增後的值,即a[1]的地址,a[1]的值賦給b。
7.*(++p)
p = a; b = *(++p);
與6結果相同,*與++運算符優先級相同,運算順序是自右向左。
8.++(*p)
p = a; b = ++(*p);
p指向11,b值為11,先取p指向a[0]值為10,a[0]的值自增變成11,前綴自增返回值為11賦給b。
9. ++*p
p = a; b = ++*p;
結果同8,*與++運算符優先級相同,運算順序是自右向左。
總結
第一個原則就是前綴值為變化後,後綴值為變化前。第二個原則,*++優先級相同,讀的時候從右向左。這些都是本人自己試著總結的,如有錯誤請多指正,希望對有疑惑的朋友有所幫助。
完整代碼
/*本程序用來測試前綴自增運算符,後綴自增運算符,取內容符號的運算優先級以及順序帶來的返回值的影響*/
#include "stdio.h"
void myPrint(int n,int j, int k)
{
printf("no.%d:p->%d, q->%d\n", n,j, k);
}
void myPrintNew(int n,int j, int k)
{
printf("no.%d:p->%d, b->%d\n", n,j, k);
}
void init(int a[5])
{
a[0] = 10;
a[1] = 11;
a[2] = 12;
a[3] = 13;
a[4] = 14;
}//防止某些測試的操作改變了數組的值,在每次使用數組之前使用初始化函數
int main(int argc, char* argv)
{
//int a[5] = { 10, 11, 12, 13, 14 }, *p,*q,b;
int a[5] ,*p, *q, b;
init(a);
//1.
init(a);
p = a;
q = p++;
myPrint(1,*p, *q);
//p指向11,q指向10
//後綴自增運算符,返回的是自增前的值
//2.
init(a);
p = a;
q = ++p;
myPrint(2,*p, *q);
//p指向11,q指向11
//前綴自增運算符,返回的是自增後的值
//1,2:閱讀順序:從左到右
//3.
init(a);
p = a;
b = *p++;
myPrintNew(3,*p, b);
//p指向11,b值為10
//先執行p++,p自增,指向a[1],p++的值為自增前的值(見1),即a[0]的地址,a[0]的值賦給b
//4.
init(a);
p = a;
b = *(p++);
myPrintNew(4,*p, b);
//結果與3相同
//*與++運算符優先級相同,運算順序是自右向左
//5.
init(a);
p = a;
b = (*p)++;
myPrintNew(5,*p, b);
//結果與3相同,但這時是先取p指向的值即a[0],a[0]自增即a[0]的值變成11,自增是後綴的,返回自增前的值,即10
//與8對照
//6。
init(a);
p = a;
b = *++p;
myPrintNew(6, *p, b);
//p指向11,b值為11
//先執行++p,p自增,指向a[1],++p的值為自增後的值(見2),即a[1]的地址,a[1]的值賦給b
//7.
init(a);
p = a;
b = *(++p);
myPrintNew(7, *p, b);
//與6結果相同
//*與++運算符優先級相同,運算順序是自右向左
//8
init(a);
p = a;
b = ++(*p);
myPrintNew(8, *p, b);
//p指向11,b值為11
//先取p指向a[0]值為10,a[0]的值自增變成11,前綴自增返回值為11賦給b
//9??
init(a);
p = a;
b = ++*p;
myPrintNew(9, *p, b);
//結果同8
//*與++運算符優先級相同,運算順序是自右向左
return 0;
}
運行結果