自增運算符++有前綴和後綴兩種,在搭配間接訪問運算符*時,因為順序、括號和結合關系的影響,很容易讓人產生誤解,產生錯誤的結果,這篇文章來詳細分析一下這幾種運算符的不同搭配情況。
++、--和*的優先級順序
在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; }
運行結果