C程序設計學習筆記(完結)


 

時間:2015-4-16 09:17

 

不求甚解,每有會意,欣然忘食。
學習的過程是痛苦的

 

第1章    程序設計和C語言 
    
第2章    算法——程序的靈魂
   —算法的五個特點
            有窮性    確定性    有零個或多個輸入    有一個或多個輸出    有效性
   —程序的三種基本結構
           順序結構    
           選擇結構    
                if 語句
                switch 語句
            循環結構
                while 循環
                for 循環
                until 循環(就是do ... while循環)
    —偽代碼
            偽代碼是介於自然語言和計算機語言之間的文字和符號來描述算法。它如同一篇文章一樣,自上而下地寫下來。
            每一行表示一個基本操作。
    —結構化程序設計
            自頂向下    逐步細化    模塊化設計    結構化編碼
第3章    最簡單的程序設計——順序程序設計
  —數據的表現形式及其運算
            常量和變量
                常量
                    整型常量
                        正數 000 123 0 -18
                    實型常量
                        有兩種表示形式
                            1、十進制小數形式    2.5 0.0 
                            2、指數形式    由於在計算機輸入或輸出時,無法表示上角或下角,故規定以字母e或E代表以10為底的指數。
                                    注意:e或E之前必須有數字,且e或E后面必須為正數,不能寫為e5、1e2.5
                    字符常量
                        1、普通字符
                                用單括號括起來的一個字符,例如 ‘a’、‘1’、‘#’
                        2、轉義字符
                                \'     一個單撇號(‘)    具有此八進制碼的字符
                                \"    一個雙撇號(“)    輸出此字符
                                \?   一個問號(?)       輸出此字符
                                \\    一個反斜線(\)    輸出此字符
                                \a   警告 alert               產生聲音或視覺信號
                                \b   退格 backspace    將當前位置后退一個字符
                                \f    換頁 form feed      將當前位置移到下一頁的開頭
                                \n   換行 line feed        將當前位置移到下一行的開頭
                                \r    回車 carriage return    將當前位置移到本行的開頭(起源於早期打字機,每打完一行先到行首再換行)
                                \t    水平制表符            將當前位置移到下一個tab位置
                                \v   垂直制表符            將當前位置移到下一個垂直指標對齊點
                                \o、\oo或\ooo             其中一個o代表一個八進制數字
                                    輸出與該八進制碼對應的ASCII字符,例如'\101'的八進制數101的ASCII字符,即'A(八進制數101相當於
                                    十進制數65),'\012'代表八進制數12(即十進制數10)的ASCII碼所對應的字符”換行“符。
                                \xh[h...]                        其中一個h代表一個十六進制數字
                                    輸出與該十六進制碼對應的ASCII字符

                    字符串常量
                    符號常量(宏定義)
                        # define    PI    3.1415
                        符號常量的優點:含義清晰    一改全改
                        注意:要區分符號常量和變量,不要把符號常量誤認為變量,符號常量不占內存,只是一個臨時符號,在預編譯
                                   之后這個符號就不存在了,故不能對符號常量賦以新值。
                變量
                    變量代表一個有名字的,具有特定屬性的一個存儲單元。它用來存放數據,也就是存放變量的值,在程序運行期間,
                    它的值是可以改變的。變量名實際上是以一個名字代表一個存儲地址。
                常變量
                    const int max = 0;  表示max被定義為一個整型變量,在變量存在期間其值不能改變。
                    改變max的值:const int max = 1;
                            # include <stdio.h>
                            
                            int main(void)
                            {
                               const int max = 10;
                            int a = 20;
                            printf("a = %d\n",a);        //輸出a的值為20;
                            a = max;
                            printf("a = %d\n",a);        //輸出a的值為10.
                            
                            return 0;
                            }

    —數據類型
            所謂類型,就是對數據分配存儲單元的安排,包括存儲單元的長度(所占字節)以及數據的存儲形式。
       純量類型:算術類型和指針類型,因為其變量的值是以數字來表示的。
       算術類型:其中基本類型(包括浮點型和整型)和枚舉類型變量的值都是數值,統稱為算術類型。
            整型類型:
                基本整型 int    短整型 short int    長整型 long int     字符型 char
            浮點類型:單精度浮點型 float    雙精度浮點型 double
            枚舉類型 enum  枚舉類型是程序中用戶定義的證書類型。
            指針類型 *
        組合類型:數組類型和結構體類型統稱為組合類型。(共用體(聯合體)類型不屬於組合類型,因為在同一時間內只有一個成員
                             具有值。)
            數組類型 [ ]
            結構體類型 struct
        空類型 void
            void指針的意義(所有的指針都是4個字節)
            C語言規定只有相同類型的指針才可以相互賦值。
            void * 指針作為左值用於“接收”任意類型的指針:
                    void * p = &p1;
            void * 指針作為右值賦值給其他指針時需要強制類型轉換。
                    int * p1 = NULL;
                    char * p2 = ((char *)malloc(sizeof(char) * 20);
            因為malloc函數的返回值是void *類型,所以前面需要用 char * 來進行強制類型轉換。
            不存在void類型的變量。
    —整型數據
            基本整形int
                在存儲單元中的存儲方式是:用正數的補碼形式存放。一個正數的補碼是此數的二進制形式。
                負數求補碼:先將此數的絕對值寫成二進制形式,然后將所有二進制位取反再+1。

                    5的原碼    00000000|00000101
                    按位取反    11111111|11111010
                    再+1(-5的原碼)    11111111|11111011
                在存放正數的存儲單元中,最左面一位是用來表示符號的,0為正,1為負。
                    二進制最大值 01111111 | 11111111  = 十進制 32767
                    二進制最小值 10000000 |  00000000 = 十進制 -32768
                    因此,一個兩個字節的整型變量的值的范圍是 -32768~32767 
                    signed int 有符號基本整型
                    unsigned int 無符號基本整型
                    因為 unsigned int 二進制無符號位,所以范圍增大一倍。
                說明:1)只有整型(包括字符型)數據可以加 signed 或 unsigned 修飾符,實型數據不能加。
                           2)對無符號整型數據用”%u“格式輸出,”%u“表示無符號十進制數的格式輸出。
                           3)在將一個變量定義為無符號整型后,不能賦予一個負值。 
    —字符型數據
        字符與字符代碼
            字符是按其代碼(整數)形式存儲的。
            各種字符集(包括ASCII字符集)的基本集都包括了127個字符,其中包括:
                · 字母:大寫英文字母A~Z,小寫英文字母a~z。
                · 數字:0~9。
                · 專門符號,29個: ! " # & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ ` { | } ~
                · 空格符:空格、水平制表符(tab)、垂直制表符、換行(line feed)、換頁(form feed)。
                · 不能顯示的字符:空字符(null,以'\0'表示)、警告(以'\a'表示)、退格(以'\b'表示)、回車(以'\r'表示)等。
            可以看到,以上的字符的ASCII代號碼最多用7個二進制位就可以表示。所有127個字符都可以用7個二進制位表示
            (ASCII代碼為127時,二進制形式為1111111,7位全都是1)。所以在C中,制定一個字節(8位)存儲一個字符,
            此時,字節中的第1位置為0。
        字符變量
            字符變量,實際上是一個字節的整型變量,由於它常用來存放字符,所以成為字符變量,可以把0~127之間的整數賦給一個
            字符變量。
                # include <stdio.h>
                int main (void)
                {
                     char a = 65;
                     printf("%c\n",a);
                     return 0;
                }
                運行結果:  A
                                    press anykey to continue
                                                        字符型數據的存儲空間和值的范圍
    ———————————————————————————————————————
    |                        類型                              |    字節數    |                    取值范圍                   |
    ———————————————————————————————————————
    |            signed char 有符號字符型        |        1        |        -128~127,即2^7~2^7-1        |
    ———————————————————————————————————————
    |        unsigned char 無符號字符型        |        1        |        0~255,即0~2^8-1                 |
    ———————————————————————————————————————
    說明:在使用有符號字符型變量時,允許存儲的值為-127~127,單字符的代碼不可能為負值,所以在存儲字符時實際上只用到
               0~127這一部分,其第1位都是0。
                如果將一個負整數賦給有符號字符型變量是合法的,但它不代表一個字符,而作為一字節整型變量存儲負整數。
    附注:前面已介紹,127個基本字符用7個而僅為存儲,如果系統只提供127個字符,那么就將char型變量的第一個二進位設為0,
               用后面的7位存放0到127個字符的代碼。在這種情況下,系統提供的char類型詳單與 signed char。但是在實際應用中,
               往往覺得127個字符不夠用,希望能多提供一些可用的字符。根據此需要,有的系統提供了擴展的字符集,把可用的字符由
               127個擴展為255個即擴大了一倍。就是把本來不用的第一位用起來,把char變量改為 unsigned char,即第一位並不固定
                設為0,而是把8位都用來存放字符代碼。這樣,可以存放255個字符代碼,但它並不適用於所有的系統。
    —浮點型數據
        浮點型數據是用來表示具有小數點的實數的。
    float型 單精度浮點型
        float占4個字節,能得到6位有效數字。
    double型 雙精度浮點型
        double占8個字節,能得到15位有效數字。
       (在C語言中進行浮點數的算術運算時,將float型數據自動轉換成double型,再進行運算)
    long double型 長雙精度浮點型
        long double占16個字節,能得到19位有效數字。
    —怎樣確定常量的類型
            整型常量
                在一個整數的末尾加大寫字母L或小寫字母l,表示它是常整型。
            浮點型常量
                從編譯系統把浮點型常量都按雙精度處理,分配8個字節,例如:
                    float a = 3.14159;
                    在進行編譯時,對float變量分配4個字節,但對於浮點型常量3.14159,按雙精度處理,分配8個字節。
                    以上程序會損失精度,但是可以用以下方法來強制指定常量的類型:
                        float a = 3.14159f;                    //把此3.14159按單精度浮點型常量處理,編譯時不出現警告。
                        long double a = 1.23L;             //把此1.23作為long double處理
    —運算符和表達式
            算術運算符 
                + - * / %
                /   兩個實數相除的結果是雙精度實數,兩個整數相除的結果是整數,5/3=1,舍去小數部分,
                    但是如果除數或被除數中有一個為負值,則舍入的方向是不固定的。
                % %運算符要求參加運算的對象(即操作數)為整數,結果也是整數。如8%3 = 2。
                除 % 以外的運算符的操作數可以是任何算術類型。
            自增自減
                ++i;--i;  (在使用i之前,先使i的值+1或-1)
                i++;i--;  (在使用i之后,再使i的值+1或-1)
                注意:自增運算符和自減運算符只能用於變量,而不能用於常量或表達式。
                自增運算符常用於循環語句中,使循環變量自動+1;也用於指針變量,使指針指向下一個地址。
            算術表達式和運算符的優先級與結合性
                自右至左,即右結合性。
            不同類型數據間的混合運算
                整型、實型、字符型數據之間可以進行混合運算:
                    1、+ - * / 運算的兩個數中有一個數位float 或 double 型,結果都是double型,因為系統將所有的float型數據都先轉換為
                        double 型再進行運算。
                    2、如果 int 型和float或double型進行運算,先把int型和float型轉換為double型,再進行運算,結果為double型。
                    3、字符 char型數據與整型數據進行運算,就是把字符的ASCII碼與整型數據進行運算,如果字符型數據與實行數據
                         進行運算,則將字符的ASCII代碼轉換為double型再進行運算。
                一個字符型數據既可以以字符形式輸出,也可以以整數形式(十進制)輸出。
            強制類型轉換運算符
                可以利用強制類型轉換運算符將一個表達式轉換成所需類型。例如:
                    (double) a                 (將a轉換成double類型)
                    (int)(x+y)                   (將 x+y的值轉換成int型)
                    (float)(5%3)              (將5%3的值轉換成float型)
                其一般形式為 (類型名)(表達式)
                需要說明的是,在強制類型轉換時,得到一個所需類型的中間數據,而原來變量的類型未發生變化。例如:
                    a = (int)x
                如果定義x為float型,a為整型變量,進行強制類型運算(int)a之后得到一個int類型的臨時值,它的值等於x 的整數部分,
                把它賦給a,注意x的值和類型都未發生變化,仍為float類型,該臨時值在賦值后就不存在了。另外,在函數調用時,有時
                為了使實參與形參類型一致,可以使用強制類型轉換運算符得到一個所需類型的參數。
            C運算符
                (1)算術運算符                        (+ - * / % ++ --)
                (2)關系運算符                        (> < == >= <= !=)
                (3)邏輯運算符                        (&&  ||  ! )
                (4)位運算符                            (<<  >> ~ | ^ &)
                (5)賦值運算符                        (= 及其擴展賦值運算符)
                (6)條件運算符                        ( ?  :)
                (7)逗號運算符                        ( , )
                (8)指針運算符                        ( *  )
                (9)求字節數運算符                 (sizeof)
                (10)強制類型轉換運算符        ( (類型) )
                (11)成員運算符                      ( .  -  >)
                (12)下標運算符                      ( [ ] )
                (13)其他                                (如函數調用運算符())
        — C 語句
                控制語句
                    1、if()… else    條件語句
                    2、for()…         循環語句
                    3、while()…      循環語句
                    4、do…while()  循環語句
                    5、continue           結束本次循環語句
                    6、break                終止執行switch語句或循環語句
                    7、switch               多分支選擇語句
                    8、return               函數返回語句
                    9、goto                 轉向語句,在結構化程序中基本不用goto語句
                復合的賦值運算符
                    +=   -=
                    賦值運算符左側應該是一個可修改的“左值”,左值的意思是他可以出現在賦值運算符的左側,它的值是可以改變的。
                    並不是任何形式的數據都可以作為左值,變量可以作為左值,而算術表達式 a+b 就不能作為左值,
                    常量也不能作為左值,因為常量不能被賦值。能出現在賦值運算符右側的表達式稱為“右值”,
                    顯然左值也可以出現在賦值運算符的右側,因而凡是左值都可以作為右值。
                賦值過程中的類型轉換
                    如果賦值運算符兩側的類型不一致,但都是算數類型時,在賦值時要進行類型轉換,類型換換是由系統自動進行的,
                    轉換的規則是:
                        1、將浮點型數據(包括單、雙精度)賦給整型變量時,先對浮點數取整,即舍棄小數部分,然后賦予整型變量。
                              如果 i 為整型變量,執行"i=3.56"的結果是使i的值為3,以整數形式存儲在整型變量中。
                        2、將整型數據賦給單、雙精度時,數值不變,但以浮點數形式存儲到變量中。如果有float變量,執行“f=23;”。
                              先將整數23轉換成實數23.0,再按指數形式存儲在變量f中,如果23賦給double型變量 d ,即執行“d = 23;”,
                              則將整數23轉換成雙精度實數23.0,然后以雙精度浮點數形式存儲到變量d中。
                        3、將一個double 型數據賦給float變量時,先將雙精度轉換為單精度,即只取6~7位有效數字,存儲到float變量的4個
                              字節中。應注意雙精度數值的大小不能超出float型變量的數值范圍。
                        4、字符型數據賦給整型變量時,將字符的ASCII碼賦給整形變量。
                        5、將一個占字節多的整型數據賦給一個占字節少的整型變量或字符變量時,只將低字節的數據賦值,即發生截斷。
                賦值語句和賦值表達式
                    在if的條件中可以包含賦值表達式,但不能包含賦值語句。
                            賦值表達式:a = 5
                            賦值語句:a = 5;
                    表達式沒有分號,而賦值語句有分號。
                變量賦初值
                    一般變量初始化不是在編譯階段完成的(只有在靜態存儲變量和外部變量的初始化是在編譯階段完成的),而是在程序
                    運行時執行本函數時賦予初值的,相當於執行一個賦值語句。
        —數據的輸入輸出
            C語言本身不提供輸入輸出的語句,輸入和輸出操作是由從標准函數庫中的函數來實現的。
                在調用標准輸入輸出庫函數時,文件開頭應該有以下預處理指令。
                    # include <stdio.h>                 //系統定義函數,是標准方式。
                或
                    # include "stdio.h"                  //用戶定義函數
            用printf函數輸出數據
                格式字符
                    1、%d格式符:輸出一個有符號的十進制整數,若輸出long數據,在d前面加字母l,即%ld。
                    2、%c格式符:用來輸出一個字符。(ASCII碼中0~127是標准的,128~255是擴展的,因為字符變量無符號)
                                            一個整數,如果在0~127范圍中,也可以用%c輸出,因為字符變量實際上是一個字節的整型變量。
                                            如果整數較大,則把它的最后一個字節的信息以字符形式輸出。
                    3、%s格式符:用來輸出一個字符串。
                    4、%f格式符:用來輸出實數(包括單、雙精度、長雙精度),以小數形式輸出,有以下幾種用法:
                                            ①基本型,用%f:
                                                    不指定輸出數據的長度,由系統根據數據的實際情況決定數據所占的列數。
                                                    系統處理的方法一般是:實數中的整數部分全部輸出,小數部分輸出6位。
                                            ②制定數據寬度和小數位數,用%m.nf:
                                                    m表示數據寬度,n表示小數位數,m包括符號位。
                                            ③輸出的數據向左對齊,用%-m.nf:
                                                    輸出默認右對齊,- 表示左對齊。
                    5、%e格式符:用格式聲明%e 指定以指數形式輸出實數。如果不指定輸出數據所占的寬度和數字部分的小數位數,
                                            系統會自動給出數字部分的小數位數為6位,指數部分占5列(如e+002)。數值按標准化指數形式
                                            輸出(即小數點前必須有而且只有1位非零數字)。例如:
                                                1.234560e+002
                    其它格式符:
                        1、i 格式符:作用與d格式符相同。
                        2、o 格式符:以八進制整數形式輸出。
                        3、x 格式符:以十六進制數形式輸出。
                        4、u 格式符:用來輸出無符號(unsigned)型數據,以十進制整數形式輸出。
                        5、g格式符:用來輸出浮點數,系統自動選擇 f 格式或者 e 格式輸出,選擇其中長度較短的格式,不輸出無意義的0。
            用scanf函數輸入數據
                scanf函數所用的格式字符和附加字符用法與printf相似。
                使用scanf函數時應注意的問題
                    1、scanf函數中的“格式控制”后面應當是變量地址,而不是變量名,要使用&運算符。
                    2、如果在“格式控制字符串”中除了格式聲明以外還有其他字符,則在輸入數據時在對應的位置上應輸入與這些字符
                          相同的字符。
                    3、在用“%c ”格式聲明輸入字符時,空格字符和“轉義字符”中的字符都作為有效字符輸入,因為%c是字符格式,
                          所以輸入的每個字符都會被存儲到相應的變量當中。
                    4、在輸入數值數據時,如輸入空格,回車,tab鍵或遇非法輸入(不屬於數值的字符),則認為該數據結束。
            字符數據的輸入輸出
                putchar()  輸出一個字符
                    putchar函數即可以輸出能在顯示器上顯示的字符,也可以輸出屏幕控制字符,如put('\n')
                        \\  整型數據與字符是通用的,可以再putchar()中輸入該字符的ASCII碼。
                getchar()  輸入一個字符
                        在鍵盤輸入信息時,並不是在鍵盤上敲一個字符,該字符就立即送到計算機中去的,這些字符先暫存在鍵盤的緩沖
                        器中,只有按了Enter鍵才把這些字符一起輸入到計算機中,然后按先后順序分別賦給相應的變量。
                        執行getchar()可以從輸入設備獲取一個可顯示的字符,也可以獲取一個控制字符。
                        用getchar()函數得到的字符可以賦給一個字符變量,也可以作為表達式的一部分putchar(getchar())。
                puts()       輸出字符串
                gets()       輸入字符串

