欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C 語言基礎教程(我的C之旅開始了)[九]

 更新時間:2007年02月25日 00:00:00   作者:  

24. +、-、*、/、= 的優(yōu)先級

1. 優(yōu)先級

    和數(shù)學一樣,C 語言規(guī)定先乘除后加減。也就是說,乘法運算符和除法運算符的優(yōu)先級Precedence)比加法運算符和減法運算符高。同時,C 語言也規(guī)定,如果兩個運算符的優(yōu)先級相同,并且它們之間沒有被優(yōu)先級比它們高或者低的運算符隔開,則它們的運算順序根據(jù)它們在語句中出現(xiàn)的先后而定。大多數(shù)運算符都是從左向右進行運算的,不過也有從右向左進行運算的(例如賦值運算符)。乘法運算符和除法運算符的優(yōu)先級相同,加法運算符和減法運算符的優(yōu)先級相同。因此,以下語句

        var = 8.0 + 20.0 / 4.0 * 2.0;

運算順序為:

        20.0 / 4.0
        5.0 * 2.0  (20.0 / 4.0 得 5.0)
        8.0 + 10.0
        var = 18.0

在這個表達式中,/ 和 * 優(yōu)先級相同,而且是從左向右進行運算的,所以先運算 20.0 / 4.0,然后才輪到 5.0 * 2.0。

    如果我們想讓加法先進行,可以給 8.0 + 20.0 加上括號

        var = (8.0 + 20.0) / 4.0 * 2.0;

這個語句的運算順序為:

        8.0 + 20.0
        28.0 / 4.0
        7.0 * 2.0
        var = 14.0

    C 語言規(guī)定,先進行括號里面的運算,后進行括號外面的運算。在括號里面,運算順序和上面討論的一樣。例如:

        var = (8.0 + 20.0 / 4.0 * 2.0) / 3.0;

運算順序為:

        20.0 / 4.0
        5.0 * 2.0
        8.0 + 10.0
        18.0 / 3.0
        var = 6.0

下表總結了這幾個運算符的優(yōu)先級以及它們的結合律,按優(yōu)先級從高到低進行排列

        運算符             結合律

          ()               從左向右
       + -(單目)         從右向左
         * /               從左向右
       + -(二目)         從左向右
          =                從右向左


2. 優(yōu)先級和運算順序

    運算符優(yōu)先級Operator precedence)是決定運算順序的重要規(guī)則,但不能完全(也沒必要完全)確定運算順序。例如:

        5 * 3 + 8 * 4;

根據(jù)運算符優(yōu)先級,我們知道,乘法運算先于加法運算。但是 5 * 3 和 8 * 4 誰先誰后,我們并不能確定。它們運算的先后是由編譯器決定的。這是因為某種運算順序在某種系統(tǒng)中效率更高,而另一種運算順序在另一種系統(tǒng)中效率更高。無論它們的運算先后如何,最終得到的結果都是 47。

    您可能會說:“乘法不是從左向右進行運算的嗎?這不是說明最左邊的乘法最先進行嗎?”是的,乘法的確是從左向右進行運算,但是您也要看到,這兩個乘法運算符之間被加法運算符隔開了!我們舉一個例子來說明乘法從左向右進行運算的意思。以下語句

        5 * 2 * 9 * 4;

運算順序為:

        5 * 2
        10 * 9
        90 * 4


下面我們來看一個小程序。

        /* precedence.c -- 優(yōu)先級測試 */
        #include <stdio.h>

        int main(void)
        {
            int var1, var2;

            var1 = var2 = -(9 + 4) * 5 + (6 + 8 * (7 - 1));
            printf("var1 = var2 = %d\n", var1);

            return 0;
        }

請認真閱讀以上程序,想想會出現(xiàn)什么結果,然后編譯運行,看看運行結果和您想象的是否一樣。

    首先,括號運算符優(yōu)先級最高。但是 (9 + 4) 和 (6 + 8 * (7 - 1)) 運算的先后是由編譯器決定的。假設 (9 + 4) 先進行,則運算后得 13,然后負號運算符作用于 13 得 -13。于是我們得到:

        var1 = var2 = -13 * 5 + (6 + 8 * (7 - 1));

