C語言學習筆記--C運算子

YunFei_Chen發表於2019-08-12

C運算子

運算子是一種告訴編譯器執行特定的數學或邏輯操作的符號。C語言內建了豐富的運算子,並提供了以下型別的運算子:

  • 算術運算子
  • 關係運算子
  • 邏輯運算子
  • 位運算子
  • 賦值運算子
  • 雜項運算子
    本章將逐一介紹算術運算子、關係運算子、邏輯運算子、位運算子、賦值運算子和其他運算子。

算術運算子

下表顯示了C語言支援的所有的算術運算子。假設變數A的值為10,變數B的值為20,則:

運算子描述例項
+把兩個運算元相加A+B將得到30
-從第一個運算元中減去第二個運算元A-B將得到-10
*把兩個運算元相乘A*B將得到200
/分子除以分母B/A將得到2
%取模運算子,整除後的餘數B%A將得到0
++自增運算子,整數值增加1A++將得到11
- -自減運算子,整數值減少1A- -將得到9

例項
請看下面的例項,瞭解C語言中所有可用的算術運算子:

#include<stdio.h>
int main()
{
	int a=21;
	int b = 10;
    int c ;
   
   	c = a + b;
   	printf("Line 1 - c 的值是 %d\n", c );
   	c = a - b;
   	printf("Line 2 - c 的值是 %d\n", c );
   	c = a * b;
   	printf("Line 3 - c 的值是 %d\n", c );
   	c = a / b;
   	printf("Line 4 - c 的值是 %d\n", c );
   	c = a % b;
   	printf("Line 5 - c 的值是 %d\n", c );
   	c = a++;  // 賦值後再加 1 ,c 為 21,a 為 22
   	printf("Line 6 - c 的值是 %d\n", c );
   	c = a--;  // 賦值後再減 1 ,c 為 22 ,a 為 21
  	 printf("Line 7 - c 的值是 %d\n", c );
}

將上面的程式碼被編譯和執行時,將會產生下列結果:

Line 1 - c 的值是 31
Line 2 - c 的值是 11
Line 3 - c 的值是 210
Line 4 - c 的值是 2
Line 5 - c 的值是 1
Line 6 - c 的值是 21
Line 7 - c 的值是 22

以下例項演示了a++和++a的區別:
例項

#include<stdio.h>
int main()
{
	int c;
	int a=10;
	c=a++;
	printf("先賦值後運算:\n");
   	printf("Line 1 - c 的值是 %d\n", c );
   	printf("Line 2 - a 的值是 %d\n", a );
   	a = 10;
   	c = a--; 
   	printf("Line 3 - c 的值是 %d\n", c );
   	printf("Line 4 - a 的值是 %d\n", a );
 
   	printf("先運算後賦值:\n");
   	a = 10;
   	c = ++a; 
   	printf("Line 5 - c 的值是 %d\n", c );
   	printf("Line 6 - a 的值是 %d\n", a );
   	a = 10;
   	c = --a; 
   	printf("Line 7 - c 的值是 %d\n", c );
   	printf("Line 8 - a 的值是 %d\n", a );
}

以上程式的執行輸出結果為:

先賦值後運算:
Line 1 - c 的值是 10
Line 2 - a 的值是 11
Line 3 - c 的值是 10
Line 4 - a 的值是 9
先運算後賦值:
Line 5 - c 的值是 11
Line 6 - a 的值是 11
Line 7 - c 的值是 9
Line 8 - a 的值是 9

關係運算子

下表顯示了C語言支援的所有關係運算子。假設變數A的值為10,變數B的值為20,則:

運算子描述例項
==檢查兩個運算元的值是否相等,如果相等則條件為真。(A==B)不為真
!=檢查兩個運算元的值是否相等,如果不相等則條件為真。(A!=B)為真
>檢查左運算元的是否大於右運算元的值,如果是則條件為真。(A>B)不為真
<檢查左運算元的值是否小於右運算元的值,如果是則條件為真。(A<B)為真
>=檢查左運算元的值是否大於或等於右運算元的值,如果是則條件為真。(A>=B)不為真
<=檢查左運算元的值是否小於或等於右運算元的值,如果是則條件為真。(A<=B)為真