第4章    選擇結構程序設計
    —關系運算符與表達式
            運算符優先等級
                !(非) > 算術 > 關系 > 邏輯 > 條件 > 賦值
            邏輯運算符與表達式
                實際上,邏輯運算符兩側的運算對象不但可以是0和1,或者0和非0的正數,也可以是字符型、浮點型、枚舉型或指針型的
                純量數據,系統最終以0和非0來判斷他們屬於真或假。
                邏輯型變量(布爾型變量)C語言中沒有bool型變量,C++中有

    —條件運算符和條件表達式
        (    ?    :    )是三目運算符,要求有三個操作對象,它是C語言中的唯一一個三目運算符。
                int a = 1,b = 2,c = 3;
                    printf("%d",a>b?a:(a<b?c:a));    //輸出結果為3。
    —switch語句
        switch后面括號內的”表達式“,其值的類型只能是整數類型或者字符型。

第5章    循環結構程序設計
    逗號表達式從左向右,賦值表達式從右向左。
    在循環結構中定義的變量的有效范圍僅限循環結構中,在循環外不能使用此變量。
    break語句只能用於循環語句和switch語句中,而不能單獨使用,如果是雙重循環,在內循環中有break語句,則break僅中止內循環。
第6章    利用數組處理批量數據
    —怎樣定義和引用一維數組
        如果在被調用的函數(不包括主函數)中定義數組,其長度可以是變量或非常量表達式,如:
            void fun(int n)
            {
                int  a [2 * n]        // 合法,n的值從實參傳來。
            }
        在調用fun函數時,形參n從實參得到值,這種情況被稱為“可變長數組”,允許每次調用fun函數時,n有不同的值。
        但是在執行函數時,n的值是不變的,數組長度是固定的,如果定義數組為靜態存儲方式,則不能用“可變長數組”,如:
            static a [2 * n]        // 不合法,a數組指定為靜態static存儲方式。
    —一維數組的初始化
            1、在定義數組時對全部數組元素賦予初值,如:
                    int a[5] = {1,2,3,4,5};
            2、可以只給數組中的一部分元素賦值,如:
                    int a[5] = {1,2,3};
                系統自動給后兩個元素賦初值為0。
            3、如果想使數組中全部元素值為0,可以寫成:
                    int a[5] = {0};
                或
                    int a[5] = {0,0,0,0,0}
            4、在對全部數組元素賦初值時,由於數據的個數已確定,因此可以不指定數組長度,如:
                    int a[] = {1,2,3,4,5};
            說明:如果在定義數值型數組時,指定了數組的長度並未對之初始化,凡未被初始化列表指定初始化的數據元素,
            系統會自動把它們初始化為0(如果是字符型數組,則初始化為'\0',如果是指針型數組,則初始化為NULL,即空指針)。
    —怎樣定義和引用二維數組
            用矩陣形式表示二維數組,是邏輯上的概念,能形象的表示出行列的關系,而在內存中每個元素是連續存放的,不是二位的,
            而是線性的。
    —二維數組的初始化
            1、分行給二維數組賦初值,如:
                    int a[3][4] = {{1,2,3,4}{5,6,7,8}{9,10,11,12}};
            2、int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
            3、可以對部分元素賦初值,如:
                    int a[3][4] = {{1},{5},{9}};
                  它的作用是只對各行第一列(即序號為0的列)的元素賦初值,其余元素自動為0,也可以對各行中的某一元素賦初值,如:
                    int a[3][4] = {{1},{0,6},{0,0,11}};
                  初始化后的數組元素如下:
                    1  0  0  0
                    0  6  0  0
                    0  0  11 0
            4、如果對全部元素都賦初值(即提供全部數據),則定義數組時對第1維數組的長度可以不指定,但第2維的長度不能省,如:
                    int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
                  系統會根據數據總個數和第2維的長度算出第1維的長度。
    —字符串
        使用字符串處理函數        # include <string.h>
        1、puts()函數——輸出字符串的函數
                用puts()函數輸出的字符串中可以包含轉義字符。
        2、gets()函數——輸入字符串的函數
                一般利用gets函數的目的是向字符數組輸入一個字符串,而不關心其函數值。
             注意:用puts和gets函數只能輸出或輸入一個字符串。
        3、strcat()函數——字符串連接函數
                其一般形式為:
                    strcat(字符數組1,字符數組2)
                strcat是STRingCATenate(字符串連接)的縮寫其作用是把兩個字符串連接起來,把字符串2接到字符串1的后面,結果
                放在字符數組1中,函數調用后得到一個函數值——字符數組1的地址。
                說明:
                    1、字符數組1必須足夠大,能容納字符數組2.。
                    2、連接前兩個字符串后面都有'\0',連接時將字符串1后面的'\0'取消,只在新串最后保留'\0'。
        4、strcpy()和strncpy()函數——字符串復值函數
                其一般形式為
                    strcpy(字符數組1,字符串2)
                strcpy是STRingCoPY的縮寫(字符串復制),它表示將字符串2復制到字符數組1中去。
                說明:
                    1、字符數組1必須足夠大,能容納字符串2。
                    2、“字符數組1”必須寫成數組名形式(str1),“字符串2”可以是字符數組名也可以是一個字符串常量。
                    3、復制時將str2中的字符串和其后的'\0'一起復制到字符數組1中,取代字符數組1中的前n個字符,未復制的不一定是
                         '\0',而是str1中原有的內容。
                    4、不能用賦值語句直接賦值。
                    5、可以用strncpy函數將字符串2中前面n個字符復制到字符數組1中去,但復制的字符個數不應多於str1中原有的字符,不
                         包括'\0'。如:
                            strcpy(str1,str2,5);
        5、strcmp()函數——字符串比較函數
                其一般形式為:
                    strcmp(字符串1,字符串2)
                strcmp是STRing CoMPare(字符串比較)的縮寫。它的作用是比較字符串1和字符串2。
                說明:
                    字符串比較的規則是:將兩個字符串自左向右逐個字符比較(按ASCII碼值大小比較),直到出現不同的字符或'\0'為止。
                    1、如全部字符相同,則認為兩個字符串相等。
                    2、若出現不同的字符,則以第1對不相同的字符的比較結果為准。
                比較的結果由函數值帶回。
                    1、如果字符串1 = 字符串2,則函數值為0。
                    2、如果字符串1 > 字符串2,則函數值為一個正整數。
                    3、如果字符串1 < 字符串2,則函數值為一個負整數。
                注意:對兩個字符串比較,不能用以下形式:
                    if (str1 > str2)
                        printf("yes\n");
                    而只能用:
                    if (strcmp(str1 > str2) > 0)
                        printf("yes\n");
        6、strlen()函數——測字符串長度
                其一般形式為:
                    strlen(字符數組)
                strlen是STRingLENgth(字符串長度)的縮寫。它是測試字符串長度的函數,函數的值為字符串中的實際長度(不包括'\0')
                    char str[10] = "China";
                    printf("%d\n",strlen(str));        //或者strlen("China");
                輸出:5
        7、strlwr()函數——轉換為小寫的函數
        8、strupr()函數——轉換為大寫的函數
