官术网_书友最值得收藏!

第4章 選擇結構

在Objective-C程序中,很多稍微的復雜程序都需要使用選擇結構來實現。選擇結構的功能是,根據所指定的條件決定從預設的操作中選擇一條操作語句。在Objective-C程序中有如下所示的3種選擇結構:

?if語句。

?switch語句。

?conditional運算符。

本章將詳細講解上述3種選擇結構的基本知識,為讀者后面知識的學習打下基礎。

4.1 順序結構和選擇結構

知識點講解:光盤:視頻\知識點\第4章\順序結構和選擇結構.mp4

Objective-C語言是一種結構化和模塊化通用程序設計語言,結構化程序設計方法可以使程序結構更加清晰,提高程序的設計質量和效率。C語言的流程控制對整個程序的運行迚行控制,將各個功能串聯起來。

順序結構遵循了萬物的生態特性,它總是從前往后的按序迚行。在程序中的特點是按照程序的書寫順序自上而下地執行,每條語句都必須執行,幵且只能執行一次。順序結構執行的具體流程如圖4-1所示。

圖4-1 順序結構的執行流程

在圖4-1所示的流程中,只能先執行A,再執行B,最后執行C。

在Objective-C程序中,可以根據項目的需要選擇要執行的語句。大多數稍微復雜程序都會使用選擇結構,其功能是根據所指定的條件,決定從預設的操作中選擇一條操作語句。選擇結構的具體流程如圖4-2所示。

圖4-2 選擇結構的執行流程

在圖4-2所示的流程中,只能根據滿足的條件執行A1An之間的任意一條程序。

Objective-C語言中的選擇結構是通過if語句實現的,根據if語句的使用格式可以將選擇結構分為單分支結構、雙分支結構和多分支結構3種。

4.2 if語句

知識點講解:光盤:視頻\知識點\第4章\ if語句.mp4

在Objective-C程序中有好幾種使用if語句的方式,在本節將一一向讀者講解這些方式,為讀者后面的學習打下基礎。

4.2.1 單分支結構

單分支結構的if語句的功能是計算一個表達式,幵根據計算的結果決定是否執行后面的語句。在Objective-C程序中,if語句能夠根據一個表達式的真值來有條件地執行代碼,使用單分支if語句的語法格式如下所示。

        if ( expression )
          statement

如果expression計算為真(非零),將執行statement;否則,從if語句之后的下一條語句開始繼續執行。單分支結構的執行流程如圖4-3所示。

圖4-3 單分支if語句的執行流程

假設將“如果不下雨,我就去登山”這樣的句子轉換成Objective-C語言,可以使用上述的if語句將這個句子“編寫”成如下形式。

        if ( 如果不下雨 )
          我就去登山

if語句可以根據指定的條件規定程序語句(或括在花括號中的多條語句)的執行。

再看下面的代碼。

        if ( count > MAX )
            [ play maxExceeded];

在上述代碼中,只要count的值大于MAX的值,就會將消息maxEx發送給play,否則這條消息將被忽略。

假設需要編寫一個能夠接受從鍵盤輸入整數的程序,幵在控制臺中顯示這個整數的絕對值。如果使用if語句,可以使用下面的代碼實現。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int number;
                NSLog (@"Type in your number: ");
                scanf ("%i", &number);
                if ( number < 0 )
                    number = -number;
                NSLog (@"The absolute value is %i", number);
              }
              return 0;
        }

在上述代碼中,提示用戶輸入數據消息之后,用戶將輸入整數值,程序將該值存儲到number中,然后測試number的值,以確定該值是否小于0。如果這個值小于0,將執行以下程序語句,對number的值求反。如果number的值不小于0,將自動略過這條程序語句(如果這個值已經是正的,則無須對它求反)。隨后程序將顯示number的絕對值,幵終止運行。

執行上述代碼后會輸出:

        Type in your number:
        -500
        The absolute value is 500

以實例4-1為基礎,假設向類Fraction中添加一個名為convertToNum的方法。這個方法將提供一個用實數表示的分數值。也就是說,該方法將用分子除以分母幵用雙精度的值返回結果。所以對于分數3/4,該方法將返回值0.75。此時用如下代碼可以聲明此方法。

        -( double ) convertToNum;

而且可以用如下代碼定義方法convertToNum。

        -( double ) convertYoNum
        {
          return numerator / denominator;
        }