例項
看下面的例項,瞭解C語言中所有可用的關係運算子:

#include <stdio.h>
 
int main()
{
   int a = 21;
   int b = 10;
   int c ;
 
   if( a == b )
   {
      printf("Line 1 - a 等於 b\n" );
   }
   else
   {
      printf("Line 1 - a 不等於 b\n" );
   }
   if ( a < b )
   {
      printf("Line 2 - a 小於 b\n" );
   }
   else
   {
      printf("Line 2 - a 不小於 b\n" );
   }
   if ( a > b )
   {
      printf("Line 3 - a 大於 b\n" );
   }
   else
   {
      printf("Line 3 - a 不大於 b\n" );
   }
   /* 改變 a 和 b 的值 */
   a = 5;
   b = 20;
   if ( a <= b )
   {
      printf("Line 4 - a 小於或等於 b\n" );
   }
   if ( b >= a )
   {
      printf("Line 5 - b 大於或等於 a\n" );
   }
}

當上面程式碼被編譯和執行時,它會產生下列結果:

Line 1 - a 不等於 b
Line 2 - a 不小於 b
Line 3 - a 大於 b
Line 4 - a 小於或等於 b
Line 5 - b 大於或等於 a

邏輯運算子

下表顯示了C語言支援的所有關係邏輯運算子。假設變數A的值為1,變數B的值為0,則:

運算子描述例項
&&稱為邏輯與運算子。如果兩個運算元都非零,則條件為真。(A&&B)為假
ll稱為邏輯或運算子。如果兩個運算元中有任意一個非零,則條件為真(AllB)為真
稱為邏輯非運算子。用來逆轉運算元的邏輯狀態。如果條件為真則邏輯非運算子將使其為假!(A&&B)為真

例項
看下面的例項,瞭解C語言中所有可用的邏輯運算子:

