1. 程式人生 > >c語言 基本運算

c語言 基本運算

計算機的基本能力就是計算,所以一門程式設計語言的計算能力是非常重要的。C語言之所以無所不能,是因為它不僅有豐富的資料型別,還有強大的計算能力。C語言一共有34種運算子,包括了常見的加減乘除運算。這講就對C語言中的運算子做一個詳細介紹。

一:算術運算子

算術運算子非常地簡單,就是小學數學裡面的一些加減乘除操作。不過呢,還是有一些語法細節需要注意的。

1.加法運算子 + 

1 int a = 10;
2 
3 int b = a + 5;

在第3行利用加法運算子 + 進行了加法運算,再將和賦值給了變數b,最終變數b的值是15

 

2.減法運算子 或 負值運算子 - 

1 int b = 10 - 5;
2 
3 int a = -10;

1> 在第1行利用減法運算子 - 進行了減法運算,再將差賦值給了變數b,最終變數b的值是5

2> 在第3行中,這個 - 並不是什麼減法運算子,而算是一個負值運算子,-10代表的是負十

 

3.乘法運算子 * 

1 int b = 10 * 5;

注意:乘法運算子並不是x或者X,而是星號*。變數b最終的值是50。

 

4.除法運算子 / 

1 double a = 10.0 / 4;
2 double b = 10 / 4;
3  
4 printf("a=%f, b=%f \n", a, b);

注意:除法運算子並不是÷,而是一個正斜槓 /

1> 第1行中的10.0是浮點型,4是整型,因此會將4自動型別提升為浮點型後再進行運算,最後變數b的值是2.5

2> 第2行中的10和4都是整型,計算機中的運算有個原則:相同資料型別的值才能進行運算,而且運算結果依然是同一種資料型別。因此,整數除於整數,求出來的結果依然是整數,會損失小數部分。最後變數b的值是2。檢視輸出結果:

3> 如果想讓 整數除於整數 不損失精度的話,可以將某個整數強制轉換為浮點型資料

複製程式碼 複製程式碼
1 double a = (double)10 / 4;
2 
3 double b = 10 / (double)4;
4 
5 double c = (double)10 / (double)4;
6 
7 double d = (double) (10 / 4);
複製程式碼 複製程式碼
  • 10和4之間只要有1個強轉為浮點型資料即可,另外1個整數會自動型別提升為浮點型資料。因此,變數a、b、c的值都是2.5。
  • 變數d的情況就不一樣了,第7行程式碼的意思是先計算(10/4)的值,再將(10/4)的值強轉為浮點型資料。(10/4)的值是2,將2強轉為浮點型資料,那不也就是2麼?所以,變數d的值是2

 

5.模運算子 或稱 取餘運算子 % 

注意:這個%並不是除號÷,它是一個取餘運算子,或者叫做模運算子。取餘的意思是,取得兩個整數相除之後的餘數。比如,5除於2的餘數是1,5除於3的餘數是2。因此使用這個%有個原則:%兩側必須都為整數。下面的寫法是錯誤的:

1 int a = 5.0 % 2;

編譯器會直接報錯,因為5.0並非整數。

1> 正數取餘

1 int a = 5 % 2;
2 int b = 2 % 5;

簡單計算可得:變數a的值為1,變數b的值為2

 2> 負數取餘

1 int a = -5 % 2;
2 int b = 5 % -2;
3 int c = -5 % -2; 

利用%求出來的餘數是正數還是負數,由%左邊的被除數決定,被除數是正數,餘數就是正數,反之則反。因此變數a、b、c的值分別是-1、1、-1

 

6.運算順序

1> 算術表示式

用算術運算子將資料連線起來的式子,稱為“算術表示式”。比如a + b、10 * 5等。如果表示式比較複雜的話,那麼就要注意一下它的運算順序。表示式的運算順序是按照運算子的結合方向和優先順序進行的。

2> 結合方向

算術運算子的結合方向是從左到右。例如表示式2+3+4,先計算2+3。

3> 優先順序

優先順序越高,就越先進行運算,當優先順序相同時,參照結合方向。下面是算術運算子的優先順序排序:

負值運算子(-) > 乘(*)、除(/)、模(%)運算子 > 加(+)、減(-)運算子

例如表示式4+5*8/-2的計算順序為:-、*、/、+,最後的結果是-16

4> 小括號