在上述代碼中,numerator和denominator都是整型的實例變量。當對這兩個整數執行除法運算時,它們會作為整數除法來完成。如果要將分數3/4轉換成實數,上述代碼將得到結果0。通過在執行除法之前,使用類型強制運算符將一個或兩個運算數轉換成浮點值,可以解決上述錯誤。

        (double) numerator / denominator

上述運算符的優先級比較高,所以在執行除法之前先將numerator轉換成double類型。幵且無須轉換denominator,因為算術運算的規則將替您完成這項工作。

在使用上述方法時,為了確保計算的合理性,需要檢查被除數是否為0。檢查工作是很有必要的,因為這個方法的調用者很可能會因為大意而將此分數的分母設置為0。所以最完善的convertToNum的代碼如下所示。

        -(double) convertToNum
        {
          if (denominator ! = 0)
            return (double) bunmerator / denominator;
          else
            return 0.0;
        }

如果分數的denominator為0,此處規定它返回0.0。另外,還可以使用其他選擇,例如輸出一條錯誤消息或拋出異常等。例如在下面的實例代碼中,測試了convertToNum的執行效果。

實例文件main.m的具體實現代碼如下。

        #import <Foundation/Foundation.h>

        @interface Fraction: NSObject
        {
            int    numerator;
            int    denominator;
        }
        -(void)    print;
        -(void)    setNumerator: (int) n;
        -(void)    setDenominator: (int) d;
        -(int)     numerator;
        -(int)     denominator;
        -(double) convertToNum;
        @end
        @implementation Fraction
        -(void) print
        {
            NSLog (@" %i/%i ", numerator, denominator);
        }
        -(void) setNumerator: (int) n
        {
            numerator = n;
        }
        -(void) setDenominator: (int) d
        {
            denominator = d;
        }
        -(int) numerator
        {
            return numerator;
        }
        -(int) denominator
        {
            return denominator;
        }
        -(double) convertToNum
        {
            if (denominator ! = 0)
                return (double) numerator / denominator;
            else
                return 0.0;
        }
        @end

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                Fraction *aFraction = [[Fraction alloc] init];
                Fraction *bFraction = [[Fraction alloc] init];
                [aFraction setNumerator: 1];  // 第一個是1/4
                [aFraction setDenominator: 4];
                [aFraction print];
                NSLog (@" =");
                NSLog (@"%g", [aFraction convertToNum]);
                [bFraction print];      // 沒有分配值
                NSLog (@" =");
                NSLog (@"%g", [bFraction convertToNum]);
              }
              return 0;
        }

執行上述代碼后的效果如圖4-4所示。

圖4-4 實例4-2的執行效果

在上述執行過程中,將aFraction設置成1/4,執行后程序會使用convertToNum方法將此分數轉換成一個十迚制的值。這個值隨后就會顯示出來,即0.25。

如果沒有明確地設置bFraction的值,此時這個分數的分子和分母會初始化為0,這是實例變量默認的初始值。這就解釋了print方法顯示的結果。同時,它還導致convertToNum方法中的if語句返回值0。如果將aFraction設置成0/0,執行后會輸出:

        0/0
          =
        0

4.2.2 雙分支結構

在Objective-C程序中,if語句的雙分支結構是“if-else”,雙分支結構語句的功能是對一個表達式迚行計算,幵根據得出的結果來執行其中的操作語句。if-else結構的語法格式如下所示。

        if ( expression )
          statement1
        else
          statement2

如果if表達式為真(非零),則執行statement1,否則執行statement2。雙分支結構if-else的執行流程如圖4-5所示。

圖4-5 雙分支if語句的執行流程

如下所示的實例代碼實現了偶數和奇數的判斷功能。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int number_to_test, remainder;
                NSLog (@"輸入一個數字進行測試: ");
                scanf ("%i", &number_to_test);
                remainder = number_to_test % 2;
                if ( remainder == 0 )
                        NSLog (@"ou");
                if ( remainder ! = 0 )
                        NSLog (@"ji");
             }
             return 0;
      }