在 (6 + 8 * (7 - 1)) 中,先運算 (7 - 1),得:

        var1 = var2 = -13 * 5 + (6 + 8 * 6);

因為 * 優(yōu)先級高于 +,于是我們得到:

        var1 = var2 = -13 * 5 + (6 + 48);

進而

        var1 = var2 = -13 * 5 + 54;
        var1 = var2 = -65 + 54;
        var1 = var2 = -11;

因為賦值運算是從右向左的,所以 -11 被賦值給 var2,接著 var2 被賦值給 var1。最終的結果是,var1 和 var2 相等,它們的值都是 -11。


 

25. 模除運算符 %

 

    %模除運算符Modulus Operator),用于求余數(shù)。% 只可用于對整數(shù)進行模除,不可用于浮點數(shù)。例如:

          15 % 2       // 正確。余數(shù)為 1
          15.2 % 3     // 錯誤!

C99 以前,并沒有規(guī)定如果操作數(shù)中有負數(shù),模除的結果會是什么。C99 規(guī)定,如果 % 左邊的操作數(shù)是正數(shù),模除的結果也是正數(shù);如果 % 左邊的操作數(shù)是負數(shù),模除的結果就是負數(shù)。例如:

          15 % 2       // 余 1
          15 % -2      // 余 1
          -15 % 2      // 余 -1
          -15 % -2     // 余 -1

標準規(guī)定,如果 a 和 b 都是整數(shù),則 a % b 可以用公式 a - (a / b) * b 算出。例如:

          -15 % 2 == -15 - (-15 / 2) * 2 == -15 - (-7) * 2 == -1

最后,我們看一個小程序。

        /* months_to_year.c -- 將用戶輸入的月數(shù)轉換成年數(shù)和月數(shù) */

        #include <stdio.h>

        int main(void)
        {
            int months, years, months_left, months_per_year = 12;

            printf("Enter the number of months: ");
            scanf("%d", &months);

            years = months / months_per_year;         /* 算出年數(shù) */
            months_left = months % months_per_year;   /* 算出剩余的月數(shù) */

            printf("%d months is %d years, %d months.\n", months, years, months_left);

            return 0;
        }

26. 自增運算符和自減運算符
 

1. 自增運算符(Increment Operator)

    自增運算符 ++ 使操作數(shù)的值增 1。++ 可以置于操作數(shù)前面,也可以放在后面。例如:

        ++n ;
        n++ ;

這兩個語句產生的結果都是使 n 增 1,可以說沒什么區(qū)別。使用以下語句得到的效果也是一樣的:

        n = n + 1 ;

    盡管上面兩個語句中,++ 前置和后置沒有區(qū)別。但是,++ 前置和后置其實是有區(qū)別的。例如:

        int n = 1, post, pre;

        post = n++;
        pre = ++n;

對于 post = n++; 這個語句,n 的值被賦予 post 后,n 才增 1。也就是說,這個語句執(zhí)行完后,post 的值是 1,而 n 的值變成 2。而 pre = ++n; 這個語句,n 先增 1,然后再把自增后的值賦予 pre。也就是說,這個語句執(zhí)行完后,pre 的值是 3,n 的值也是 3。

    由此可得,如果 ++ 前置,則 ++ 的操作數(shù)先增 1,然后再參與其它運算;如果 ++ 后置,則 ++ 的操作數(shù)先參與其它運算,然后才增 1。嚴格地說,前置 ++ 的操作數(shù)的值在被使用之前增 1,而后置 ++ 的操作數(shù)的值在被使用之后增 1。例如:

        int n = 5, post = 1, pre = 1;
        pre = ++n + pre;    // 運算結束后 pre 為 7
        n = 5;
        post = n++ + post;  // 運算結束后 post 為 6

 