第7章 用函數實現模塊化程序設計
    —調用函數
            如果函數值的類型和return語句中表達式的值不一致,則以函數類型為准。對數值型數據,可以自動進行轉換,即函數類型決
            定返回值的類型。
            當函數類型被定義為void型時,函數體重不得出現return語句。
    —函數的遞歸調用
            在調用一個函數的過程中又出現直接或間接的調用該函數本身,稱為函數的遞歸調用。如:
                int fun(int x)
                {
                    int x,y;
                    y = fun(x);
                    return z;
                } 
            在調用函數fun的過程中,又要調用fun函數,這是直接調用本函數。
            如果在調用函數f1的過程中要調用f2函數,而在調用f2函數過程中又要調用f1函數,就是間接調用本函數。
        舉個例子:有5個學生坐在一起,問第5個學生多少歲,他說比第4個學生大2歲,問第4個學生多少歲,他說比第3個學生大2歲,
                          問第3個學生多少歲,他說比第2個學生大2歲,問第2個學生,他說比第1個學生大2歲,第一個學生10歲,請問第5
                          個學生多大?
                    即:
                        age(5) = age(4) + 2;
                        age(4) = age(3) + 2;
                        age(3) = age(2) + 2;
                        age(2) = age(1) + 2;
                        age(1) = 10;

                        # include <stdio.h>
 
                        int main (void)
                        {
                int age(int n);
                printf("NO.5,age:%d\n",age(5));
        
                return 0;
                        }
                        int age(int n)
                        {
                int c;
                if (n == 1)
                    c = 10;
                else
                c = age(n-1) + 2;
 
                return c;
                        }
                        當最后一次遞歸調用結束的時候,開始依次出棧,
                        出棧從最后那次調用開始,直到第一次調用結束。 
                用遞歸方法求 a!。
                     # include <stdio.h>
 
                    int main (void)
                    {
                  int jiecheng(int n);
                int x;
                scanf("%d",&x);
                printf("%d\n",jiecheng(x));
 
                return 0;
                        }
 
                        int jiecheng(int a)
                        {
                        if (a<0)
                        printf("data error!\n");
                        else if (a == 1 || a == 0)
                        a = 1;
                        else
                        a = jiecheng(a-1) * a;
 
                        return a;
                        }
    —數組作為函數參數
            數組元素可以用作函數實參,不能用作形參,因為形參是在函數被調用時臨時分配的存儲單元,不可能為一個數組元素單獨
            分配存儲單元(數組是一個整體,在內存中占連續的一段存儲空間)。在用數組元素做函數實參時,把實參的值傳給形參,
            是“值傳遞”的方式。數據傳遞的方向是從實參傳到形參,單向傳遞。
            出了用數組元素作為函數參數外,還可以用數組名作為函數參數(包括實參和形參),應當注意的是:用數組元素作實參時,
            向形參變量(數組名或指針變量)傳遞的是數組首元素的地址。
    —局部變量和全局變量
        定義變量有三種情況:
            1、在函數的開頭定義。
            2、在函數內的復合語句定義。
            3、在函數的外部定義。
        局部變量
            在一個函數內部定義的變量只在本函數范圍內有效,也就是說只有在本函數內才能引用它們,在此函數意外是不能使用這些
            變量的。在復合語句內定義的變量只在本復合語句范圍內有效,在該復合語句以外是不能使用這些變量的,以上這些稱為“局部
            變量”。
        全局變量
            在函數內定義的變量是局部變量,而在函數外定義的變量稱為外部變量,外部變量是全局變量(也稱全程變量)。全局變量可以
            為本文件中其他函數所共用。它的有效范圍為從定義變量的位置開始到本源文件結束。
                注意:在函數內定義的變量是局部變量,在函數外定義的變量是全局變量。
            為了便與區別全局變量和局部變量,在C程序設計人員中有一個習慣(但非規定),將全局變量名的第一個字母用大寫表示。
            當局部變量和全局變量沖突時,局部變量有效,全局變量被屏蔽。
        從作用域看:
            全局變量具有全局作用域。全局變量只需在一個源文件中定義,就可以作用於所有的源文件。當然,其他不包括全局變量定義的
            源文件需要用extern關鍵字再次聲明這個全局變量。
    —變量的存儲方式和生存期
        動態存儲方式與靜態存儲方式
            從變量的作用域的角度來觀察,變量可以分為全局變量和局部變量。
            還可以從另一個角度,即從變量值存在的時間(即生存期)來觀察。有的變量在程序運行的整個過程都是存在的,而有的變量則
            是在調用其所在的函數是才臨時分配存儲單元,而在函數調用結束后該存儲單元馬上就釋放了,變量不存在了。也就是說,變量
            的存儲有兩種不同的方式:靜態存儲方式和動態存儲方式。靜態存儲方式是指在程序運行期間由系統分配固定的存儲空間的方式,
            而動態存儲方式則是在程序運行期間根據需要進行動態的分配存儲空間的方式。
        先看一下內存中的供用戶使用的存儲空間的情況。這個存儲空間可以分為3個部分:
            1、程序區。
            2、靜態存儲區。
            3、動態存儲區。
        數據分別存放在靜態存儲區和動態存儲區中。全局變量全部存放在靜態存儲區中,在開始執行時給全局變量分配存儲區,程序執行
        完畢就釋放。在程序執行過程中它們占據固定的存儲單元,而不是動態的進行分配和釋放。
        在動態存儲區中存放以下數據:
            1、函數形式參數。在調用函數時給形參分配存儲空間。
            2、函數定義的沒有用的關鍵字static聲明的變量,即自動變量。
            3、函數調用時的現場保護和返回地址等。
        對以上這些數據,在函數調用開始時分配動態存儲空間,函數結束時釋放這些空間。在程序執行過程中,這種分配和釋放是動態的,
        如果在一個程序中兩次調用同一函數,而在此函數中定義了局部變量。在兩次調用時分配給這些局部變量的存儲空間的地址可能是
        不相同的。
        在C語言中,每一個變量和函數都有兩個屬性:數據類型和數據的存儲類別。存儲類別指的是數據在內存中存儲的方式(如靜態存
        儲和動態存儲)。C語言的存儲類別包括4種:自動的 auto(系統默認類別)、靜態的 statis、寄存器的 register、外部的 extern。
            自動變量 (auto自動變量):
                函數中的局部變量,如果不專門聲明為 static 靜態存儲類別,都是動態地分配存儲空間的,數據存儲在動態存儲區中。函數中
                的形參和在函數中定義的局部變量(包括在復合語句中定義的局部變量),都屬於此類。在調用該函數時,系統會給這些變量
                分配存儲空間,在函數調用結束時就自動釋放這些存儲空間。因此這類局部變量稱為自動變量。自動變量用關鍵字 auto作為
                存儲類別的聲明。實際上,關鍵字 auto可以省略,不寫auto 則隱含指為“自動存儲類別”,它屬於動態存儲方式。程序中大多
                數變量都屬於自動變量。
           靜態局部變量(static局部變量)
                有時希望函數中的局部變量的值在函數調用結束后不消失而繼續保留原值,即其占用的存儲單元不釋放,在下一次再調用該
                函數時,該變量已有值(就是上一次函數調用結束時的值)。這是就應該指定該局部變量為“靜態局部變量”,用關鍵字 static
                進行聲明。
            寄存器變量(register 變量)
                一般情況下,變量(包括靜態存儲方式和動態存儲方式)的值是存放在內存中的。當程序中用到哪一個變量的值時,由控制器
                發出指令將內存中該變量的值送到運算器中。經過運算器進行運算,如果需要存數,再從運算器將該數據送到內存中。
                如果有一些變量使用頻繁(例如在一個函數中執行10000次循環,每次循環中都要引用某局部變量),則為存取變量的值要花
                費不少時間。為提高執行效率,允許將局部變量的值放在CPU中的寄存器中,需要時直接從寄存器中取出參加運算,不必再
                到內存中去存取,。由於對寄存器的存取速度遠高於對內存的存取速度,因此這樣做可以提高執行效率。這種變量叫做寄存
                器變量。用關鍵字register 作聲明即可。如:
                    register int f;        //定義f為寄存器變量。
                由於現在的計算機的速度越來越快,性能越來越高,優化的編譯系統能夠識別使用頻繁的變量,從而自動的將這些變量存放
                在寄存器中,而不需要程序設計者去指定。因此,現在實際上用register 聲明變量的必要性不大,只需了了解即可。
            全局變量(extern變量)
                全局變量都是存放在靜態存儲區中的,因此它們的生存期是固定的,存在於程序的整個運行過程。一般來說,外部變量是在
                函數的外部定義的全局變量,它的作用域是從變量的定義處開始,到本程序文件的末尾。在此作用域內,全局變量可以為程
                序中各個函數所引用。但有時程序設計人員希望能擴展外部變量的作用域,有以下幾種情況:
                1、在一個文件內擴展外部變量的作用域。
                        如果外部變量不在文件的開頭定義,其有效的作用范圍只限於定義處到文件的結束。在定義點之前的函數不能引用該外
                        部變量。如果在定義點之前的函數需要引用該外部變量,則應該在飲用之前用關鍵字extern對該變量做“外部變量聲
                        明”,表示把該外部變量的作用於擴展到此位置,有了此聲明,就可以從聲明處起,合法的使用該外部變量。
                        用extern 聲明外部變量時,類型名可以寫也可以省寫。例如“extern int A,B,C;”也可以寫成“extern A,B,C;”.因為它不
                        是定義變量,只需寫出外部變量名即可。
                2、將外部變量的作用域擴展到其他文件
                        在任意一個文件中定義外部變量A,而在靈異文件中用 extern 對A作“外部變量聲明”,即“extern A;”
                        當文件和函數都有該變量時,extern的處理方式為:先找函數,再找文件,找不到按出錯處理。
                3、將外部變量的作用域限制在本文件中
                        有時在程序設計中希望某些外部變量只限於被本文件引用,而不能被其他文件引用,可以在定義外部變量時加一個
                        static 聲明。例如:
                            file1.c                            file2.c
                            static int A;                    extern A;
                                                                 A = A * 2;                //出錯
                        這種加上static聲明、只能用於本文件的外部變量稱為“靜態外部變量”。
                用static 聲明一個變量的作用是:
                    1、對局部變量用static聲明,把它分配在靜態存儲區,該變量在整個程序執行期間不釋放,其所分配的空間始終存在。
                    2、對全局變量用static聲明,則該變量的作用於只限於本文件模塊
                注意:
                    用auto、register、static聲明變量時,是在定義變量的基礎上加上這些關鍵字,而不能單獨使用,編譯時會被認為“重新
                    定義”。
            存儲類別小結
                對一個數據的定義,需要指定兩種屬性:數據類型和存儲類別,分別使用兩個關鍵字:
                    static int a;            //靜態局部整型變量或靜態外部整型變量
                    auto char c;          //自動變量,在函數內定義(自動變量是自動創建自動釋放,存在於棧;動態變量需要申請內存 malloc)
                    register int b;        //寄存器變量,在函數內定義
                此外,可以用extern聲明已定義的外部變量:
                    extern b                //將已定義的外部變量b的作用域擴展至此
                下面從不同角度做歸納:
                    1、從作用域角度區分,有局部變量和全局變量。它們采用的存儲類別如下:
                        按作用域角度區分:
                            (1)局部變量:自動變量,即動態局部變量(離開函數,值就消失)。
                                                       靜態局部變量(離開函數,值仍保留)。
                                                       寄存器變量(離開函數,值就消失)。
                                                       (形式參數可以定義為自動變量或寄存器變量)
                            (2)全局變量:靜態外部變量(只限本文件引用)。
                                                       外部變量(即非靜態的外部變量,允許其他文件引用)。
                    2、從變量存在的時間(生存期)來區分,有動態存儲和靜態存儲兩種類型。靜態存儲是程序整個運行時間都存在,而動態
                        存儲則是在調用函數時臨時分配單元。
                        按變量的生存期區分:
                            (1)動態存儲:自動變量(本函數有效)。
                                                       寄存器變量(本函數內有效)。
                                                       形式參數(本函數內有效)。
                            (2)靜態存儲:靜態局部變量(函數內有效)。
                                                       靜態外部變量(本文件內有效)。
                                                       外部變量(用extern聲明后,其他文件可引用)。
                    3、從變量值存放的位置來區分:
                            (1)內存中靜態存儲區:靜態局部變量
                                                                    靜態外部變量(函數外部靜態變量)。
                                                                    外部變量(可為其他文件引用)。
                            (2)內存中動態存儲區:自動變量和形式參數。
                            (3)cpu中的寄存器:寄存器變量。
                    4、關於作用域和生存期的概念。
                        如果一個變量在某個文件或函數范圍內是有效的,就稱該范圍為該變量的作用域,在此作用域內可以引用該變量,在專
                        業書中稱變量在此作用域內“可見”。如果一個變量值在某一時刻是存在的,則認為這一時刻屬於該變量的生存期,或稱
                        該變量在此時刻“存在”。
                        ———————————————————————————————————
                        |                                           |             函數內              |               函數外             |    
                        |            變量存儲類別          ——————————————————————
                        |                                           |    作用域    |    存在性    |    作用域    |    存在性    |
                        ———————————————————————————————————
                        |    自動變量和寄存器變量    |        √         |        √        |        ×        |        ×         |
                        ———————————————————————————————————
                        |            靜態局部變量          |        √         |        √        |        ×        |        ×         |
                        ———————————————————————————————————
                        |            靜態外部變量          |        √         |        √        |√只限本文件|       √        |
                        ———————————————————————————————————
                        |               外部變量              |        √         |        √        |        √        |        √         |
                        ———————————————————————————————————
                    5、static對局部變量和全局變量的作用不同,對局部變量來說,它使變量由動態存儲方式改變為靜態存儲方式。而對全局
                         變量來說,它使變量局部化(局限於本文件),但仍為靜態存儲方式,從作用域角度來看,凡有static聲明的,其作用
                        都是局限的,或者是局限於本函數內(靜態局部變量)。或者局限於本文件內(靜態外部變量)。