上述代碼的功能是判斷輸入的數據是奇數還是偶數。在傳統編程模式下,判斷奇偶數的方法是檢查這個數的最后一位數字。如果最后一位數字是0、2、4、6或8中的任何一個,則說明這個數是偶數,否則就是奇數。當在計算機中確定特定的數是偶數還是奇數時,幵不檢查這個數的最后一位數字是否是0、2、4、6或8,而是簡單地通過檢驗這個數能否整除2來確定。如果能整除2,這個數是偶數,否則就是奇數。在Objective-C語言中,可以使用模運算符“%”來計算兩個整數相除所得的余數。在編程中可以使用模運算符“%”來迚行除法判斷,如果某個數除以2所得的余數為0,它就是偶數,否則就是奇數。

執行上述代碼后會輸出:

        輸入一個數字進行測試:
        5
        ji

在上述代碼中,當輸入一個數后,計算此數除以2所得的余數。第一條if語句測試了這個余數的值,檢驗它是否等于0。如果等于0,將顯示消息“ou”。第二條if語句測試余數,檢驗它是否不等于0,如果不等于0,就會顯示一條消息聲明這個數是奇數。

若第一條if語句成功,則第二條if語句肯定失敗。如果一個數能被2整除,它就是偶數,否則就是奇數。在編寫程序時,會多次使用“否則”這一概念。在Objective-C語言中,這通常稱為if-else結構。

其實if-else僅僅是if語句一般格式的一種擴展形式。如果表達式的計算結果是TRUE,將執行之后的statement 1;否則將執行statement 2。在任何情況下,都會執行statement 1或statement 2兩者中的一個,而不是兩個都執行。

例如下面的實例代碼中,可以將if-else語句用在上面的程序中。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int number_to_test, remainder;
                NSLog (@"Enter your number to be tested:");
                scanf ("%i", &number_to_test);
                remainder = number_to_test % 2;
                if ( remainder == 0 )
                      NSLog (@"ou.");
                else
                      NSLog (@"ji.");
              }
              return 0;
        }

在上述代碼中,使用單個if-else語句替換程序中的兩個if語句。此時看到,使用這種新的程序語句有助于減少程序的復雜性,同時又提高了程序的可讀性。執行上述代碼后會輸出:

        Enter your number to be tested:
        1234
        ou.

4.2.3 復合條件測試

在Objective-C開發應用中,if語句判定表達式的形式不可能總是類似于“remainder == 0”的簡單格式。在接下來的內容中,將講解復合條件測試的內容。復合條件測試的功能是用邏輯與或者邏輯或運算符連接起來形成一個或多個簡單條件測試。這兩個運算符分別用字符對“&&”和“||”來表示。

復合運算符可用于形成極其復雜的表達式,這樣大大提高了程序員在構成表達式時的靈活性,但是此時需要注意謹慎使用這種靈活性。通常比較簡單的表達式閱讀和調試會更容易一些,所以可以大量地使用圓括號來提高表達式的可讀性。這樣做的主要優點是避免由于錯誤假設表達式中的運算符優先級而陷入麻煩之中,與任何算術運算符或關系運算符相比,“&&”運算符優先級更低,但比“||”運算符的優先級要高。同時在表達式中還應該使用空格來加強表達式的可讀性。

請讀者看下面的代碼。

        if ( grade >=60 && grade <= 69 )
            ++grades_60_to_69;

上述代碼的功能是,只有在grade的值大于等于60幵且小于等于69時,才將grade_60_to_69的值加1。同樣使用類似的方式,再看下面的代碼。

        if ( index < 0 || index > 100 )
          NSLog (@"Error - index out of range");

在上述代碼中,當index小于0或大于100時會執行NSLog語句。

假如我們需要編寫一個程序來測試某個年份是不是閏年。眾所周知,如果某個年份能被4整除,它就是閏年。但是能被100整除的年份幵不是閏年,除非它能同時被400整除。根據上述對閏年的描述,基本算法思路如下所示。

(1)計算某個年份除以4、100和400所得的余數,幵將這些值分別賦值給名稱合適的變量,如rem_4、rem_100和rem_400。

(2)繼續測試這些余數,以確定是否滿足閏年的標準。

如果重新表達上述對閏年的定義,可以將閏年表示為:如果某個年份能被4整除但不能被100整除或某個年份能被400整除,這一年就是閏年。

根據上述思路,編寫判斷是否閏年的代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int year, rem_4, rem_100, rem_400;
                NSLog (@"輸入一個年份: ");
                scanf ("%i", &year);
                rem_4 = year % 4;
                rem_100 = year % 100;
                rem_400 = year % 400;
                if ( (rem_4 == 0 && rem_100 ! = 0) || rem_400 == 0 )
                      NSLog (@"是閏年.");
                else
                      NSLog (@"不是閏年.");
              }
              return 0;
        }

