1. 程式人生 > >C 【printf 和 scanf 函式的使用】

C 【printf 和 scanf 函式的使用】

        對於printf函式,我們主要要掌握printf函式的輸出格式

        而對於scanf函式,我們則要知道幾個輸入過程中的錯誤輸入情況和scanf函式的實現原理

  •  (1)printf 函式
  •     printf格式控制 部分 的完整格式:
  •     "% - 0 m.n l或h 格式字元"
  •     下面對組成格式說明的各項加以說明: 
  •                ① %   表示格式說明的起始符號,不可缺少。
  •                ② -   有-表示左對齊輸出(右側補空格),如省略表示右對齊輸出(左側補空格)。
  •                ③ 0   有0表示指定空位填0,如省略表示指定空位不填。
  •                ④ m.n   m指域寬,即對應的輸出項在輸出裝置上所佔的字元數。n指精度。用於說明輸出的實型數的小數位數。對數值型的來說,未指定n時,隱含的精度為n=6位。
  •                ⑤ l或h   l對整型指long型,對實型指double型。h用於將整型的格式字元修正為short型。
  •                ⑥ 格式字元(格式字元用於 指定輸出項的 資料型別輸出格式) :
  •                                 d格式:用來輸出十進位制整數。有以下幾種用法:
  •                                           %d %hd %ld
  •                                 o格式:以無符號八進位制形式輸出整數
  •                                 x格式:以無符號十六進位制形式輸出整數
  •                                 u格式:以無符號十進位制形式輸出整數
  •                                 c格式:輸出一個字元
  •                                 s格式:用來輸出一個串。有幾種用法列舉:
  •                                              ① %s   例如:printf("%s","CHINA")輸出"CHINA"字串(不包括雙引號)。
  •                                              ② %ms   輸出的字串佔m列,如字串本身長度大於m,則突破獲m的限制,將字串全部輸出。若串 長小於m,則左補空格。
  •                                              ③ %-ms   如果串長小於m,則在m列範圍內,字串向左靠,右補空格。
  •                                            (以下④⑤條中的 m和n 的含義不同於上面)
  •                                              ④ %m.ns   輸出佔m列,但只取字串中 左端 n個字元。這n個字元輸出在m列的右側,左補空格。 注意:如果n未指定,預設為0。如果n>m,則m自   動取n的值,即保證n個字元正常輸出。
  •                                              ⑤ %-m.ns   其中m、n含義同上,n個字元輸出在m列範圍的左側,右補空格。 注意:如果n未指定,預設為0。如果n>m,則m自動取n的值,即保證n個字元正常輸出。
  •  (2)scanf 函式
  •     scanf是一個阻礙式函式,程式在執行過程中會停在scanf函數出現的地方,直到接收資料時才會執行後面的程式碼。
  •     scanf使用時注意的幾個點:
  •                  ① 如果在控制檯輸入時輸入了多個空格、回車、Tab都會被系統忽略的(這其中包括輸入多個實型常量 和型常量時如果間輸入了多餘的空格、回車、Tab也是都會被系統忽略的
  •                  ② 字元型常量整型常量 或 實型常量 混合輸入的時候,要注意新增分隔符,來避免無意輸入 空格 造成的錯誤
  •                  ③ 在scanf中,儘量不要使用\n,因為會造成在輸入的時候無限換行。如果使用了\n,那麼在輸入的時候一定要原樣輸入“\n”才可以解決
  •     scanf實現原理:系統會將使用者在控制檯輸入的內容放入輸入緩衝區,scanf會從輸入緩衝區內逐個取出內容賦值給格式符,如果型別不一致的話不會修改原有資料。並且如果輸入緩衝區中不為空,那麼再次使用scanf時scanf會一直從緩衝區中獲取值,而不會要求使用者再次輸入。
  •     接下來一段程式碼會將上面 需要注意的幾個點 和 實現原理 相結合為大家展示

  • #include <stdio.h>
    
    int main(int argc, const char * argv[]) {
        
        int intValue1 = 1;
        char charValue1 = '1';
        int intValue2 = 2;
        
        char charValue2 = '2';
        int intValue3 = 3;
        
        printf("-----第一次輸入:-----\n");
        scanf("%d%c%d", &intValue1, &charValue1, &intValue2);
        printf("\n-----第一次輸出:-----\n");
        printf("intValue1 = %d,charValue1 = %c,intValue2 = %d\n", intValue1, charValue1, intValue2);
        
        printf("\n-----第二次輸入:-----\n");
        scanf("%c%d", &charValue2, &intValue3);
        printf("\n-----第二次輸出:-----\n");
        printf("charValue2 = %c,intValue3 = %d\n\n", charValue2, intValue3);
        
        return 0;
    }
    
    /*
     *  執行結果:
     
        -----第一次輸入:-----
        19 s 32
    
        -----第一次輸出:-----
        intValue1 = 19,charValue1 =  ,intValue2 = 2
    
        -----第二次輸入:-----
    
        -----第二次輸出:-----
        charValue2 = s,intValue3 = 32
     
     */
    

  •    執行結果分析:
       
       首先看輸入部分,第一次看似輸入了3個值,實則不然,我們輸入了5個。分別是:19 空格 s 空格 32
       再看第二次輸入,直接被跳過了。
     
       其次看輸出部分,一次輸入(只按了一次回車),兩次結果都打印出來了:
       intValue1 = 19,charValue1 =  ,intValue2 = 2,charValue2 = s,intValue3 = 32

       經上面的分析,我們一共在控制檯手動輸入了5個值,也就是讓scanf去輸入緩衝區去取5次值,第一次輸入scanf將前三個值取出來,也就是取出 19、空格、s,並將他們賦給intValue1、charValue1、intValue2,前兩個正常賦值,但是第三個值 s 和 intValue2的型別不匹配,所以輸入快取區裡的值 s 並沒有被取走,而intValue2顯示的就是它初始化時被賦予的值 2。
       試想一下,現在輸入快取區中還存在三個值,那就是第一次沒被取走的 s 以及 空格 和 32。所以說第二次控制檯輸入不會執行,而是繼續在輸入快取區中取值。自然 s 賦給了 charValue2,又因為 空格 換行 tab 遇到 非char型別的值時會被忽略,所以說 空格 就被忽略了。那麼最後一個值 32 就被賦給intValue3了。
     
     
  •    接下來一個小問題,來加深理解這部分內容:
  • #include <stdio.h>
    
    void test1();
    
    int main(int argc, const char * argv[]) {
        
        int a = 0;
        int b = 0;
        int c = 0;
        int d = 0;
        int e = 0;
        int f = 0;
    
        printf("第一次輸入:\n");
        scanf("%i,%i,%i", &a, &b, &c);
        printf("-----第一次輸入結束-----\n");
        printf("第一次輸出結果---%i,%i,%i,%i,%i,%i\n", a, b, c, d, e, f);
    
    //    setbuf(stdin, NULL); // 清空輸入快取區的快取資料
    
        printf("第二次輸入:\n");
        scanf("%i,%i,%i", &d, &e, &f);
        printf("-----第二次輸入結束-----\n");
        printf("第二次輸出結果---%i,%i,%i,%i,%i,%i\n", a, b, c, d, e, f);
        
        
        return 0;
    }
    
    /*
     *  執行結果:
     
        第一次輸入:
        1,2,3,4,5,6
        -----第一次輸入結束-----
        第一次輸出結果---1,2,3,0,0,0
        第二次輸入:
        -----第二次輸入結束-----
        第二次輸出結果---1,2,3,0,0,0
     
     */
  •    執行結果分析:

               和上面的程式一樣,一次性輸入多個值,那麼會在快取區裡儲存未賦值的資料。那為什麼第二次輸入的時候d、e、f的值還是0呢?不應該是4,5,6嗎?這是因為在輸入的時候我們加上了逗號作為分隔符,而一次輸入6個值時,c與d之間是沒有逗號作為分隔符的,但我們卻多輸入了一個逗號,那麼逗號就會從快取區中取出並依次賦給d、e、f,但型別不匹配,所以說賦值失敗,於是輸出結果d、e、f還是0。

  •   
    /*
     *  如果是按下面的方式進行輸出,空格去替代3和4之間的逗號,那麼賦值時空格遇到非char型別的資料自動忽略,所以後面的4、5、6成功賦值
     *  執行結果:
     
        第一次輸入:
        1,2,3 4,5,6
        -----第一次輸入結束-----
        第一次輸出結果---1,2,3,0,0,0
        第二次輸入:
        -----第二次輸入結束-----
        第二次輸出結果---1,2,3,4,5,6
     
     */