#include<stdio.h>
int main()
{
	int a=5;
	int b=20;
	int c;
	if(a&&b)
	{
		printf("Line1-條件為真\n");
	}
	 if ( a || b )
   	{
      	printf("Line 2 - 條件為真\n" );
   	}
   	/* 改變 a 和 b 的值 */
   	a = 0;
   	b = 10;
   if ( a && b )
   {
      printf("Line 3 - 條件為真\n" );
   }
   else
   {
      printf("Line 3 - 條件不為真\n" );
   }
   if ( !(a && b) )
   {
      printf("Line 4 - 條件為真\n" );
   }
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Line 1 - 條件為真
Line 2 - 條件為真
Line 3 - 條件不為真
Line 4 - 條件為真

位運算子

位運算子作用於位,並逐位執行操作。&,l和^的真值表如下所示:

pqp&qplqp^q
00000
01011
11111
10011

假設如果A=60且B=13,現在以二進位制格式表示,如下所示:
A=00111100
B=00001101
A&B=00001100
AlB=00111101
A^B=00110001
~A=11000011
下表顯示了C語言支援的位運算子。假設變數A的值為60,變數B的值為13,則

運算子描述例項
&按位與操作,按二進位制位進行“與”運算。運算規則:0&0=0;0&1=0;1&0=0;1&1=1;(A&B)將得到12,即為00001100
l按位或運算子,按二進位制位進行“或”運算。運算規則:0|0=0;0|1=1;1|0=1;1|1=1;(A
^異或運算子,按二進位制位進行“異或”運算。運算規則:0^0=0;0^1=1;1^0=1;1^1=0;(A ^ B) 將得到 49,即為 0011 0001
~取反運算子,按二進位制位進行“取反”運算。運算規則:~1=0;~0=1;(~A ) 將得到 -61,即為 1100 0011,一個有符號二進位制數的補碼形式。
<<二進位制左移運算子。將一個運算物件的各二進位制位全部左移若干位(左邊的二進位制位丟棄,右邊補0)。A << 2 將得到 240,即為 1111 0000
>>二進位制右移運算子。將一個數的各二進位制位全部右移若干位,整數左補0,負數左補1,右邊丟棄A>>2將得到15,即為00001111

例項
看下面的例項,瞭解C語言所有可用的位運算子:

#include<stdio.h>
int main()
{
   unsigned int a=60;		/* 60 = 0011 1100 */  
   unsigned int b = 13;    /* 13 = 0000 1101 */
   int c = 0;           
 
   c = a & b;       /* 12 = 0000 1100 */ 
   printf("Line 1 - c 的值是 %d\n", c );
 
   c = a | b;       /* 61 = 0011 1101 */
   printf("Line 2 - c 的值是 %d\n", c );
 
   c = a ^ b;       /* 49 = 0011 0001 */
   printf("Line 3 - c 的值是 %d\n", c );
 
   c = ~a;          /*-61 = 1100 0011 */
   printf("Line 4 - c 的值是 %d\n", c );
 
   c = a << 2;     /* 240 = 1111 0000 */
   printf("Line 5 - c 的值是 %d\n", c );
 
   c = a >> 2;     /* 15 = 0000 1111 */
   printf("Line 6 - c 的值是 %d\n", c );
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Line 1 - c 的值是 12
Line 2 - c 的值是 61
Line 3 - c 的值是 49
Line 4 - c 的值是 -61
Line 5 - c 的值是 240
Line 6 - c 的值是 15

賦值運算子

下表列出了C語言支援的賦值運算子:

運算子描述例項
=簡單的賦值運算子,把右邊運算元的值賦給左邊運算元C=A+B將把A+B的值賦給C
+=加且賦值運算子,把右邊運算元加上左邊運算元的結果賦值給左邊運算元C+=A相當於C=C+A
- =減且賦值運算子,把左邊運算元減去右邊運算元的結果賦值給左邊運算元C-=A相當於C=C-A
*=乘且賦值運算子,把右邊運算元乘以左邊運算元的結果賦值給左邊運算元C*=A相當於C=C*A
/=除且賦值運算子,把左邊運算元除以右邊運算元的結果賦值給左邊運算元C/=A相當於C=C/A
%=求模且賦值運算子,求兩個運算元的模賦值給左邊運算元C%=A相當於C=C%A
<<=左移且賦值運算子C<<=2等同於C=C<<2
>>=右移且賦值運算子C>>=2等同於C=C>>2
&=按位與且賦值運算子C&=2等同於C=C&2
^=按位異或且賦值運算子C^ =2等同於C=C^2
l=按位或且賦值運算子Cl=2等同於C=Cl2

看下面例項,瞭解C語言中所有可用的賦值運算子:
例項

#include <stdio.h>
 
main()
{
   int a = 21;
   int c ;
 
   c =  a;
   printf("Line 1 - =  運算子例項,c 的值 = %d\n", c );
 
   c +=  a;
   printf("Line 2 - += 運算子例項,c 的值 = %d\n", c );
 
   c -=  a;
   printf("Line 3 - -= 運算子例項,c 的值 = %d\n", c );
 
   c *=  a;
   printf("Line 4 - *= 運算子例項,c 的值 = %d\n", c );
 
   c /=  a;
   printf("Line 5 - /= 運算子例項,c 的值 = %d\n", c );
 
   c  = 200;
   c %=  a;
   printf("Line 6 - %= 運算子例項,c 的值 = %d\n", c );
 
   c <<=  2;
   printf("Line 7 - <<= 運算子例項,c 的值 = %d\n", c );
 
   c >>=  2;
   printf("Line 8 - >>= 運算子例項,c 的值 = %d\n", c );
 
   c &=  2;
   printf("Line 9 - &= 運算子例項,c 的值 = %d\n", c );
 
   c ^=  2;
   printf("Line 10 - ^= 運算子例項,c 的值 = %d\n", c );
 
   c |=  2;
   printf("Line 11 - |= 運算子例項,c 的值 = %d\n", c );
 
}

當上面的程式碼被編譯和執行時,會產生下列結果:

Line 1 - =  運算子例項,c 的值 = 21
Line 2 - += 運算子例項,c 的值 = 42
Line 3 - -= 運算子例項,c 的值 = 21
Line 4 - *= 運算子例項,c 的值 = 441
Line 5 - /= 運算子例項,c 的值 = 21
Line 6 - %= 運算子例項,c 的值 = 11
Line 7 - <<= 運算子例項,c 的值 = 44
Line 8 - >>= 運算子例項,c 的值 = 11
Line 9 - &= 運算子例項,c 的值 = 2
Line 10 - ^= 運算子例項,c 的值 = 0
Line 11 - |= 運算子例項,c 的值 = 2

雜項運算子 sizeof&三元

下表列出了C語言支援的其他一些重要的運算子,包括sizeof?:

運算子描述例項
sizeof()返回變數的大小。sizeof(a)將返回4,其中a是整數
&返回變數的地址。&a;將給出變數的實際地址。
*指向一個變數。*a;將指向一個變數。
?:條件表示式如果條件為真 ?則值為X:否則值為Y

請看下面的例項,瞭解C語言中所有可用的雜項運算子:
例項

#include <stdio.h>
 
int main()
{
   int a = 4;
   short b;
   double c;
   int* ptr;
 
   /* sizeof 運算子例項 */
   printf("Line 1 - 變數 a 的大小 = %lu\n", sizeof(a) );
   printf("Line 2 - 變數 b 的大小 = %lu\n", sizeof(b) );
   printf("Line 3 - 變數 c 的大小 = %lu\n", sizeof(c) );
 
   /* & 和 * 運算子例項 */
   ptr = &a;    /* 'ptr' 現在包含 'a' 的地址 */
   printf("a 的值是 %d\n", a);
   printf("*ptr 是 %d\n", *ptr);
 
   /* 三元運算子例項 */
   a = 10;
   b = (a == 1) ? 20: 30;
   printf( "b 的值是 %d\n", b );
 
   b = (a == 10) ? 20: 30;
   printf( "b 的值是 %d\n", b );
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Line 1 - 變數 a 的大小 = 4
Line 2 - 變數 b 的大小 = 2
Line 3 - 變數 c 的大小 = 8
a 的值是 4
*ptr 是 4
b 的值是 30
b 的值是 20

C中的運算子優先順序

運算子的優先順序確定表示式中項的組合。這會影響到一個表示式如何計算。某些運算子比其他運算子有更高的優先順序,例如,乘除運算子具有比加減運算子更高的優先順序。
例如x=7+3 * 2,在這裡,x被賦值為13,而不是20,因為運算子 * 具有比+更高的優先順序,所以首先計算乘法3*2,然後再加上7.
下表將按運算子優先順序從高到低列出各個運算子,具有較高優先順序的運算子出現在表格的上面,具有較低優先順序的運算子出現在表格的下面。在表示式中,較高優先順序的運算子會優先被計算。

類別運算子結合性
字尾() [] -> . ++ –從左到右
一元+ - ! ~ ++ – (type)*& sizeof從右到左
乘除* / %從左到右
加減+ -從左到右
移位<< >>從左到右
關係< <= > >=從左到右
相等== !=從左到右
位與 AND&從左到右
位異或 XOR^從左到右
位或 ORl從左到右
邏輯與 AND&&從左到右
邏輯或 ORll從左到右
條件?:從右到左
賦值= += -= *= /= %= >>= <<= &= ^= l=從右到左
逗號,從左到右

請看下面的例項,瞭解C語言中運算子的優先順序:
例項

#include <stdio.h>
 
main()
{
   int a = 20;
   int b = 10;
   int c = 15;
   int d = 5;
   int e;
 
   e = (a + b) * c / d;      // ( 30 * 15 ) / 5
   printf("(a + b) * c / d 的值是 %d\n",  e );
 
   e = ((a + b) * c) / d;    // (30 * 15 ) / 5
   printf("((a + b) * c) / d 的值是 %d\n" ,  e );
 
   e = (a + b) * (c / d);   // (30) * (15/5)
   printf("(a + b) * (c / d) 的值是 %d\n",  e );
 
   e = a + (b * c) / d;     //  20 + (150/5)
   printf("a + (b * c) / d 的值是 %d\n" ,  e );
  
   return 0;
}

當上面程式碼被編譯和執行時,會產生下面的結果:

(a + b) * c / d 的值是 90
((a + b) * c) / d 的值是 90
(a + b) * (c / d) 的值是 90
a + (b * c) / d 的值是 50

綜合總結

1、利用異或 ^ 來交換兩個數的值,而且不引入其他變數。

unsigned int a=60;  //0011 1100
unsigned int b=13;  //0000 1101
a=a^b;              //a=a^b=0011 0001
b=a^b;              //b=a^b=0011 1100  相當於b1=(a^b)^b
a=a^b;              //a=a^b=0000 1101  相當於a1=(a^b)^((a^b)^b)

例項

#include<stdio.h>

int main( )
{
    unsigned int a=60;         //0011 1100
    unsigned int b=13;         //0000 1101
    printf("a=%d,b=%d",a,b);   //輸出a,b的值
    printf("\n");
    a=a^b;                     //a=a^b=0011 0001
    b=a^b;                     //b=a^b=0011 1100
    a=a^b;                     //a=a^b=0000 1101
    printf("a=%d,b=%d",a,b);   //輸出a,b的值
}

上面程式碼編譯和執行時,會產生下面的結果:

a=60,b=13;
a=13,b=60;

2、利用位與 &運算,判斷一個整數是否是2的整數次冪。
二進位制數的位權是以2為底的冪,如果一個整數 m 是 2 的 n 次冪,那麼轉換為二進位制之後只有最高位為 1,其餘位置為 0,再觀察 m-1 轉換為二進位制後的形式以及 m&(m-1) 的結果,例如:

2 --> 0000 0010        1 --> 0000 0001        2&1 --> 0000 0010 & 0000 0001 = 0
4 --> 0000 0100        3 --> 0000 0011        4&3 --> 0000 0100 & 0000 0011 = 0
8 --> 0000 1000        7 --> 0000 0111        8&7 --> 0000 1000 & 0000 0111 = 0

可以看出所有的 1 完美的錯過了,根據位與的特點可知 m&(m-1) 的結果為 0。
如果整數 m 不是 2 的 n 次冪,結果會怎樣呢?例如 m=9 時:

9 --> 0000 1001        8 --> 0000 1000        9&8 --> 0000 1001 & 0000 1000 != 0

利用這一特點,即可判斷一個整數是否是2的整數次冪。
示例:

int func(int num)
{
    return ((num > 0) && ((num & (num - 1)) == 0));//2的n次冪大於0
}

返回值為 1,則輸入的正整數為 2 的整數次冪,返回值為 0 則不是。
對於2的冪指數的程式碼為:

#include <stdio.h>

int num;
int func(int num)
{
    if ((num>0)&&(num&(num-1))==0)
    {
        printf("%d是2的整數次冪",num);
    }
    else
    {
        printf("%d不是2的整數次冪",num);
    }
    return((num>0)&&(num&(num-1))==0);
}

int main()
{
    printf("請輸入要查詢的數\n");
    scanf("%d",&num);
    func(num);
}

3、對取餘運算的說明
取餘,也就是求餘數,使用的運算子是 %。C 語言中的取餘運算只能針對整數,也就是說,% 的兩邊都必須是整數,不能出現小數,否則編譯器會報錯。
另外,餘數可以是正數也可以是負數,由 % 左邊的整數決定:

  • 如果 % 左邊是正數,那麼餘數也是正數;
  • 如果 % 左邊是負數,那麼餘數也是負數;
    例如:
#include <stdio.h>

int main()
{
    printf( "100%%12=%d \n100%%-12=%d \n-100%%12=%d \n-100%%-12=%d \n", 100%12, 100%-12, -100%12, -100%-12 );
    return 0;
}

執行結果:

100%12=4
100%-12=4
-100%12=-4
-100%-12=-4 

4、a++ 與 ++a 區別在於一個後加,一個先加。
a++ 輸出 a 的值再自加,快取 a 自加後的結果,用於下次進行與 a 相關的計算。
++a 則相當於 a+1。

#include <stdio.h>

int main(int argc, char **argv) {
    int a=100;
    int b=50;
//    b++;
    printf("%d,%d\n",a++,++a);
    printf("%d,%d",b++,++b);
    return 0;
}

執行後輸出:

101,102
51,52

若不註釋 b++:

int main(int argc, char **argv) {
    int a=100;
    int b=50;
    b++;
    printf("%d,%d\n",a++,++a);
    printf("%d,%d",b++,++b);
    return 0;
}

則結果為:

101,102
52,53

相關文章