接下來開始測試運行效果,分別輸入了3個年份迚行測試,輸入第1個年份,執行后輸出:

        輸入一個年份:
        1955
        不是閏年.

輸入第2個年份,執行后輸出:

        輸入一個年份:
        2000
        是閏年.

輸入第3個年份,執行后輸出:

        輸入一個年份:
        1800
        不是閏年.

在上述測試中輸入了3個年份,第一個不是閏年(1955),因為它不能被4整除;第二個是閏年(2000),因為它能被400整除;第三個不是閏年(1800),因為它雖然能被100整除但不能被400整除。要使測試用例完整,還應該檢驗能被4整除但不能被100整除的年份是否是閏年。

在上述代碼中,可以不必計算中間結果rem_4、rem_100和rem_400,而是直接在if語句中迚行了計算,實現代碼如下所示。

        if ( ( year % 4 == 0 && year % 100 ! = 0 ) || year % 400 == 0 )

通過在各種運算符之間添加空格,增強了上述表達式的可讀性。如果決定不添加空格幵刪除非必需的圓括號,將會獲得以下表達式。

        if(year%4==0&&year%100! =0)||year%400==0)

可以使用條件運算符來代替簡單的if語句。條件運算符的格式如下所示。

        表達式1? 表達式2:表達式3

條件運算符的運算規則為:如果表達式1的值為真,則以表達式2的值作為條件表達式的值,否則以表達式3的值作為整個條件表達式的值。條件表達式通常被用于賦值語句之中。條件表達式的執行流程如圖4-6所示。

圖4-6 條件運算符

4.2.4 if語句的嵌套

在使用if語句的一般格式時,如果圓括號中表達式的求值結果是TRUE,則執行后面的語句。如果這條程序語句是另外一條if語句,也是完全合法的,例如下面的代碼。

        if ( [Gamez isOver] == NO )
            if ( [Gamez whoseTurn] == YOU )
                [Gamez your];

如果向Gamez發送的isOver消息所返回的值為NO,將執行隨后的語句,它是另一條if語句。這條if語句會比較從Gamez返回的值與YOU。如果這兩個值相等,將向Gamez對象發送yourMove消息。所以只有在兩邊的對弈都未結束且輪到您移動棋子時,才發送yourMove消息。事實上,使用復合關系可以將這條語句等價地表示為如下形式。

        if ( [Gamez isOver] == NO && [Gamez whoseTurn] == YOU )
          [Gamez your];

在使用Objective-C的if語句時,為了解決比較復雜的問題,有時需要對if語句迚行嵌套使用。幵且嵌套的位置可以固定在else分支下,在每一層的else分支下嵌套另外一個if-else語句。在嵌套的if語句中,經常使用在后面添加else子句的形式,例如下面的代碼。

        if ( [Gamez isOver] == NO )
            if ( [Gamez whoseTurn] == YOU )
                [Gamez your];
            else
                [Gamez my];

很多讀者會有一個疑問:究竟else子句是如何與if語句相對應的呢?也就是說用于測試從whoseTurn方法返回的值的if語句,而不是用于測試對弈是否結束的if語句。else和if的一般對應規則是:else子句通常與最近的不包含else子句的if語句對應。

在下面的實例中,可以根據年齡判斷屬于什么年齡段。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
        @autoreleasepool {
            int age = 45;
            if (age > 20)
            {
                    NSLog(@"青年人");
            }
            else if (age > 40 && ! (age > 20))
            {
                    NSLog(@"中年人");
            }
            else if (age > 60 && ! (age > 20) && ! (age > 40 && ! (age > 20)))
            {
                    NSLog(@"老年人");
            }
          }
        }

我們的目的是,大于20歲是青年人,大于40歲且小于60歲是中年人,大于60歲是老年人。從表面上看,上述代碼沒有任何問題,但是執行上述代碼后將輸出:

        青年人

由此可見,上述代碼出現了錯誤。表面看來在else后面沒有任何條件,或else if后面只有一個條件。但是因為else if的含義是“否則”,其實else本身就是一個條件,else隱含的條件是對前面的條件取反。此時需要將上述程序修改為zhengque.m,具體代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
        @autoreleasepool {
            int age = 45;
            if (age > 60)
            {
                  NSLog(@"老年人");
            }
            else if (age > 40)
            {
                  NSLog(@"中年人");
            }
            else if (age > 20)
            {
                  NSLog(@"青年人");
            }
          }
        }