如果需要先計算優先順序低的可以使用小括號()括住,小括號的優先順序是最高的!

  • 例如4+5*8-2預設的計算順序是:*、+、-
  • 如果想先執行加法運算,就可以這樣寫:(4+5)*8-2,最後的結果都是不一樣的

 

二、賦值運算子

賦值運算子又分兩種:簡單賦值運算子 和 複合賦值運算子。

1.簡單賦值運算子 =

1> 簡單用法

其實這個等號 = 從講變數開始就見過它了,它的作用是將右邊的值賦值給左邊。

1 int a = 10 + 5;

賦值運算子的結合方向是:從右到左,而且優先順序比算術運算子低。因此先進行等號=右邊的加法運算,運算完畢後再將結果賦值給等號右邊的變數。最後變數a的值是15。

 

2> 連續賦值

1 int a, b;
2 
3 a = b = 10;
  • 在第1行分別定義了int型別的變數a、b
  • 第3行程式碼的意思:將10賦值給變數b,再把變數b的值賦值給a。所以最後變數a、b的值都是10

 

3> 使用注意

等號=左邊只能是變數,不能是常量!常量都是不可變的,怎麼可以再次賦值呢?下面的寫法是錯誤的:

1 10 = 10 + 5;

 

2.複合賦值運算子

  • +=  加賦值運算子。如a += 3+2,等價於 a = a +(3+2)
  • -=  減賦值運算子。如a -= 3+2,等價於 a = a -(3+2)
  • *=  乘賦值運算子。如a *= 3+2,等價於 a = a *(3+2)
  • /=  除賦值運算子。如a /= 3+2,等價於 a = a /(3+2)
  • %=  取餘賦值運算子。如a %= 3+2,等價於 a = a %(3+2)

 

三、自增運算子和自減運算子

1.簡介

  • ++  自增運算子。如a++,++a,都等價於a = a+1
  • --  自減運算子。如a--,--a,都等價於a = a-1

注意:你寫個5++是錯誤的,因為5是常量。

 

2.++a和a++的區別

1> 單獨使用++a和a++時,它們是沒區別的

1 int a = 10;
2 a++;
1 int a = 10;
2 ++a;

上面兩段程式碼的效果都是讓a的值+1,最後a的值都為11

 

2> 下面這種情況,++a和a++就有區別了

1 int a = 10;
2 
3 int b = ++a;
1 int a = 10;
2 
3 int b = a++;

 上面兩段程式碼的執行結果是有區別的。

  • 第1段程式碼:++a的意思是先對a執行+1操作,再將a的值賦值給b。因此最後a、b的值都是11
  • 第2段程式碼:a++的意思是先將a的值拷貝出來一份,然後對a執行+1操作,於是a變成了11,但是拷貝出來的值還是10,a++運算完畢後,再將拷貝出來的值10賦值給了b,所以最後變數b的值是10,變數a的值是11

--a和a--的區別也是一樣的。

 

3> 再來看一個比較刁鑽的例子

1 int a = 10;
2 
3 a = a++;

很多人一眼看上去,覺得最後a的值應該是11,其實最後a的值是10。前面已經說過a++的作用了,這裡也是一樣的。先將a的值拷貝出來一份,然後對a執行+1操作,於是a變成了11,但是拷貝出來的值還是10,a++運算完畢後,再將拷貝出來的值10賦值給了a,所以最後變數a的值是10

 

四、sizeof

* sizeof可以用來計算一個變數或者一個常量、一種資料型別所佔的記憶體位元組數。

int size = sizeof(10);
printf("10所佔的位元組數:%d", size);

輸出結果:,10是int型別的資料,在64bit編譯器環境下,int型別需要佔用4個位元組

* sizeof一共有3種形式

  • sizeof( 變數\常量 )
sizeof(10);

char c = 'a';
sizeof(c);
  • sizeof  變數\常量
sizeof 10;

char c = 'a';
sizeof c;
  • sizeof( 資料型別 )
sizeof(float);

注意,不可以寫成sizeof float;

 

五、逗號運算子

* 逗號運算子主要用於連線表示式,例如:

1 int a = 9;
2 int b = 10;
3 
4 a = a+1 , b = 3*4;

* 用逗號運算子連線起來的表示式稱為逗號表示式,它的一般形式為:

表示式1, 表示式2, … …, 表示式n

逗號表示式的運算過程是:從左到右的順序,先計算表示式1,接著計算表示式2,...,最後計算表示式n

* 逗號運算子也是一種運算子,因此它也有運算結果。整個逗號表示式的值是最後一個表示式的值

複製程式碼 複製程式碼
1 int a = 2;
2 int b = 0;
3 int c;
4 
5 c = (++a, a *= 2, b = a * 5);
6 
7 printf("c = %d", c);
複製程式碼 複製程式碼

 ++a的結果為3,a *= 2的結果為6,b = a * 5的結果為30。因此,輸出結果為:

這裡要注意的是,右邊的表示式是有用括號()包住的,如果不用括號包住,也就是:

1 c = ++a, a *= 2, b = a * 5;
2 printf("c = %d", c);

輸出結果將為:,因為c = ++a也屬於逗號表示式的一部分,跟後面的a *= 2以及b = a * 5是相互獨立的

 

六、關係運算符

1.“真”與“假”

1> 預設情況下,我們在程式中寫的每一句正確程式碼都會被執行。但很多時候,我們想在某個條件成立的情況下才執行某一段程式碼。比如微信的這個介面:

如果使用者點選了註冊按鈕,我們就執行“跳轉到註冊介面”的程式碼;如果使用者點選了登入按鈕,我們就執行“跳轉到登入介面”的程式碼。如果使用者沒做出任何操作,就不執行前面所說的兩段程式碼。像這種情況的話可以使用條件語句來完成,但是我們暫時不學習條件語句,先來看一些更基礎的知識:如何判斷一個條件成不成立。如果這個都不會判斷,還執行什麼程式碼。

2> 在C語言中,條件成立稱為“真”,條件不成立稱為“假”,因此,判斷條件是否成立,就是判斷條件的“真假”。那怎麼判斷真假呢?C語言規定,任何非0值都為“真”,只有0才為“假”。也就是說,108、-18、4.5、-10.5等都是“真”,0則是“假”。

 

2.關係運算符的簡單使用

C語言中還提供了一些關係運算符,可以用來比較兩個數值的大小。

  • <   小於。比如a<5
  • <=  小於等於。比如a<=5
  • >   大於。比如a>5
  • >=  大於等於。比如a>=5
  • ==  等於。比如a==5
  • !=  不等於。比如a!=5

關係運算符的運算結果只有2種:如果條件成立,結果就為1,也就是“真”;如果條件不成立,結果就為0,也就是“假”。

1 int a1 = 5 > 4; // 1
2 
3 int a2 = 5 < 4; // 0

 

3.關係運算符的使用注意

1> 關係運算符中==、!=的優先順序相等,<、<=、>、>=的優先順序相等,且前者的優先順序低於後者

例如2==3>1 :先算3>1,條件成立,結果為1。再計算2==1,條件不成立,結果為0。因此2==3>1的結果為0。

2> 關係運算符的結合方向為“從左往右”

例如4>3>2 :先算4>3,條件成立,結果為1。再與2比較,即1>2,條件不成立,結果為0。因此4>3>2的結果為0。

3> 關係運算符的優先順序小於算術運算子

例如3+4>8-2 :先計算3+4,結果為7。再計算8-2,結果為6。最後計算7>6,條件成立,結果為1。因此3+4>8-2的結果為1。

 

七、邏輯運算子

 有時候,我們需要在多個條件同時成立的時候才能執行某段程式碼,比如:使用者只有同時輸入了QQ和密碼,才能執行登入程式碼,如果只輸入了QQ或者只輸入了密碼,就不能執行登入程式碼。這種情況下,我們就要藉助於C語言提供的邏輯運算子。

C語言提供了3個邏輯運算子:&&(邏輯與)、||(邏輯或)、!(邏輯非)。注意:這些都是英文字元,不要寫成中文字元。跟關係運算符一樣,邏輯運算的結果只有2個:“真”為1,“假”為0

1.&& 邏輯與

1> 使用格式

“條件A && 條件B”

2> 運算結果

只有當條件A和條件B都成立時,結果才為1,也就是“真”;其餘情況的結果都為0,也就是“假”。因此,條件A或條件B只要有一個不成立,結果都為0,也就是“假”

3> 運算過程

  • 總是先判斷條件A是否成立
  • 如果條件A成立,接著再判斷條件B是否成立:如果條件B成立,“條件A && 條件B”的結果就為1,即“真”,如果條件B不成立,結果就為0,即“假”
  • 如果條件A不成立,就不會再去判斷條件B是否成立:因為條件A已經不成立了,不管條件B如何,“條件A && 條件B”的結果肯定是0,也就是“假”

4> 舉例

邏輯與的結合方向是“自左至右”。比如表示式 (a>3) && (a<5)

  • 若a的值是4:先判斷a>3,成立;再判斷a<5,也成立。因此結果為1
  • 若a的值是2:先判斷a>3,不成立,停止判斷。因此結果為0
  • 因此,如果a的值在(3, 5)這個範圍內,結果就為1;否則,結果就為0

5> 注意

  • 若想判斷a的值是否在(3, 5)範圍內,千萬不能寫成3<a<5,因為關係運算符的結合方向為“從左往右”。比如a為2,它會先算3<a,也就是3<2,條件不成立,結果為0。再與5比較,即0<5,條件成立,結果為1。因此3<a<5的結果為1,條件成立,也就是說當a的值為2時,a的值是在(3, 5)範圍內的。這明顯是不對的。正確的判斷方法是:(a>3) && (a<5)
  • C語言規定:任何非0值都為“真”,只有0才為“假”。因此邏輯與也適用於數值。比如 5 && 4的結果是1,為“真”;-6 && 0的結果是0,為“假”

 

2.||  邏輯或

1> 使用格式

“條件A || 條件B”

2> 運算結果

當條件A或條件B只要有一個成立時(也包括條件A和條件B都成立),結果就為1,也就是“真”;只有當條件A和條件B都不成立時,結果才為0,也就是“假”。

3> 運算過程

  • 總是先判斷條件A是否成立
  • 如果條件A成立,就不會再去判斷條件B是否成立:因為條件A已經成立了,不管條件B如何,“條件A || 條件B”的結果肯定是1,也就是“真”
  • 如果條件A不成立,接著再判斷條件B是否成立:如果條件B成立,“條件A || 條件B”的結果就為1,即“真”,如果條件B不成立,結果就為0,即“假”

4> 舉例

邏輯或的結合方向是“自左至右”。比如表示式 (a<3) || (a>5)

  • 若a的值是4:先判斷a<3,不成立;再判斷a>5,也不成立。因此結果為0
  • 若a的值是2:先判斷a<3,成立,停止判斷。因此結果為1
  • 因此,如果a的值在(-∞, 3)或者(5, +∞)範圍內,結果就為1;否則,結果就為0

 

5> 注意

 C語言規定:任何非0值都為“真”,只有0才為“假”。因此邏輯或也適用於數值。比如 5 || 4的結果是1,為“真”;-6 || 0的結果是1,為“真”;0 || 0的結果是0,為“假”

 

3.!   邏輯非

1> 使用格式

“! 條件A”

2> 運算結果

其實就是對條件A進行取反:若條件A成立,結果就為0,即“假”;若條件A不成立,結果就為1,即“真”。也就是說:真的變假,假的變真。

3> 舉例

邏輯非的結合方向是“自右至左”。比如表示式 ! (a>5)

  • 若a的值是6:先判斷a>5,成立,再取反之後的結果為0
  • 若a的值是2:先判斷a>3,不成立,再取反之後的結果為1
  • 因此,如果a的值大於5,結果就為0;否則,結果就為1

4> 注意

  • 可以多次連續使用邏輯非運算子:!(4>2)結果為0,是“假”,!!(4>2)結果為1,是“真”,!!!(4>2)結果為0,是“假”
  • C語言規定:任何非0值都為“真”,只有0才為“假”。因此,對非0值進行邏輯非!運算的結果都是0,對0值進行邏輯非!運算的結果為1。!5、!6.7、!-9的結果都為0,!0的結果為1

 

4.優先順序

邏輯運算子的優先順序順序為: 小括號() > 負號 - > ! > 算術運算子 > 關係運算符 > && > ||

  • 表示式!(3>5) || (2<4) && (6<1) :先計算 !(3>5)、(2<4)、(6<1),結果為1,式子變為1 || 1 && 0,再計算1 && 0,式子變為1 || 0,最後的結果為1
  • 表示式3+2<5||6>3 等價於 ((3+2) < 5) || (6>3),結果為1
  • 表示式4>3 && !-5>2 等價於 (4>3) &&  ((!(-5)) > 2) ,結果為0

 