第8章 善於利用指針
            如果p的初值為&a[0],則p+i和a+i就是數組元素a[i]的地址,或者說,它們指向a數組序號為i的元素。[ ]實際上是變址運算符,即
    將a[i]按a+i計算地址,然后找出此地址單元中的值(先找到a地址,然后再找a+i的地址)。
   ————指向多維數組的指針
 ————指針數組
 ————多級指針
 ————指針數組做main函數的形參  ————這幾個理解的不透徹,就不寫了

    —通過指針引用字符串
        # include <stdio.h>
        int main (void)
        {
                char * string \ " I love China!";
                printf("%s\n",string);
                return 0;
        }
            運行:
                I love China!
            注意:string被定義為一個指針變量,基類型為字符型。請注意它只能指向一個字符類型數據,而不能同時指向多個字符數據,
                       更不是把“I love China!”這些字符存放到string中(指針變量只能存放地址),也不是把字符串賦給*string。只是把字符串
                       的第一個字符的地址賦給了指針變量*string。
    —使用字符指針變量和字符數組的比較
        1、字符數組由若干個元素組成,每個元素中放一個字符,而字符指針變量中存放的是地址(字符串第一個字符的地址),絕不是
             將字符串放到字符指針變量中。
        2、賦值方式。可以對字符指針變量賦值,但不能對數組名賦值。
        3、存儲單元的內容,編譯時為字符數組分配若干存儲單元,以存放個元素的值,而對字符指針變量,只分配了一個存儲單元。
        4、指針變量的值是可以改變的,而數組名代表一個固定的值,不能改變。
    —動態內存分配與指向它的指針變量
        什么是內存的動態分配
            全局變量是分配在內存中的靜態存儲區的,飛靜態的局部變量(包括形參)是分配在內存中的動態存儲區的,這個存儲區是一個
            稱之為——棧——的區域,為變量分配存儲空間。
            除此之外,C語言還允許建立內存動態分配區域,以存放一些臨時用的數據,這些數據不必在程序的聲明部分定義,也不必等到
            函數結束時才釋放,而是需要時隨時開辟,不需要時隨時釋放,這些數據是臨時存放在一個特別的自由存儲區稱為——堆——區
            域,可以根據需要,向系統申請所需大小的空間(malloc函數)。由於未在聲明部分定義它們為變量或數組,因此不能通過變量
            名或數組名去引用這些數據,只能通過指針來引用,malloc函數的定義:
                int *p;
                *p = (int*)malloc(sizeof(int));
        怎樣建立內存的動態分配
            對內存的動態分配是通過系統提供的庫函數來實現的,主要有malloc,calloc,free,realloc這四個函數。
            1、使用 malloc 函數
                其函數原型為:
                    (void *) malloc(unsigned int size)
                其作用是在內存的動態存儲區中分配一個長度為size的連續空間。形參size的類型為無符號整型(不允許為負數)。此函數的值
                (即返回值)是所分配區域的第一個字節的地址,或者說,此函數是一個指針型函數,返回的指針只想該分配區域的開頭位置
            2、使用 free 函數
                其函數原型為
                    void free(void *p);
                其作用是釋放指針變量p所指向的動態空間,使這部分空間能重新被其他變量使用。