或修改為zhengque1.m,具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
        @autoreleasepool {
            int age = 45;
            if (age > 60)
            {
                  NSLog(@"老年人");
            }
            else if (age > 40 && ! (age >60))
            {
                  NSLog(@"中年人");
            }
            else if (age > 20 && ! (age > 60) && ! (age > 40 && ! (age >60)))
            {
                  NSLog(@"青年人");
            }
        }
        }

此時執行后將輸出:

        中年人

上述格式的含義是:依次判斷表達式的值,當出現某個值為真時,則執行后面對應的語句,然后跳到整個if語句之外繼續執行程序。如果所有的表達式均為假,則執行后續語句。上述語句的執行方式和前面描述相同,如果對弈沒有結束幵且不該你移動棋子,會執行else子句。這將向Gamez發送消息my。如果對弈結束,就會跳過后面整個if語句,包括對應的else子句。其執行過程如圖4-7所示。

圖4-7 嵌套的if-else語句

4.2.5 else if結構

在Objective-C程序中,使用else if結構的語法格式如下所示。

        if ( expression 1 )
            program statement 1
        else
            if ( expression 2 )
                program statement 2
            else
                program statement 3

上述格式擴展了if語句,能夠實現對3個值的邏輯判定。上述結構通常被稱作else if結構,但是在具體使用時經常與上面格式的不同,例如下面的代碼。

        if ( expression 1 )
          program statement 1
        else if ( expression 2 )
          program statement 2
        else
          program statement 3

上述格式不但提高了代碼的可讀性,而且使執行的3個選擇路線變得更加清晰。例如在下面的實例代碼中,演示了使用else if結構的過程。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>
        int main (int argc, char *argv[])
        {
          NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
          int number, sign;
          NSLog (@"Please type in a number: ");
          scanf ("%i", &number);
          if ( number < 0 )
              sign = -1;
          else if ( number == 0 )
              sign = 0;
          else
              sign = 1;
          NSLog (@"Sign = %i", sign);
            [pool drain];
          return 0;
        }

在上述代碼中,如果輸入的數小于0,將設置sign的值為-1;如果此數等于0,將sign的值設置為0;否則,這個數一定大于0,因此將它設置為1。執行上述代碼后會輸出:

        Please type in a number:
        12
        Sign = 1

請讀者再看下面的實例代碼,可以從終端輸入字符,幵對字母符號(a~z或A~Z)、數字(0~9)或特殊字符(其他任何字符)迚行分類。要從終端讀取單個字符,需要在scanf調用中使用格式字符%c。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                char c;
                NSLog (@"Enter a single character:");
                scanf ("%c", &c);
                if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') )
                    NSLog (@"It's an alphabetic character.");
                else if ( c >= '0' && c <= '9' )
                    NSLog (@"It's a digit.");
                else
                    NSLog (@"It's a special character.");
              }
              return 0;
        }

在上述代碼中,通過讀入字符后構建的第一個測試方式,確定了char變量c是否是字母符號。此功能通過測試該字符是否為小寫字母或大寫字母來完成。根據’c’的不同情況,具體說明如下所示。

?測試的前半部分由表達式“( c >= 'a' && c <= 'z')”組成,如果c位于字符’a’和’z’之間,表達式為TRUE。也就是說,如果c是小寫字母,表達式為TRUE。

?測試的后半部分由表達式“( c >= 'A' && c <= 'Z')”組成,如果c位于字符’A’和’Z’之間,表達式為TRUE;也就是說,如果c是大寫字母,表達式為TRUE。這些測試適用于以ASCII的格式存儲字符的計算機系統。

?如果變量c是字母符號,那么第一個if測試獲得成功,將顯示消息"It's an alphabetic character."。如果測試失敗,將執行else if子句。這個子句確定此字符是否為數字。這個測試將字符c和字符’0'和’9’迚行比較,而不是與整數0和9迚行比較。這是因為字符是從終端讀入的,幵且字符’0’到’9'不同于數字0到9。事實上,在ASCII中,字符’0’在內部實際表示為數字48,字符’1’表示為49,依此類推。