2. 自減運算符(Decrement Operator)

    自減運算符 -- 使操作數(shù)的值減 1。-- 可以置于操作數(shù)前面,也可以放在后面。例如:

        --n ;
        n-- ;

自減運算符和自增運算符非常相似,區(qū)別只在于自減運算符使操作數(shù)減 1,而自增運算符使操作數(shù)增 1。例如:

        int n = 5, post = 1, pre = 1;
        pre = --n + pre;    // 運算結束后 pre 為 5
        n = 5;
        post = n-- + post;  // 運算結束后 post 為 6

 

3. 優(yōu)先級

    自增運算符和自減運算符的優(yōu)先級很高,只有圓括號的優(yōu)先級比它們高。因此,n*m++; 表示 n*(m++); 而不是 (n * m)++; 。而且 (n * m)++; 是錯誤的。因為 ++ 和 -- 的操作數(shù)只能是可變左值(modifiable lvalue),而 n * m 不是。

    注意,不要把優(yōu)先級和取值順序混淆了。例如:

        int x = 1, y = 2, z;

        z = (x + y++) * 3;   // 運算結束后 z 為 9,y 為 3

用數(shù)字代替上面的語句得:

        z = (1 + 2) * 3;

僅當 y 的值被使用后,y 才會增 1。優(yōu)先級表明的是 ++ 僅作用于 y,而不是 (x + y)。優(yōu)先級也表明 y 的值何時被使用,但是 y 的值何時增 1 是由自增運算符的本質決定的。

    當 y++ 是某個算術表達式的一部分時,您可以認為它表示“先使用 y 的值,然后自增”。類似地,++y 表示“先自增,然后使用自增后的值”。

==========================================================================

以下內容引自《C 語言常見問題集》 原著:Steve Summit 翻譯:朱群英, 孫 云

http://c-faq-chn.sourceforge.net/ccfaq/index.html

http://www.eskimo.com/~scs/C-faq/top.html

==========================================================================

4.3 對于代碼  int i = 3; i = i++; 不同編譯器給出不同的結果, 有的為 3, 有的為 4, 哪個是正確的?

    沒有正確答案;這個表達式無定義。參見問題 3.1, 3.7 和  11.32。 同時注意, i++ 和 ++i 都不同于 i+1。如果你要使 i 自增 1, 使用 i=i+1, i+=1, i++ 或 ++i, 而不是任何組合, 參見問題 3.10。

12.35 有人說 i = i++ 的行為是未定義的, 但是我剛在一個兼容 ANSI  的編譯器上測試, 得到了我希望的結果。

    面對未定義行為的時候, 包括范圍內的實現(xiàn)定義行為和未確定行為, 編譯器可以做任何實現(xiàn), 其中也包括你所有期望的結果。但是依靠這個實現(xiàn)卻不明智。參加問題 7.4, 11.31, 11.32 和 11.34。

4.2 使用我的編譯器,下面的代碼  int i=7; printf("%d\n", i++ * i++); 返回 49?不管按什么順序計算, 難道不該打印出56嗎?

    盡管后綴自加和后綴自減操作符 ++ 和 -- 在輸出其舊值之后才會執(zhí)行運算, 但這里的``之后"常常被誤解。沒有任何保證確保自增或自減會在輸出變量原值之后和對表達式的其它部分進行計算之前立即進行。也不能保證變量的更新會在表達式 ``完成" (按照 ANSI C 的術語, 在下一個 ``序列點" 之前, 參見問題 3.7) 之前的某個時刻進行。本例中, 編譯器選擇使用變量的舊值相乘以后再對二者進行自增運算。

    包含多個不確定的副作用的代碼的行為總是被認為未定義。(簡單而言, ``多個不確定副作用" 是指在同一個表達式中使用導致同一對象修改兩次或修改以后又被引用的自增, 自減和賦值操作符的任何組合。這是一個粗略的定義; 嚴格的定義參見問題 3.7, ``未定義" 的含義參見問題 11.32。) 甚至都不要試圖探究這些東西在你的編譯器中是如何實現(xiàn)的 (這與許多 C 教科書上的弱智練習正好相反); 正如  K&R 明智地指出, ``如果你不知道它們在不同的機器上如何實現(xiàn), 這樣的無知可能恰恰會有助于保護你。

4.7 我怎樣才能理解復雜表達式?``序列點" 是什么?

    序列點是一個時間點(在整個表達式全部計算完畢之后或在 ||、  &&、 ? : 或逗號 運算符處, 或在函數(shù)調用之前), 此刻塵埃落定, 所有的副作用都已確保結束。 ANSI/ISO C 標準這樣描述:

在上一個和下一個序列點之間, 一個對象所保存的值至多只能被表達式的計算修改一次。而且前一個值只能用于決定將要保存的值。

第二句話比較費解。它說在一個表達式中如果某個對象需要寫入, 則在同一表達式中對該對象的訪問應該只局限于直接用于計算將要寫入的值。這條規(guī)則有效地限制了只有能確保在修改之前才訪問變量的表達式為合法。例如 i = i+1 合法, 而 a[i] = i++ 則非法 (參見問題 3.1)。

參見下邊的問題 3.8。

相關文章

  • C++中關于union的使用方法說明

    C++中關于union的使用方法說明

    這篇文章主要介紹了C++中關于union的使用方法說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 深入C++中struct與class的區(qū)別分析

    深入C++中struct與class的區(qū)別分析

    本篇文章是對C++中struct與class的區(qū)別進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 詳解C/C++中const限定符總結

    詳解C/C++中const限定符總結

    const是一種限定符,被const所限定的變量其值不可以被改變。。這篇文章主要介紹了C/C++中const限定符總結,通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • Qt實現(xiàn)蘋果狀態(tài)切換按鈕

    Qt實現(xiàn)蘋果狀態(tài)切換按鈕

    這篇文章主要為大家詳細介紹了Qt實現(xiàn)蘋果狀態(tài)切換按鈕,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C++自定義數(shù)據(jù)類型方法詳情

    C++自定義數(shù)據(jù)類型方法詳情

    這篇文章主要介紹了C++自定義數(shù)據(jù)類型方法詳情,總結了兩種方法,分別是typedef聲明和枚舉類型enum,相關內容需要的小伙伴可以參考下面文章內容,希望對你的學習有所幫助
    2022-03-03
  • C++中發(fā)聲函數(shù)Beep用法

    C++中發(fā)聲函數(shù)Beep用法

    本文給大家分享的是Beep函數(shù)的用法以及會使揚聲器發(fā)出簡單的聲音的示例,有需要的小伙伴可以參考下
    2017-05-05
  • C語言實現(xiàn)enum枚舉

    C語言實現(xiàn)enum枚舉

    在實際編程中,有些數(shù)據(jù)的取值往往是有限的,只能是非常少量的整數(shù),并且最好為每個值都取一個名字,以方便在后續(xù)代碼中使用,比如一個星期只有七天,一年只有十二個月,一個班每周有六門課程等。 以每周七天為例,我們可以使用#define命令來給每天指定一個名字
    2021-06-06
  • 結合C++11新特性來學習C++中l(wèi)ambda表達式的用法

    結合C++11新特性來學習C++中l(wèi)ambda表達式的用法

    這篇文章主要介紹了C++中l(wèi)ambda表達式的用法,lambda表達式的引入可謂是C++11中的一大亮點,同時文中也涉及到了C++14標準中關于lambda的一些內容,需要的朋友可以參考下
    2016-01-01
  • C語言遞歸應用實現(xiàn)掃雷游戲

    C語言遞歸應用實現(xiàn)掃雷游戲

    這篇文章主要為大家詳細介紹了C語言遞歸應用實現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 從C++單例模式到線程安全詳解

    從C++單例模式到線程安全詳解

    下面小編就為大家?guī)硪黄獜腃++單例模式到線程安全詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12

最新評論