• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            聚星亭

            吾笨笨且懶散兮 急須改之而奮進
            posts - 74, comments - 166, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

                通過上次課題的講述,相信大家一定對什么是數據及數據的定義和使用方法有一定的了解了,在看本次課題之前希望大家能趁熱打鐵,再到網上下本C語言的教程,最好是買本數來鞏固下變量相關的知識。

             

            大家明白了怎么定義變量,怎么給變量賦值了,自然的就應該進一步了解一下一些詳細的代碼怎么編寫了。

             

            今天我們的任務比較簡單,就講一下如何編寫代碼及實現代碼的流程控制。應該說這個是非常簡單的東西了,本來我沒打算講它,可是本著一步一個腳印的原則,我還是簡要的說一下。在本次課題之后,我會緊跟著出一個函數的專題,來作為代碼篇的完善,至此大家應該能獨立的寫自己的程序了。

             

            本次課題知識點不是很多(也不少,但是都很簡單。),主要是在于多寫,多練,知道自己能把一些現實的問題轉換成代碼來解決問題。

             

                   不多廢話,先說下本次課題要寫的主要內容:

            1. 程序的運算和邏輯判斷
            2. 三種程序流程控制結構詳解。
            3. 養成良好的代碼編寫風格。
            4. 結束語

             

            下面開始進入正題。

            一、           程序的運算和邏輯判斷。

            說計算是電腦最基本的功能,相必沒有人會反對的。做程序,自然最基礎的就是這些運算了。

            我知道,看這個破爛文章的朋友對數據應該都是不感冒的。不過大家放心,這里牽扯的運算都很簡單,就是小學的加、減、成、除、取余數,是、非、與或和位移,沒別的了。先讓我們來了解下算術運算。

            1.         算術運算。

            加減乘除相比大家都應該很了解的。這里我不想費太多的篇幅講述這些大家都明白的知識,我把要說的知識列出來,大家自己了解就好。

             

            用于算術運算的運算符有:

             

            我想不用我說,加、減、成、除這些運算符大家都接觸過的,關于“%”運算符,其實就是取余數;用這些運算符可以將一些數字,變量等連接起來,進行運算,這樣的式子叫做表達式。例如:

            int i =5;

            i +7;     // 這里就是一個表達式。

             

            =”這個運算符其實不屬于算術運算,它也并非是我們數學課上講的“等于”,而是一個“賦值”運算符,它用來將一個常量(數字、字母等)賦值給一個變量的賦值運算符,由于我們進行算術運算以后,通常都會將運算結果保存到一個變量中,所以,我把這個賦值運算符歸類到這里。而我們日常的“等于”運算符是:“= =”,它屬于邏輯運算符,我們將在下一節中講到它。

             

            關于“++ —”這兩個運算符,上圖中已經說明了,它是對變量的對自己的自加或者自減運算,等同于:變量 = 變量+1; 或者 變量 = 變量 1;

             

            現在讓我們來舉幾個例子,來說明下這些算術運算符的用法。

            void  main()

            {

                 int x = 1;

                 int y = 2;

                 int z = 20;

             

                 x ++;         // 等同于x = x + 1;

                 y --;         // 等同于y = y - 1;

             

                 z /= x;       // 等同于z = z / 1;

                 printf("%d, %d, %d\n", x, y, z);    // 打印 x,y,z 的結果。

             

                 z %= x;  // 計算得出 z / x 以后的余數

             

                 x = x+y;

                 z -= x;

                 printf("%d, %d, %d\n", x, y, z);   // 打印 x,y,z 的結果。

            }

             

            請先不要看下面的截圖,先看下這個程序,分析一下,這兩次的輸出結果會是多少,然后對比下圖:

            看下就算的是不是正確,如果正確了,那恭喜你,基礎的算術運算就算通過了,接下來,我們需要調試這段代碼,來熟悉一些相關的匯編命令,具體操作如下圖所示:

            在代碼上右擊鼠標,選擇如下命令:

             

            我們來詳細分析一下我們現在看到的代碼:

            1:    #include "stdio.h"

            2:

            3:    void main()

            4:    {

              00401010   push        ebp

              00401011   mov         ebp,esp   ;// 將現有的堆棧給了EBP寄存器。

              00401013   sub         esp,4Ch   ;// 分配x4C大小的堆棧空間用來運算。

              00401016   push        ebx

              00401017   push        esi

              00401018   push        edi       ;// 保存寄存器環境。

              00401019   lea         edi,[ebp-4Ch] ;// 這里用ebp寄存器減去一個偏移來定位我們定義的變量,

              0040101C   mov         ecx,13h   ;// 這里-4Ch是用來定位到堆棧頭,把堆棧內容改成int3中斷以免內存泄露。

              00401021   mov         eax,0CCCCCCCCh     ;// 以上操作是保存堆棧環境,分配堆棧空間。

              00401026   rep stos    dword ptr [edi]    ;// 在下一次課題講述函數時,我們會講到,這里大家可以略過。

            5:        int x = 1;

              00401028   mov    dword ptr [ebp-4],1;// [ebp-4]是我們的變量xdword ptr是用來修飾這個變量是DWORD類型(也就是整型)。

            6:        int y = 2;

              0040102F   mov         dword ptr [ebp-8],2;// MOV就是匯編指令,相當于我們C語言中"=" 賦值運算符,它的具體用法自己百度。

            7:        int z = 20;

              00401036   mov         dword ptr [ebp-0Ch],14h

            8:

            9:        x ++;       // 等同于x = x + 1;

              0040103D   mov         eax,dword ptr [ebp-4]

              00401040   add         eax,1; // add指令就是我們C語言的"+"運算符,還有一個INC指令相當于我們的"++"運算符

              00401043   mov         dword ptr [ebp-4],eax

            10:       y --;       // 等同于y = y - 1;

              00401046   mov         ecx,dword ptr [ebp-8]

              00401049   sub         ecx,1

              0040104C   mov         dword ptr [ebp-8],ecx

            11:

            12:       z /= x;     // 等同于z = z / 1;

              0040104F   mov         eax,dword ptr [ebp-0Ch]

              00401052   cdq

              00401053   idiv        eax,dword ptr [ebp-4]

              00401056   mov         dword ptr [ebp-0Ch],eax

            13:       printf("%d, %d, %d\n", x, y, z);

              00401059   mov         edx,dword ptr [ebp-0Ch]

              0040105C   push        edx

              0040105D   mov         eax,dword ptr [ebp-8]

              00401060   push        eax

              00401061   mov         ecx,dword ptr [ebp-4]

              00401064   push        ecx

              00401065   push        offset string "%d, %d, %d\n" (0042001c)   // 傳遞參數,具體規則將在下次課題“函數”中講述。

              0040106A   call        printf (004010f0)       ; // 調用printf函數打印結果

              0040106F   add         esp,10h       ; // 這里是C條用的對戰平衡方式。(具體將在下次課題“函數”中講述)

            14:

            15:       z %= x;

              00401072   mov         eax,dword ptr [ebp-0Ch]

              00401075   cdq

              00401076   idiv        eax,dword ptr [ebp-4]

              00401079   mov         dword ptr [ebp-0Ch],edx

            16:

            17:       x = x+y;

              0040107C   mov         edx,dword ptr [ebp-4]

              0040107F   add         edx,dword ptr [ebp-8]

              00401082   mov         dword ptr [ebp-4],edx

            18:       z -= x;

              00401085   mov         eax,dword ptr [ebp-0Ch]

              00401088   sub         eax,dword ptr [ebp-4]

              0040108B   mov         dword ptr [ebp-0Ch],eax

            19:       printf("%d, %d, %d\n", x, y, z);

              0040108E   mov         ecx,dword ptr [ebp-0Ch]

              00401091   push        ecx

              00401092   mov         edx,dword ptr [ebp-8]

              00401095   push        edx

              00401096   mov         eax,dword ptr [ebp-4]

              00401099   push        eax

              0040109A   push        offset string "%d, %d, %d\n" (0042001c)

              0040109F   call        printf (004010f0)

              004010A4   add         esp,10h

            20:   }

              004010A7   pop         edi                     ; // 恢復寄存器環境

              004010A8   pop         esi

              004010A9   pop         ebx

              004010AA   add         esp,4Ch                 ; // 平衡堆棧

              004010AD   cmp         ebp,esp

              004010AF   call        __chkesp (00401170)     ; // DEBUG 模式程序專用的堆棧檢查函數。

              004010B4   mov         esp,ebp

              004010B6   pop         ebp

            004010B7   ret

             

            相信你根據上述代碼中的提示,應該能將這個匯編代碼看的差不多,當然,看不明白也沒有關系,我們需要掌握的匯編指令及其用法很少,就下面幾個:

                   mov/lea:         賦值/取地址。

                   add:               加法指令。

                   sub:               減法指令。

                   div/idiv:          除法指令。

                   mul/imul:        乘法指令。

            這些匯編指令的具體用法大家自己百度或者參考相關資料,這里不做詳細說明, 下面開始我們的邏輯、關系運算。

            2.         邏輯、關系運算。

            提起什么邏輯運算,或者什么關系運算,看名字貌似很復雜的。不過這里可能讓大家放心的是,這些運算我們日常生活中經常用到,無非就是 真的,假的,是,不是,并且,或者之類的操作。

             

            用于邏輯運算的運算符有如下幾個:

            運算符

            含義

            &&

             與(并且)

            ||

            或(或者)

            !

            非(不是)

                         

                                 用于關系運算的運算符有如下幾個:

                                

            這些運算無非就是為了判斷一個表達式成立不成立,在C語言中,只要表達式的值不為零并且符合關系運算符的要求,那這個表達式就成立的,就可以用上述的兩種運算符進行比較運算,一般情況下,這些運算符會配合下節我們要講述的流程控制語句來使用,所以這里我就不給出具體用法的例子了,有情趣的朋友,可以繼續看下面章節中的例子

             

            到現在我想主要的運算我都講完了,雖然不是很詳細,但是我想,只要大家堅持努力,多多百度,這些知識一定會掌握好的。

             

            小學的時候,我們學過四則運算,在運算的時候,遵循先乘除,后加減,有括弧的先算括弧里面的,這個規則在這里一樣使用,只不過在編程環境中,運算符很多,所以需要有個更為詳細的運算符優先級表。這里我把它貼出來,但是還希望大家能夠盡量的使用括弧來讓人看的容易,以免出錯,具體優先級表轉載如下:

            更詳細的用法可以參考如下鏈接:http://www.xxlinux.com/linux/article/development/soft/20060909/4128.html

            二、           三種程序流程控制結構詳解。

            有了上述的運算,我想大家都可以寫出一些很簡單的代碼了,但是我們在寫代碼的時候,肯定會遇到類似這樣的問題:

            Ø         有時候,我們寫的代碼必須要在達到某種條件之后才可以執行,否則不讓運行。

            Ø         有時候,我們寫的代碼很龐大,很羅嗦,因為它有幾種可能需要我們來寫出幾個程序。

            Ø         有時候,我們寫的代碼需要一直重復執行直到某種條件不成立了才不執行。

             

            只要你遇到過上述的問題,那我們這節課的內容就正是你所需要的。不多廢話,進入正題:

            1.         順序結構

            到現在為止,我們寫的所有的代碼都是順序結構的,所謂順序結構,就是代碼從第一條指令開始執行,直到執行完最后一條。中間不會落下任何一條指令。

             

            想必大家現在應該能理解什么是順序結構了,所以我不想再這里浪費太多的篇幅,直接進入下一小節。

            2.         分支結構

            所謂分支結構,就是代碼在達到某種條件的時候,執行某些指令,否則就執行別的指令。

            分支結構是改變代碼執行順序最簡單的方式,所以大家一定可以很容易的掌握它的,下面讓我們一個一個的來看。

            a)        if … else結構

            這個結構算是編程中最基礎的結構了,它有三種格式,我在這里列出來,大家可以根據實際情況選擇使用哪個:

            第一種格式:

            if (條件表達式)

            {   

                 //條件成立時執行這里的語句

                

            }

            第二種格式:

            if (條件表達式)

            {   

                 //條件成立時執行這里的語句

                

            }

            else

            {

                 //條件不成立時執行這里的語句

                

            }

            第三種格式:

            if (條件表達式1)    

            {

                 //條件表達式1成立時執行這里的語句

                

            }                   

            else if (條件表達式2)  // 這里的else if可以有無限多個(如果有很多個時可以參考使用switch語句)。

            { 

                 //條件表達式2成立時執行這里的語句

                

            }                   

            else                

            {

                 //條件表達式都不成立時執行這里的語句

                

            }   

             

                                        為了更好的說明這個語句的用法,我舉個例子:

            int MaxNum(int num001,  int num002,  int num003)

            {

                 if (num001 >= num002)

                 {

                     if (num001 >= num003)

                     {

                          return num001;         // num001 作為函數的結果返回出來。

                     }

                     else

                     {

                          return num003;

                     }

                 }

                 else

                 {

                     if (num002 >= num003)

                     {

                          return num002;

                     }

                     else

                     {

                          return num003;

                     }

                 }

            }

                                 說明:上述代碼中的功能是從提供的三個數:num001num002num003中選出最大的數來。

            至于與這些if有關的匯編指令就是跳轉,像subcmptest,之類的比較指令來影響相應的標志寄存器還有JE,JNE,JB,JNB之類的跳轉指令來跳轉到指定的代碼中執行,大家可以像我們分析算術運算的方式一樣,去調試它,去分析它,去掌握這些比較和跳轉指令的用法。

             

            這里我就省下篇幅,繼續我們的switch結構。

            b)        switch … 結構

            上小節中講述的if語句,是用于少數分支時的處理語句,它寫起來方便,代碼簡潔明了,但是如果一些表達式的結構可能有5種甚至更多種結果,需要我們分別作出不同的處理時,最好的選擇就是用wsitch語句。      

            先說明一下switch結構的語法格式:

            switch(表達式結果或者存放結果的變量)

            {

            case  結果1:

                 // switch后的括弧中的值是結果時,就執行這里的語句

                 ...;

                 break;   // break是用來跳出分支結構的關鍵字,如果這里沒有它,只要結果是結果1,那從結果1開始向下的所有指令都會被執行(包括結果2,結果3……)。

             

            case  結果2:

                 // switch后的括弧中的值是結果時,就執行這里的語句

                 ...;

                 break;   // 如果這里沒有這個關鍵字時,只要上面的結果是結果2,那從結果2開始向下的所有指令都會被執行(包括結果3,結果4……)。

             

            case  結果3:

                 // switch后的括弧中的值是結果時,就執行這里的語句

                 ...;

                 break;   // 同上

             

            case  結果N:

                 // switch后的括弧中的值是結果N時,就執行這里的語句

                 ...;

                 break;  

             

            default:

                 // switch后的括弧中的值不是上面列出的任何一個值時,就執行這里的語句

                 ...;

            }

             

                                 這里寫的可能有點模糊,我給出一個代碼片段,我說明一下switch語句的用法:

            PGAME_CHAR_INFO pGCI = GetCharInfoPoint();

            switch (pGCI->dwZhiYe)

            {

            case 1:

                 lstrcpyW(szTemp, L"靈劍\0");

                 break;

            case 2:

                 lstrcpyW(szTemp, L"日羽\0");

                 break;

            case 3:

                 lstrcpyW(szTemp, L"槍俠\0");

                 break;

            case 4:

                 lstrcpyW(szTemp, L"薩滿\0");

                 break;

            case 5:

                 lstrcpyW(szTemp, L"法皇\0");

                 break;

            case 6:

                 lstrcpyW(szTemp, L"藥王\0");

                 break;

            default:

                 lstrcpyW(szTemp, L"未知\0");

                 break;

            }

             

            其實,這個switch的匯編形式跟if結構很像,唯一的區別就是每個分支后面都會有一個break跳轉(JMP)指令,大家可以自己試著去調試這段代碼,分析一下盡量掌握這些代碼的匯編形式。

            3.         循環結構

            所謂循環結構,就是一直重復執行某段指定的語句,知道條件不滿足了為止。

            a)        for循環結構

            好,按照我們的習慣,我先寫出這個語句的基本語法結構:

            for (初始值; 滿足條件; 增量)

            {

                 要循環的語句;

            }

                                        例如下面的代碼:

            #include "stdio.h"

             

            void main()

            {

                 int i = 10;

                

                 // 循環打印輸出0到之間的所有自然數。

                 for (int x = 0; x < i; x++)

                 {

                     printf("%d\n", x);

                 }

            }

                                        打印結果如下:


                                        通過這個結果和上面的語法結構,我們可以猜測出for語句的執行流程如下圖所示:

             

            左圖中描述了for語句的執行流程,先從上面的語句中執行到for關鍵字,然后開始初始化操作,在判斷一下循環的條件是否滿足:

             

                   如果條件滿足,則繼續按照綠色的箭頭執行,開始執行要循環的語句,執行完以后,會來到增量(或叫 步長)這個語句對計數器(記錄循環次數的變量)進行增加,然后在去判斷是否滿足循環條件,如果滿足繼續執行要循環的語句,如此循環。

             

            直到條件不滿足了,按照紫色箭頭所示,跳出循環繼續執行后面的語句。

             

                   現在讓我們來調試跟蹤一下上面的那段程序, 確切的體會下電腦是如何執行循環語句的:

            1:    #include "stdio.h"

            2:

            3:    void main()

            4:    {

                 00401010   push        ebp

                 00401011   mov         ebp,esp

                 00401013   sub         esp,48h

                 00401016   push        ebx

                 00401017   push        esi

                 00401018   push        edi

                 00401019   lea         edi,[ebp-48h]

                 0040101C   mov         ecx,12h

                 00401021   mov         eax,0CCCCCCCCh

                 00401026   rep stos    dword ptr [edi]

            5:        int i = 10;

                 00401028   mov         dword ptr [ebp-4],0Ah   ; // 初始化變量i

            6:

            7:        // 循環打印輸出0到之間的所有自然數。

            8:        for (int x = 0; x < i; x++)

                     0040102F   mov         dword ptr [ebp-8],0     ; // 初始化x變量

                     00401036   jmp         main+31h (00401041)     ; // 強制跳到1041 這個位置

                     00401038   mov         eax,dword ptr [ebp-8]

                     0040103B   add         eax,1                       ; // 自變量加一,繼續判斷比較

                     0040103E   mov         dword ptr [ebp-8],eax

                     00401041   mov         ecx,dword ptr [ebp-8]   ; // 開始比較ix兩個變量

                     00401044   cmp         ecx,dword ptr [ebp-4]

                     00401047   jge         main+4Ch (0040105c); // 如果ebp-8得值(也就是x的值)大于等于i的值則跳出循環

            9:        {

            10:           printf("%d\n", x);

                     00401049   mov         edx,dword ptr [ebp-8]

                     0040104C   push        edx

                     0040104D   push        offset string "%d\n" (0042001c)

                     00401052   call        printf (00401090)       ; // 打印變量

                     00401057   add         esp,8

            11:       }

                     0040105A   jmp         main+28h (00401038)         ; // 調回去,累加器加一,然后繼續循環

            12:   }

                 0040105C   pop         edi           ; // 退出循環,恢復上下文環境。

                 0040105D   pop         esi

                 0040105E   pop         ebx

                 0040105F   add         esp,48h       ; // 平衡堆棧。

                 00401062   cmp         ebp,esp

                 00401064   call        __chkesp (00401110)

                 00401069   mov         esp,ebp

                 0040106B   pop         ebp

                 0040106C   ret

            好,到這里相信大家對for循環已經明白了,其實那個語法結構中的什么初始化,什么增量,無所謂的,只要明白了它的執行順序,然后寫上相應的代碼就可以了,接下來就是多多使用它,熟練它就好。

            b)        while循環結構

            for循環相比,while有很多的優點,當然它也簡單的一塌糊涂。我直截了當的說下這個while語句的兩種寫法和它們之間的區別:

                

            按照 for 語句中圖的分析方法,可以看出while的兩種寫法都比較容易,它們的區別也很明顯,一個先判斷下是否應該循環,另一個就不管三七二十一,先執行一遍循環體再說……

             

                   這個while語句比較容易,而且與for可以兼容,所以這里我就不再浪費篇幅去分析它了。大家如果有想去可以自己分析一下,看下它們的匯編模樣。

             

                   到這里,我們這一小節的所有知識點都已經說完了,希望大家能靈活運用它們,根據實際情況,它們之間是可以嵌套的,比如if語句中使用for語句,for語句中使用一個switch語句,等等。

            三、           養成良好的代碼編寫風格。

            引用一下高質量C++/C編程指南:http://man.chinaunix.net/develop/c&c++/c/c.htm(只看能看懂的部分)

            四、           結束語

            通過本次專題的學習,我相信大家可以寫一個很基礎的代碼了,再配合我們下節課要講述的內容,我們的基礎部分就要結束了。

             

            多寫程序,多看人家的程序,多作一些C語言的作業,靈活一下。

             

            Feedback

            # re: 2、數據的存儲空間 ------ 變量  回復  更多評論   

            2009-04-17 19:26 by wahaha
            講的很不錯,希望繼續,關注ING。。。

            # re: 2、數據的存儲空間 ------ 變量  回復  更多評論   

            2009-06-03 20:49 by cntrump
            好像不通用吧,我在VC6下編譯通過,運行時程序崩潰

            # re: 2、數據的存儲空間 ------ 變量  回復  更多評論   

            2009-06-09 13:53 by bester
            @cntrump
            release 編譯運行就應該OK了。

            # re: 2、數據的存儲空間 ------ 變量  回復  更多評論   

            2009-09-08 15:31 by 迷途流浪
            變量聲明格式應該包括:數據存儲方式
            說法要嚴謹
            亚洲欧美日韩中文久久| 免费观看成人久久网免费观看| 久久国产精品99久久久久久老狼| 久久久久久精品久久久久| 久久久噜噜噜久久| 婷婷久久精品国产| 99久久这里只精品国产免费| 久久亚洲av无码精品浪潮| 久久久久无码精品| 久久亚洲色一区二区三区| 国产精品久久久99| 久久精品亚洲男人的天堂| 狠狠人妻久久久久久综合蜜桃| 久久综合九色综合精品| 国产成人香蕉久久久久| 久久免费国产精品| 久久亚洲精品无码aⅴ大香 | 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 91精品国产91久久久久福利| 久久精品人人做人人爽电影蜜月| 九九精品99久久久香蕉| 亚洲国产成人久久精品影视| 精品免费久久久久国产一区| 亚洲国产精品成人AV无码久久综合影院 | 久久99精品国产麻豆宅宅| 久久久久亚洲av无码专区 | 亚洲国产精品久久久久网站| 久久国产视屏| 精品国产99久久久久久麻豆| 久久精品国产亚洲AV电影| 久久99久久99小草精品免视看| 激情五月综合综合久久69| 亚洲天堂久久久| 国内精品久久国产大陆| 99久久综合狠狠综合久久| 色播久久人人爽人人爽人人片AV| 久久精品无码午夜福利理论片| 韩国三级中文字幕hd久久精品| 久久亚洲AV成人无码| 久久久久久a亚洲欧洲aⅴ| 伊人久久大香线蕉精品不卡 |