?如果c是數字字符,將顯示短語"It's a digit."。否則,如果c不是字母符號幵且不是數字字符,將執行最后的else子句,幵在終端顯示短語"It's a special character."。然后程序會結束。

在上述代碼中,雖然使用scanf讀取了單個字符,但是在鍵入字符之后仍需按Enter鍵,這樣做的目的是向程序發送輸入。在Objective-C程序中規定:在按下Enter鍵之前,無論何時從終端讀入數據,程序都不會接收到在數據行中輸入的任何數據。

執行上述代碼后,如果輸入“&”則會輸出:

        Enter a single character:
        &
        It's a special character.

如果輸入“9”則會輸出:

        Enter a single character:
        9
        It's a digit.

如果輸入“D”則會輸出:

        Enter a single character:
        D
        It's an alphabetic character.

在下面的代碼中允許用戶使用如下形式輸入簡單的表達式:

        number operator number

通過下面的實例代碼可以計算表達式幵在終端顯示結果,本實例可以識別的運算符是普通的加法、減法、乘法和除法運算符。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        @interface Calculator: NSObject
        {
            double accumulator;
        }
        // 存儲的方法
        -(void)  setAccumulator: (double) value;
        -(void)  clear;
        -(double) accumulator;
        //運算方法
        -(void)  add: (double) value;
        -(void)  subtract: (double) value;
        -(void)  multiply: (double) value;
        -(void)  divide: (double) value;
        @end
        @implementation Calculator
        -(void) setAccumulator: (double) value
        {
            accumulator = value;
        }
        -(void) clear
        {
            accumulator = 0;
        }
        -(double) accumulator
        {
            return accumulator;
        }
        -(void) add: (double) value
        {
            accumulator += value;
        }
        -(void) subtract: (double) value
        {
            accumulator -= value;
        }
        -(void) multiply: (double) value
        {
            accumulator *= value;
        }
        -(void) divide: (double) value
        {
            accumulator /= value;
        }
        @end

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                double       value1, value2;
                char          operator;
                Calculator  *deskCalc = [[Calculator alloc] init];
                NSLog (@"輸入一個表達式.");
                scanf ("%lf %c %lf", &value1, &operator, &value2);
                [deskCalc setAccumulator: value1];
                if ( operator == '+' )
                    [deskCalc add: value2];
                else if ( operator == '-' )
                    [deskCalc subtract: value2];
                else if ( operator == '*' )
                    [deskCalc multiply: value2];
                else if ( operator == '/' )
                    [deskCalc divide: value2];
                NSLog (@"%.2f", [deskCalc accumulator]);
              }
              return 0;
        }

對上述代碼的具體說明如下所示。

(1)首先調用scanf指定讀入變量value1、operator和value2的值。Double的值可以用“%lf”格式字符讀入,而變量value1是表達式的第一個運算數。

(2)接下來開始讀入運算符。因為運算符是字符(+、-、*或/),幵非數字,因此需要將它讀入到字符變量運算符中。“%c”格式字符可以告訴系統從終端讀入下一個字符。格式字符串中的空格表示輸入中允許存在任意個數的空格。這樣在輸入這些值時可以使用空格將運算數和運算符分隔開。

(3)在讀入兩個值和運算符之后,程序將第一個值存儲在計算器的累加器中。然后將operator的值和4個選項比較。如果存在正確的匹配,相應的消息就會發送給計算器來執行運算。在最后一個NSlog中,檢索累加器的值用于顯示。然后程序就會結束。

執行上述代碼后,下面是輸入3種不同類型數據后的輸出情況。

第1種情況會輸出:

        輸入一個表達式.
        123.5 + 59.3
        182.80

第2種情況會輸出:

        輸入一個表達式.
        198.7 / 26
        7.64

第3種情況會輸出:

        輸入一個表達式.
        89.3 * 2.5
        223.25

請讀者再看下面的實例代碼,如下代碼考慮了除以0和輸入未知運算符的情形。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>
        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                  double      value1, value2;
                  char         operator;
                  Calculator *deskCalc = [[Calculator alloc] init];
                  NSLog (@"輸入一個表達式.");
                  scanf ("%lf %c %lf", &value1, &operator, &value2);
                  [deskCalc setAccumulator: value1];
                  if ( operator == '+' )
                      [deskCalc add: value2];
                  else if ( operator == '-' )
                      [deskCalc subtract: value2];
                  else if ( operator == '*' )
                      [deskCalc multiply: value2];
                  else if ( operator == '/' )
                      if ( value2 == 0 )
                            NSLog (@"Division by zero.");
                      else
                            [deskCalc divide: value2];
                  else
                            NSLog (@"Unknown operator.");
                  NSLog (@"%.2f", [deskCalc accumulator]);
              }
              return 0;
        }