第9章 用戶自己建立數據類型
    —定義結構體的方式
            1、 定義結構體數組
                  struct student            //struct student  是用戶自定義的一種數據類型
                  {
                        int age;
                        float score;
                  } 
                  struct student s1 = {19,92.5} ;
             2、
                  struct student
                  {
                        int age;
                        float score;
                  } s1;                        //只能定義一次
    —怎樣使用結構體變量 

        1、賦值和初始化
              定義的同時可以整體賦初值
              如果定義完之后,只能單個的賦初值。
                struct student            //struct student  是用戶自定義的一種數據類型
                {
                      int age;
                      float score;
                } 
                struct student s1 = {19,92.5} ;    //定義的同時賦初值
                struct student s2;        //定義
                s2.age = 10;                //分開賦值
                s2.score = 80.5; 
                printf("%d %f\n",s1.age,s1.score);
                printf("%d %f\n",s2.age,s2.score); 
    —結構體指針
        所謂結構體質針就是指向結構體變量的指針,一個結構體變量的起始地址就是這個結構體變量的指針。如果把一個結構體變量的起
        始地址存放在一個指針變量中,那么這個指針變量就指向該結構體變量。
        指向結構體變量的指針:
            指向結構體對象的指針變量既可指向結構體變量,也可指向結構體數組中的元素。指針變量的基類型必須與結構體變量的類型
            相同。例如:
                struct student * p;        // p可以指向struct student類型的變量或數組元素
        # include <stdio.h>
        # include <string.h>
        struct student
        {
        int age;
        char name[10];
        };
 
        int main (void)
        {
        struct student s1;
        struct student *s2;
        s2 = &s1;                                // s2 指向 s1,必須加&取地址符號
        s1.age = 18;
        strcpy(s1.name,"wang");
        printf("%d   %s\n",s1.age,s1.name);
                printf("%d   %s\n",(*s2).age,(*s2).name);
 
        return 0;
        }
        說明:為了方便和直觀,C語言允許把(*p).name用p->num來代替,“->”代表一個箭頭,p->num表示p所指向的結構體變量中的num
                  成員。"->"稱為指向運算符。
                        如果p指向一個結構體變量s1,以下三種方法等價:
                        1、s1. 成員名
                        2、(*p). 成員名
                        3、p -> 成員名 
     —用指針處理鏈表        ——見數據結構
        鏈表有一個“頭指針”變量,它存放一個地址,該地址指向一個元素。鏈表中每一個元素稱為“結點”,每個結點都應包括兩個部分:
        (1)用戶需要用的實際數據;(2)下一個結點的地址。可以看出,頭指針指向第1個元素,第1個元素又指向第2個元素……直到
        最后一個元素,該元素不再指向其他元素,它稱為“表尾”,它的地址部分存放一個“NULL”(表示空地址),鏈表到此結束。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM