2023年11月5日 星期日

Chapter 04:C的輸出PART02、運算、輸出

 目標:

  1. 學會輸出、輸入的格式化。
  2. 學會輸出。
  3. 學會運算式。
  4. 溢位處理

筆者的小講堂:

在前一章節已經學會了最基本的輸出,而輸出都是字串,但是因為資料型態的不同,因此要用一點點複雜的方式輸出其他資料型態。最基本的問題,如果我叫電腦算1+1,是用printf("1+1");,那答案會是2嗎?其實不然,輸出的是1+1,因為電腦以為那是一句句子,不是一個運算式。那麼,要入何正確的輸出1+1為2呢?這就是這個章節要學的內容了。

學完了輸出與資料型態,那輸入怎麼辦?放心,輸入與輸出是一體兩面的,基本上輸出學好了,稍稍動一點手腳,就是輸入了。那為什麼是先學輸出?要是不先會輸出,就不知道結果了!其實我們可以在原始碼內把要的參數放進去,這就是輸入了,但這不實際,因為最後呈現在使用者前的不是原始碼,而是一個執行檔,對你而言也許是一個介面,因此就要有輸入了。

一、格式化

不到各位好不好奇,為何是printf,而不是print?因為f代表的是format,即為格式化的意思。由此可知,C很注重格式與資料型態(是強型語言,反之即為弱型語言)。在這一小節裡,我們將認識如何格式化輸入/輸出。這裡有一個插曲,有些時候不用特別格式化是為什麼?因為我們會把一些未定義格式視為某一種格式,如前述的1+1就先被視為字串。

在學完格式化後,接著將會學輸入、輸出,而格式化會扮演重要角色喔。

常見如下:

  • 整數:以%d表示,表示整數,遇到小數點會被進位或捨去。
  • 長整數:以%ld表示,表整數,可以表較多位的整數,遇到小數點會被進位或捨去。
  • 短整數:以%hd表示。
  • 浮點數:以%f表示,整數、浮點數都行。%a.bf指的是輸出a位數數字(如1.2為兩位),b是指輸出小數點一下b位。
  • 字元:以%c表示,主要是輸入英文字母,會被當成ASCII碼處理。通常可用於將輸出ASCII碼或是輸入的字轉換成ASCII碼。
  • 字串:以%s表示。
  • 指標:以%p表示,輸出記憶體位址。
  • 科學記號:以%e或%E表示,差別在10的表示法。若是以%e輸出1.02×10^26,會得到1.02e26;若是以%E輸出1.02×10^26,會得到1.02E26。同樣的,若以%4.2E會得到4位數字,小數點一下2位。

輸出ASCII碼,可以輸出8、10、16等進位。若要格式化成8進位,則為%o或%O;若是格式化成10進位,則為%u;若是格式化成16進位,則為%x或%X。而大小寫的差異在於裡頭的英文字母的大小寫,類似科學記號的E和e的差異。

有趣的是,格式化符號間可以插入數字,使其顯示寬度固定,例如%2d代表顯示2位數寬的;但是,若超過2位數,仍會超出,並顯示出來。然後,“+”表示向右對齊,“-”表向左對齊,例如%-2d表向左對齊並保持兩單位寬。

上面介紹的是常見的格式化類別,具體的應用將在下節說明。

二、輸出

輸出常用的是printf輸出文字(當然,亦有其他輸出或輸出方式,例如puts、putchar等,這裡不多做說明)、發聲(對!可以發聲)。

其語法為:printf("格式化符號",變數名稱或運算式),e.g.printf("%d",1+1);輸出2。

我們只要把雙引號內加入格式化符號,再加上一個逗點,加上運算式或變數,便可以完成要求。不過,要注意的是,若要輸出多個運算式或是變數,需要用逗號隔開,且在雙引號中的格式化符號是依序進行的,如:

printf("%d %d %d",1,1+2,3*4);,會輸出1 3 12。

三、運算式

為什麼是講運算式而不是輸入?因為輸入有一個重點,就是變數。

那麼,什麼是變數什麼是常數?變數就是會變的數,常數是固定不變的數。因為輸入時使用者去定義某一代數的值,那個代數就是變數。這裡要澄清一下的是,這裡的“數”、“值”不是單指數學上狹義的數字,還包含文字等(這包含了格式化的內涵)的喔!

在進入運算式前,我們先定義一下“運算式”與“運算子”。運算式是指一般的列式,如A+B;而運算子是指運算式中的符號,如A+B的“+”。

PART 01.一元運算子

常見的運算式如下:

  • 加法:表示a+b
  • 減法:表示a-b
  • 乘法:表示a*b
  • 除法:a/b
  • 取餘:a%b,指的是a除以b的餘數
  • 次方:在C中,我們會使用迴圈或函數進行,沒有特殊運算子處理。

在程式上,有一些不符合數學意義,卻是合法的運算式,常見如下:

  • a=a+b,簡寫成a+=b
  • a=a-b,簡寫成a-=b
  • a=a/b,簡寫成a/=b
  • a=a*b,簡寫成a*=b
  • a=a%b,簡寫成a%=b

那麼,上面的意義是什麼?其實很簡單,又有一些複雜。簡單來說,就是先進行等號右邊的運算,再把結果取代等號左邊的變數。同時,大多也符合數學上的四則運算,若不放心的話,可以加上括號,因為括號是最優先的。有一點要注意的是,等號左右不可以寫相反,因為等號的左邊是一種變數,而等號的右邊相對是常數,常數是不能被變數定義的,所以a+b=a是不合法的宣告。

因此,可以說:變數=常數(需被定義出一個值)之間的運算。

PART 02.二元運算子(1) 

有一點很特別的,數學上表達關係的符號在C上有一些不同。

  • 等於:意思即為數學上的“相同”。C以“==”表示。
  • 不等於:意即為數學上的“不同”。C以“!=”表示。 
  • 大於:C以“>”表示。
  • 小於:C以“<”表示。
  • 大於等於:以“>=”表示。
  • 小於等於:以“<=”表示。

請注意:i,j=10,11; 是錯誤的語法。

接著來認識既熟悉有陌生的進位制,在此會介紹2、10進位制。如下:

十進位制:

定義:滿十進一位。

實例:153(是10進位)以十進位表示。

153÷10=15•••3

15÷10=1•••5

1÷10=0•••1

接著把餘數由下到上念一遍便是153。若逆向回推可得:1×10^2+5×10^1+3×10^0。

2進位制:

定義:滿二進位。

實例:153(十進位)以2進位表示。

153÷2=76•••1

76÷2=38•••0

38÷2=19•••0

19÷2=9•••1

9÷2=4•••1

4÷2=2•••0

2÷2=1•••0

1÷2=0•••1

接著把餘數由下到上讀一遍,的10011001。同理,回推可得:(由上而下的餘數)1×2^7+0×2^6+0×2^5+1×2^4+1×2^3+0×2^2+0×2^1+1×2^0=153

至於其他進位制的概念是相同的,以16進位為例,10就是A、11是B...,把除數改成16;同理,36進位的話A是10、B是11、...Z是36,把除數改成36。有趣的可以自行嘗試。

PART 03.二元運算子(2)(位元運算子)

接下來來位元運算子,在進行位元運算前,要先知道兩個概念,一是數學上集合的意義(若不懂得建議先去認識,以便了解接下來的內容,在此不贅述),二是二進位制,因為二進位制只有0、1,也算是一種相對的存在(有和沒有的感覺)。而進行運算時基本上是0和1的關係進行計算,先把數字轉換成二進位制,接著每一位數互相比較,以十進位來講好了,就是兩數的個位數與個位數比,十位數與十位數比,依此類推。常見如下(以兩數運算為例):

  • AND運算:在C以&表示。兩者皆為1或0才是1(true),其他皆是0(false)。
  • OR運算:在C以|表示。兩數只要有一個有1即使1(true),兩個皆為0才是0(false)。
  • NOT運算:在C以!表示。把1變0,0變1。
  • XOR運算:在C以^表示。1和1為0,0和0為0,1和0或0和1為1。

再接著是平移,就是把二進位制的數字進行平移,大原則是缺位補零,被擠出的去掉。

  • a>>b:a右移b單位。如11011右移兩單位得到00110。e.g. a>>=b 或 a=a>>b
  • a<<b:a左移b單位。如111001左移3單位得到001000。e.g. a<<=b 或 a=a<<b

在這個小節有一點要注意的是,一般而言,若後面用運算式重新定義了前面已經定義好的變數,則後面定義的變數會覆蓋前面定義的變數。 

最後,先在這裡埋下一個伏筆,就是關係(邏輯)運算子。它是用來進行運算式之間的關係判斷,後面章節會再提到流程控制時,會在詳細說明。

四、變數的宣告

在前面的章節講過或許可以體會到寫程式,尤其是C,在進行一些運算要先進行宣告(告知電腦我要什麼,配多少記憶體等),而進行運算而要賦予某變數名稱為某一值也要進行宣告,就好數學上的代數,我們可以先說x、y等於什麼,在進行運算,如x+y。

語法:資料型態 變數名稱;

e.g.int i=0;/*可以在宣告變數時宣告一個常數*/ 或 int i;

但有一點是要注意的,在變數的命名上建議是有意義的字,以便後續處理(例如有一大堆變數,由於名稱不規則,導致不知道自己在幹嘛)。二是不要空格,因為空格(空白字元)對編譯器而言會不知道如何處理或出錯,若要空格,則建議以底線代替。三是避免使用保留字,保留字就是在進行程式編輯時,會用到的具有控制性、功能性的字,如:char、short、int、unsigned、long、float、double、struct、union、void、enum、signed、const、volatile、typedef、auto、register、static、extern、break、case、continue、default、do、else、for、goto、if、return、switch、while、sizeof等。