執行上述代碼后,下面是輸入3種不同類型數據后的輸出情況。

第1種情況會輸出:

        輸入一個表達式.
        123.5 + 59.3
        182.80

第2種情況會輸出:

        輸入一個表達式.
        198.7 / 0
        Division by zero.
        198.7

第3種情況會輸出:

        輸入一個表達式.
        125 $ 28
        Unknown operator.
        125

當輸入的運算符是斜杠“/”時,如果表示除法,則需要執行另一個測試,以確定value2是否為0。是0則在終端顯示一條適當的消息,否則將執行除法運算幵顯示結果。在這種情況下,要特別注意嵌套的if語句和對應的else子句。

在上述程序結尾的else子句會捕獲所有的失敗,也就是除了前面else if之外的所有情形。因此任何與測試的4個字符不匹配的operator值都會導致執行最后的else子句,幵在終端上顯示“Unknown operator.”的錯誤提示信息。

在Ojective-C程序中,解決除0問題的較好方法是,在計算除法的方法內部執行測試。所以可以將方法divide修改成下面的形式。

        -(void) divide: (double) value
        {
          if (value ! = 0.0)
            accumulator /= value;
          else {
            NSLog (@"Division by zero.");
            accumulator = 99999999.;
          }
        }

如果value不是0則執行除法,否則會顯示消息幵將累加器設置為99999999。累加器可以隨意設置,例如可設置為0,也可以設置成一個特殊值來表示出現錯誤。一般來說,最好讓除法方法本身來處理特殊的情況,而不是依賴程序員另外編寫的其他方法。

4.3 switch語句

知識點講解:光盤:視頻\知識點\第4章\switch語句.mp4

Objective-C程序經常會選擇執行多個分支,多分支選擇結構可在n個操作選擇一個分支執行。實際上前面介紹的的嵌套雙分支語句可以實現多分支結構,在Objective-C語言中,專門提供了一種實現多分支結構的switch語句。本節將詳細講解switch語句的基本知識。

4.3.1 switch語句基礎

在Objective-C程序中,可以使用switch語句實現選擇功能,具體語法格式如下所示。

        switch ( expression )
        {
          case value1:
              program statement
              program statement
                ...
              break;
          case value2:
              program statement
              program statement
                ...
              break;
          ...
          case valuen:
              program statement
              program statement
                ...
              break;
          default:
              program statement
              program statement
                ...
              break;
        }

在上述格式中,括在圓括號中的expression連續地與value1, value2, ……, valuen迚行比較,后者必須是單個常量或常量表達式。如果發現某種情況下某個value的值與expression的值相等,就執行該情況之后的程序語句。當包含多條這樣的程序語句時,不必將它們括在圓括號中。

在Objective-C程序中,break語句表示了一種特定情況的結束,幵導致switch語句的終止。在每種情況的結尾都要包含break語句,如果忘記為特定的情況執行這項操作,只要執行這種情況,程序就會繼續執行下一種情況。如果選擇這樣的方式,必須在此插入注釋以便將我們的目的告知其他程序員或使用人員。

如果expression的值不與任何情況的值匹配,將執行default之后的語句。這在概念上等價于前一個例子中使用的else。其實在Objective-C語言中,switch語句的一般格式可以等價地表示成下面的if語句。

        if ( expression == value1 )
        {
          program statement
          program statement
            ...
        }
        else if ( expression == value2 )
        {
          program statement
          program statement
            ...
        }
          ...
        else if ( expression == valuen )
        {
          program statement
          program statement
            ...
        }
        else
        {
          program statement
          program statement
            ...
        }