八、三目運算子

1.N目運算子

  • 像邏輯非(!)、負號(-)這種只連線一個數據的符號,稱為“單目運算子”,比如!5、-5。
  • 像算術運算子、關係運算符、邏輯運算子這種連線二個數據的負號,稱為“雙目運算子”,比如6+7、8*5、5>6、4 && 0、
  • 以此類推,連線3個數據的運算子,應該稱為“三目運算子”

 

2.三目運算子

C語言提供了唯一一個三目運算子:條件運算子。

1> 使用格式

表示式A ? 表示式B : 表示式C

2> 運算結果

如果表示式A成立,也就是為“真”,條件運算子的結果就是表示式B的值,否則,就為表示式C的值

3> 結合方向和優先順序

  • 優先順序順序為:算術運算子 > 關係運算符 > 條件運算子 > 賦值運算子
  • 條件運算子的結合方向是“從右至左”
1 int a = 3>4 ? 4+5 : 5>4 ? 5+6 : 6>7+1;

上面的程式碼等價於

1 int a = (3>4) ? (4+5) : ( (5>4) ? (5+6) : (6>(7+1)) );

簡化一下就是

1 int a = 0 ? 9 : ( 1 ? 11 : 0 );

繼續簡化為

1 int a = 0 ? 9 : 11;

所以a的值是11

 

九、位運算子

所謂位運算就是對每一個二進位制位進行運算。C語言一共提供了6種位運算子,只能對整數進行操作,分別是:&按位與、|按位或、^按位異或、<<左移、>>右移、~取反。

1.& 按位與

1> 使用形式:整數a & 整數b

2> 功能:整數a和b各對應的二進位相與。只有對應的兩個二進位均為1時,結果位才為1,否則為0。參與運算的數以補碼方式出現。

3> 舉例:比如9&5,其實就是1001&101=1,因此9&5=1

4> 規律:

  • 相同整數相&的結果是整數本身。比如5&5=5
  • 多個整數相&的結果跟順序無關。比如5&6&7=5&7&6

 

2.| 按位或

1> 使用形式:整數a | 整數b

2> 功能:整數a和b各對應的二進位相或。只要對應的二個二進位有一個為1時,結果位就為1,否則為0。參與運算的數以補碼方式出現。

3> 舉例:比如9|5,其實就是1001|101=1101,因此9|5=13

4> 規律:

  • 相同整數相|的結果是整數本身。比如5|5=5
  • 多個整數相|的結果跟順序無關。比如5|6|7=5|7|6

 

3.^ 按位異或

1> 使用形式:整數a ^ 整數b

2> 功能:整數a和b各對應的二進位相異或。當對應的二進位相異(不相同)時,結果為1,否則為0。參與運算的數以補碼方式出現。

3> 舉例:比如9^5,其實就是1001^101=1100,因此9^5=12

4> 規律:

  • 二進位制中,與1相^就會取反,與0相^保持原位
  • 相同整數相^的結果是0。比如5^5=0
  • 多個整數相^的結果跟順序無關。比如5^6^7=5^7^6
  • 因此得出結論:a^b^a = b

 

4.~ 取反

1> ~為單目運算子,具有右結合性,使用形式:~整數a

2> 功能:對整數a的各二進位進行取反(0變1,1變0)

3> 舉例:比如~9,其實就是~(0000 0000 0000 0000 0000 0000 0000 1001)=(1111 1111 1111 1111 1111 1111 1111 0110),因此~9=-10

 

5.<< 左移

1> <<是雙目運算子,使用形式:整數a<<正數n

2> 功能:把整數a的各二進位全部左移n位,高位丟棄,低位補0。左移n位其實就是乘以2的n次方。

3> 舉例:3<<4,3本來是0000 0011,左移4位後變成了0011 0000,因此3<<4 = 48 = 3 * 24

4> 需要注意的是:由於左移是丟棄最高位,0補最低位,所以符號位也會被丟棄,左移出來的結果值可能會改變正負性

 

6.>> 右移

1> >>是雙目運算子,使用形式:整數a>>正數n

2> 功能:把整數a的各二進位全部右移n位,保持符號位不變。右移n位其實就是除以2的n次方。

3> 舉例:32>>3,32本來是0010 0000,右移3位後變成了0000 0100,因此32>>3 = 4 = 32 / 23