值得一提的是,字串的宣告是要用中括號宣告字元數量,例如:

char words[1000];//宣告一個字串陣列words,會放最多1000個元素。又因為結尾會有'\0',因此最多只可以放999個字
 

五、輸入

終於要來講輸如了,其實輸入和輸出是一體兩面,且輸出稍稍複雜了一點。

語法:scanf("格式化字元",&變數名稱);

e.g.scamf("%d",&a);

可以注意到,在輸入時,有加了一個&(取址運算子),那就是指輸入值被定位到某一變數名稱。同樣的,還有其他寫法,如getchar、gets等,這裡就不多作介紹了。

若要多重輸入,可以在雙引號中放入多個格式化字元,若格式化字元間沒有任何空格或符號的話,只要輸入一個值按一次tab鍵或空白鍵或enter鍵即可。同理,若格式化字元間有其他符號、字元,代表輸入時要隔一個該符號、字元。

當然還有其他細節,因為筆者才疏學淺,加上入門使用頻率較低,故就不多做介紹了。

六、綜合範例

1.請輸出1+1=2。

答:

#include<stdio.h>

int main()

{

    printf("1+1=%d",1+1);

    return 0;

}
2.請讓使用者分別輸入兩個數字,中間隔一個×,讓使用者輸出a×b

答:

#include<stdio.h>

#include<stdlib.h>

int main()

{

    int a,b;//宣告變數

    scanf("%d×%d",&a,&b);//輸入

    printf("%d×%d=%d",a,b,a*b);//輸出

    return 0;

}
3.請讓使用者輸入一串字串,如XXX,並輸出「歡迎XXX到訪」。

答:

#include<stdio.h>

#include<stdlib.h>

int main(){

    char name[10000];//要將名字存放到陣列裡,因為C無法直接處理字串。第一個中括號是可輸入的字母數量。

scanf("%s",&name);//輸入時不包含空格

printf("歡迎%s的到訪",name);

return 0;

    }

4.當a=3,b=4時,請執行a+=b*=a*=a/=b+a-b*a。

#include<stdio.h>

#include<stdlib.h>

int main(){

    int a=3,b=4;

    printf("%d",a+=b*=a*=a/=b+a-b*a);

    return 0;

    }

5.令a=10,b=9。請輸出a+=b、a-=b、a*=b、a/=b、a%=b、a>>b、a<<b

#include<stdio.h>

int main()

{

    int a=10,b=9;

    printf("%d\n%d\n%d\n%d\n%d\n%d\n%d\n",a+=b,a-=b,a*=b,a/=b,a%=b,a>>b,a<

6.令a=9,b=10。輸出a&b、a|b、a!b、a^b。

#include<stdio.h>

int main()

{

    int a=10,b=9;

 printf("%d\n%d\n%d\n%d\n",a&b,a|b,a!b,a^b);

    return 0;

}

7.請宣告一個常數,並且輸出該常數

#include<stdio.h>

#include<stdlib.h>

#define pi 3.1415926//注意,沒有=號和分號

int main(){
    printf("%f",pi);
    return 0;
    system("pause");
}

另解

#include<stdio.h>

#include<stdlib.h>

const float pi=3.1415926;//和define用法不同的是,const要具備資料型態、變數名稱、等號、值、分號

int main(){
    printf("%f",pi);
    return 0;
    system("pause");
}

七、實力挑戰

PART1.概念題

(一)是非題

  1. 變數的命名可以隨意命名。
  2. 在二進位制中,0不可能在開頭。
  3. 字元和字串是相同的
  4. %E可以輸出科學記號。

(二)偵錯題


1.以下是程式碼的片段,請問有何錯誤(假設片段以外的是正確的)?

printf(%d);

2.小明想要輸入完後按enter鍵,把結果輸出在下一行(輸入為第一行,而輸出要再第三行),但不知為何要多按一次enter鍵,可不可以少按一次enter鍵?並且達到要求?請把程式碼打出來,並執行及寫下來。小明的程式碼如下:

#include<stdio.h>

#include<stdlib.h>

int main(){

    int a;

    scanf("%d\n",&a);

    printf("%d",a);

    return 0;

    }
3.請偵錯。小明想輸出「hello world\」,但有錯誤。
#include<stdio.h>

#include<stdlib.h>

int main(){

    printf("hello world\");

    return 0;

    }
4.請計算13527以二進位如何表示。

PART2.實作挑戰

請讓使用者輸入攝氏溫度,並輸出華氏溫度,要小數點以下2位。要換行,且要有提示詞。

輸入:攝氏溫度:-40

輸出:華氏溫度:-40

2.讓使用者輸入直徑,求出圓周長、圓面積。輸出圓周長並水平跳格2次輸出圓面積,並且不用提示詞。圓周率=3.14

輸入:2

輸出:6.28 3.14

這裡說明一下的是,這裡暫不給參考答案,一是題目偏易,二是給了會限制思考,因為程式無固定寫法。

回目錄

沒有留言:

張貼留言