在現實應用中,可以將本章實例4-10中的if語句轉換成等價的switch語句。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>
        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                double  value1, value2;
                char     operator;
                Calculator *deskCalc = [[Calculator alloc] init];
                NSLog (@"輸入一個表達式.");
                scanf ("%lf %c %lf", &value1, &operator, &value2);
                [deskCalc setAccumulator: value1];
                switch ( operator ) {
                    case '+':
                        [deskCalc add: value2];
                        break;
                    case '-':
                        [deskCalc subtract: value2];
                        break;
                    case '*':
                        [deskCalc multiply: value2];
                        break;
                    case '/':
                        [deskCalc divide: value2];
                        break;
                    default:
                        NSLog (@"Unknown operator.");
                        break;
                }
                NSLog (@"%.2f", [deskCalc accumulator]);
              }

對上述代碼具體說明如下。

(1)在讀入表達式之后,operator的值會逐一比較每種情況指定的值。當發現一個匹配的值時,會執行包含在這種情況中的語句。

(2)使用break語句終止,switch語句的執行程序也會在此處結束。如果不存在匹配operator值的情況,將執行顯示"Unkown operator. "的default語句。上述代碼中default中的break語句實際上不是必需的,因為這種情況之后的switch中不存在任何語句。然而,記住在每種情況的結尾都包含break語句是一種良好的程序設計習慣。

執行上述代碼后會輸出:

        輸入一個表達式.
        178.99 - 324.8
        -147.81

4.3.2 任何兩種情況的值都不能相同

在編寫Objective-C的switch語句時,應該記住任何兩種情況的值都不能相同,幵且可以將多個情況的值與一組程序語句關聯起來。簡單地在要執行的普通語句之前列出多個情況的值(每種情況中值的前面都使用關鍵字case,而且后面要有一個冒號)就能實現該任務。例如,在下面的switch語句中,如果operator等于星號或是小寫字母x,則執行方法multiply。

        switch ( operator )
        {
          ...
        case '*':
        case 'x':
            [deskCalc multiply: value2];
            break;
          ..
        }

在下面的實例中,根據成績輸出對應的評判結果。

實例文件main.m的具體實現代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, char * argv[])
        {
          @autoreleasepool{
              char score = 'C';  // 聲明變量score,并為其賦值為’C'
              // 執行switch分支語句
              switch (score)
              {
                  case 'A':
                          NSLog(@"優秀.");
                          break;
                  case 'B':
                          NSLog(@"良好.");
                          break;
                  case 'C':
                          NSLog(@"中");
                          break;
                  case 'D':
                          NSLog(@"及格");
                          break;
                  case 'F':
                          NSLog(@"不及格");
                          break;
                  default:
                          NSLog(@"成績輸入錯誤");
              }
          }
        }

執行后將輸出:

上述輸出結果完全正確,因為字符表達式score的值為“C”,對應的結果為“中”。

4.3.3 switch語句小結

Objective-C的switch語句中,每個case可以有多條語句,而不需要一條復合語句。value1, value2, ...必須是整數、字符常量或者值為一個整數的常量表達式。換句話說,在編譯時必須得到一個整數。不允許具有相同的整數值的重復的case。

當執行一條switch語句時會計算expression,幵且將結果與整數case標簽迚行比較。如果找到一個匹配,則執行標簽后面的語句。執行逐一按照順序迚行,直到遇到一條break語句或到達了switch的末尾。break語句會導致執行跳出到 switch之后的第一條語句。

在case后面幵不一定必須有一條break語句。如果省略了break,則執行將跳入到后續的case。如果你看到已有的代碼中省略了break,這可能是一個錯誤(這是很容易犯的錯誤),也可能是有意的(如果程序員想要一個case及其后續的case都執行相同的代碼會這樣做)。

如果integer_expression沒有和任何case標簽匹配,如果有該標簽的話,執行將跳到可選的default標簽后面的語句。如果沒有匹配也沒有default,那么switch什么也不做,它將從switch后面的第一條語句開始繼續執行。

主站蜘蛛池模板: 剑川县| 新邵县| 丹阳市| 丹江口市| 凉城县| 革吉县| 城口县| 封开县| 盐池县| 蒙山县| 金溪县| 新津县| 冕宁县| 丹凤县| 伊春市| 景洪市| 嘉鱼县| 墨玉县| 穆棱市| 延津县| 西充县| 仙桃市| 横峰县| 宜君县| 白河县| 海丰县| 右玉县| 卫辉市| 仙居县| 阿城市| 广南县| 桂东县| 合山市| 仁寿县| 会同县| 翁牛特旗| 名山县| 思南县| 漾濞| 郎溪县| 隆子县|