講師: 李根逸 (Ken-Yi Lee), E-mail: feis.tw@gmail.com
資料型態、運算子與表示式
【第⼆二講】
!49
課程⼤大綱
!50
資料型態 [P.51]
C/C++ 內建的常⾒見資料型態 [P.52]
使⽤用 sizeof 看⼤大⼩小 [P.53]
變數宣告 [P.54]
不同資料型態間的差異 [P.55]
整數 (short int, int, long int) 的可表⽰示範圍 [P.56]
浮點數 (float/double) 的表⽰示法 [P.58]
printf 與 scanf 的格式字串 [P.59]
字⾯面常數的型態 [P.61]
不同型態間的轉換 (隱性/顯性轉型) [P.62]
字元 (char) 的表⽰示法 [P.65]
各種常⾒見運算⼦子:
算數運算⼦子: +-*/% [P.69], 指定運算⼦子: = [P.70]
關係與等號運算⼦子: <, >, <=, >=, ==, != [P.72]
邏輯運算⼦子 [P.73]
運算⼦子優先順序 [P.74]
資料型態 (Data type)
在⾼高階語⾔言中,為了能夠⽅方便有效 (省時省空間) 的 撰寫程式碼並做出各種複雜的運算,我們需要使⽤用多 種資料型態
例如 : 整數, ⼩小數和⽂文字處理等 ...
電腦內部是使⽤用位元 (Bit) 這個基本單位來表⽰示資料 並儲存於記憶單元 (記憶體) 或輔助記憶單元 (硬碟) 中。
每個位元只可以表⽰示 0 或 1 兩種值
任何資料型態的資料都可以轉換成由⼀一串位元來表⽰示
換句話說,資料型態就是要告訴電腦要怎麼去解釋某⼀一 串位元資料,我們可以規定如何對不同的型態做運算
!51
C 常⾒見的內建資料型態
資料型態 名稱 ⼤大⼩小
(bytes)
範例
短整數
(Short Integer)short int 2 32
整數
(Integer)int 4 32
⻑⾧長整數
(Long Integer)long int 4 32
字元
(Character)char 1 ‘3’
單精度浮點數
(Single Precision Floating Point)
float 4 3.2
雙精度浮點數
(Double Precision Floating Point)
double 8 3.2
無 void (無) (無)
!52
⼤大⼩小是《實作相依》
《實作相依》:意指語⾔言標準內容並沒有強制的規定,
在使⽤用不同編譯器或設定的情況下,可能會不⼀一樣
使⽤用 sizeof 看⼤大⼩小
語⾔言標準內對資料型態沒有嚴格定義⼤大⼩小,隨著編譯 器與設定的不同⽽而可能不同。我們只知道在同樣的編 譯器與設定中,同樣資料型態的⼤大⼩小是固定的。
例如 int 不⼀一定要是 4 個位元組⼤大,只是我們現在⼀一 般的電腦架構與作業系統通常是。⽽而在 32-bit 編譯器 內, long int 的⼤大⼩小可能是 4 個位元組, 但在 64- bit 編譯器中, long int 的⼤大⼩小可能是 8 個位元組
sizeof 是⼀一個特殊的運算⼦子,會得到某變數或資料 型態在該平台編譯後佔有記憶體的⼤大⼩小。我們表⽰示記 憶體⼤大⼩小所使⽤用的單位是位元組 (byte) ,⽽而⼀一個位 元組 (byte) 通常等於⼋八個位元 (bit)
開啟範例檔 sizeof.cpp 並執⾏行看看
!53
變數宣告
變數名稱在使⽤用前,需要先進⾏行宣告讓編譯器知道:
資料型態 變數名稱;
資料型態 變數名稱 = 初始值;
保留字 (keywords):
C 語⾔言中下列名稱 (保留字) 無法作為變數名稱
auto,break,case,char,const,continue,default, do,double,else,enum,extern,float,for,goto,if, int,long,register,return,short,signed,sizeof, static,struct,switch,typedef,union,unsigned, void,volatile,while
int num;
int num = 0;
名稱通常為英⽂文字⺟母⼤大⼩小 寫、數字和底線構成,數 字不能開頭,⼤大⼩小寫不同 也代表不同的名稱
num
(int)
?
2293620 (記憶體位址)
!54
在宣告時給予初始值這動作我們稱為初始化
表⽰示的資料意涵不同:
整數 (int) 與字元 (char)
表⽰示的原理不同:
整數 (int) 與浮點數 (float)
可表⽰示的範圍⼤大⼩小不同:
短整數 (short int) 與⻑⾧長整數 (long int)
可表⽰示的精確度⼤大⼩小不同:
單精度浮點數 (float) 與倍精度浮點數 (double)
有無正負數 (有號與無號)
有號整數 (int) 與無號整數 (unsigned int)
不同資料型態間的差異
與⼤大⼩小有關
!55
整數型態的可表⽰示範圍
資料型態可表⽰示的範圍與他佔記憶體的『⼤大⼩小』有關
每個位元可以表⽰示兩種值 (0 或 1) 每個位元組如果有 8 個位元 :
每個位元組可以表⽰示
2
8 =256
種值在可表⽰示正負數 (即有號 [signed]) 的情況下,可表⽰示的整數範圍 會是從 -128 到 127 (共 256 個數字)
當無號 [unsigned] 時,可表⽰示的整數範圍是從 0 到 255
如果⼀一個資料型態有 4 個位元組,則可以表⽰示 :
2
8x4 =2
32 =4,294,967,296
種值4 個位元組⼤大的 int 可表⽰示範圍是從
−2,147,483,648
到2,147,483,647 (約九位數有效數字)
4 個位元組⼤大的 unsigned int 的可表⽰示範圍就是從
0
到4,294,967,295 (約九位數有效數字)
!56
運算結果超出可表⽰示範圍 稱為『溢位』,在溢位的 情況下,值會變多少⼤大部 分情況是《未定義⾏行為》
不要因為 範圍可以
⼤大⼀一點就
⽤用無號數
【補充】 int 的位元表⽰示法
!57
⼗十進位表⽰示法 ⼆二進位表⽰示法
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 1 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 1 0 1 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 1 1 1 1 1 1 1 1 256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 2147483647 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 -2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 0 -255 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 0 0 0 0 0 0 0 1 -2147483648 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 負數⽤用 2 的
補數表⽰示法: 將正數表⽰示 法的 0 和 1 互換後再加 1
32 bits (4 bytes)
如何表⽰示整數是《實作相依》⾏行為,這裡只是列出⼀一般的作法作為參考
浮點數表⽰示法
浮點數 (floating point) 是⽤用來將實數數位化表⽰示 的⼀一種表⽰示法
我們現在所⽤用的是由 IEEE 制定的浮點數表⽰示標準
簡單來看,浮點數的表⽰示法將位元分成三個區塊
符號位元 (1 Bit), 指數部分, ⼩小數部分
0 0 0 1 1 1 1 0 0 0 0 1 1 0 1 1
0 0 0 1 1 1 1 0 0 0 0 1 1 0 1 1
+ 3 1563
+ 0.1563 ✕ 10 3
(指數)
(符號) (有效數字) [影響精確度]
(實際上格式⽐比較複雜,這裡只是個概念的說明。細節可參考 http://goo.gl/imXGf)
7707
!58
float 有效數字約6位,double 約15位
printf 與 scanf 的格式字串
資料型態 名稱 格式符
短整數 (Short Integer)
short int %hd
整數 (Integer)
int %d
⻑⾧長整數 (Long Integer)
long int %ld
字元 (Character)
char %c
單精度浮點數
(Single Precision Floating Point)
float %f
雙精度浮點數
(Double Precision Floating Point)
double %f, %lf
!59
printf scanf
【範例】使⽤用浮點數
請修改程式讓使⽤用者分別輸⼊入三個整數後,算出三個 整數的和、平均值、乘積並顯⽰示給使⽤用者看 (四捨五
⼊入到⼩小數點後三位 )
注意: 平均值可能具有⼩小數⽽而且使⽤用者可能輸⼊入的數值 帶有⼩小數
變數宣告時須改為⽤用 float 宣告
scanf 和 printf 須使⽤用 %f 來讀⼊入或輸出 float printf 的格式字串可以加上數字表⽰示位數
%.3f 表⽰示印出浮點數並四捨五⼊入到⼩小數點後第三位
!60
【範例】 calc.cpp
字⾯面常數的型態
字⾯面 資料型態 名稱
3 整數
(Integer)long int int
3u 無號整數
(Unsigned Integer)unsigned int
3l ⻑⾧長整數
(Long Integer)long int
3. 雙精度浮點數
(Double Precision Floating Point)double
3.f 單精度浮點數
(Single Precision Floating point)float
‘3’ 字元
(Character)char
!61
【補充】在能表⽰示的 情況下整數選前者
【範例】 constant.cpp
不同型態間的轉換
編譯器為了讓你的運算式合理,可能會試著幫你做型 態的⾃自動轉換 (隱性轉型)。
不同基本資料型態間的⾃自動轉換 (隱性轉型) 通常以
『可表⽰示範圍⼤大』的為準
例如 :
4 / 3 時,計算結果的資料型態會是 int
4 / 3. 時,4 是 int ⽽而 3. 是 double。計算時會先將 4 轉換成 double 後再除以 3.,計算結果資料型態是 double。
你也可以⽤用強制的⽅方式進⾏行型態轉換 (顯性轉型):
例如:
4 會先被強制轉換為 double 型態 (即 4. ),再試著去除以 3,此時 3 也被動的隱性轉型成 double 型態 (即 3.)。計算結果的資料型態 會是 double
4 / 3 與 4 / 3.
(double) 4 / 3
!62
【範例】隱性轉型與格式
請開啟範例檔,並猜測執⾏行結果 提⽰示與解釋:
A = B 是指將 B 的值給 A,此時如果 B 的型態與 A 不 同則可能會造成無法編譯或發⽣生隱性轉型將 B 轉為 A 的型態
轉型時,浮點數轉為整數是無條件捨去,通常值會變得不精確
要⼩小⼼心的是,使⽤用 printf 或 scanf 時,輸⼊入的引數並 不會⾃自動的轉型
例如: printf(“%d”, 3.);
會因為 3. 是 double 卻當成 int 印⽽而失敗,產⽣生不易預期的結果 printf 跟 scanf 這算是特例中的特例,但是我們常常使⽤用到。
!63
【範例】 casting.cpp
【範例】⼤大數計算
試寫⼀一程式輸⼊入兩個五位數整數後輸出他們的乘積
int 的資料型態⼀一般情況下約可表⽰示 log(231) ~ 9 位有 效整數
【補充】使⽤用範圍更⼤大的整數型態
C++99 (新版 C++ 標準) 和 C99 (新版 C 標準) 中有
⼀一個 long long int 的資料型態⾄至少可表⽰示約 log(263)
~ 19 位有效整數
在 Dev C++ 中,請在 printf 內使⽤用 %I64d 來列印 long long int 型態數值
在 GCC 編譯器中,long long int 是⼀一個語⾔言擴充功能
!64
【範例】 bignum.cpp
‘A’+1=?
(char) (int)
‘A’-1=?
(char) (int)
‘A’+’1’=?
(char)(char)
(???)
(???)
(???)
在輸⼊入、儲存和運算時,char 都是使
⽤用整數(ASCII值)格式,只有在輸出 (顯⽰示或列印) 的時候會依照該 ASCII 值所對應的⽂文字套⽤用字型後輸出
【範例】 char.cpp 字元 (char) 是⼀一種整數型態
【範例】⼤大⼩小寫轉換
試寫⼀一程式輸⼊入⼀一⼤大寫英⽂文字元,顯⽰示相對應的⼩小寫 英⽂文字元
提⽰示:
!66
範例輸⼊入⼀一 :
A
範例輸出⼀一 :
a
範例輸⼊入⼆二 :
B
範例輸出⼆二 :
b
範例輸⼊入三 :
Z
範例輸出三 :
z
char input = ?;
char output = input - ‘A’ + ‘a’;
【範例】 tolower.cpp
【補充】關於字元
就前⾯面的解釋我們了解字元的處理⽅方式是利⽤用建表編 號的⽅方法來達成。但在 C/C++ 語⾔言標準中並沒有 強制規定字元所使⽤用的編號表格 (只規定要能表⽰示其 中 95 個字元),像是⼀一般電腦⽤用的是 ASCII 或是 ISO/IEC 646 的編碼標準都是可能的。
⼀一個字元 (char) 原則上由⼀一個位元組構成,但是⼀一個 位元組並不⼀一定是有 8 位元 (某些古⽼老或特別的電腦結 構)
⽽而也因為未嚴格規定編碼表格, char 資料型態不⼀一 定等價於 signed char 或 unsigned char,此為
《實作相依⾏行為》。
!67
使⽤用型態的選擇
那麼我們到底應該選擇怎樣的資料型態呢?
!
!
!
!
!
對於初學者只要熟悉使⽤用這些資料型態就夠了
其他型態的⽤用途?
最佳化記憶體的使⽤用或效率
⽤用途 資料類型 格式符
整數 (⼀一般情況) int %d
浮點數 (有⼩小數或位數過⼤大) double %f %lf
字元 char %c
printf scanf
!68
算術運算⼦子 : +-*/%
算術運算⼦子運算的結果與運算元的值跟型態有關
運算⼦子是有優先順序的 (*/% 優先於 +- ) 算術運算⼦子優先順序相同時,在左邊的先
每次執⾏行⼀一個運算⼦子時就會產⽣生⼀一個中間結果,我們 稱為『暫時變數』,我們要了解這暫時變數的『值』
與『型態』:
A = 3 * ( 2 + 1 ) + 7 / 2 + 9 * 3.;
A = 3 * 3 + 7 / 2 + 9 * 3.;
A = 9 + 7 / 2 + 9 * 3.;
A = 9 + 3 + 9 * 3.;
A = 9 + 3 + 27. ; A = 12 + 27. ; A = 39. ;
!69
【範例】賦值運算⼦子 : =
= 為賦值運算⼦子
賦值運算⼦子會將右⽅方的值給左⽅方的變數
賦值運算⼦子的左⽅方⼀一定要放置某個變數。
賦值運算⼦子的運算結果就是左⽅方變數最後的值跟型態
運算優先順序
賦值運算⼦子 (=) 的運算優先順序是全部裡⾯面最低的⽽而 且運算順序是由右⾄至左 (特別!)
int A,C;
double B, D;
A = 3;
3 = A;
A = C = 3;
A = B = C = D = 3 + 7 / 2.;
!70
【範例】 assign.cpp 這結果會是什麼?
!
!
!
!
!
在⼀一般 C 語⾔言標準 (C89/C90) 中,我們使⽤用 int 型態來儲存是⾮非真假對錯:
0 表⽰示假的、錯誤和不成⽴立的意思 1 表⽰示真的、正確和成⽴立的意思 2 表⽰示真的、正確和成⽴立的意思 -1 表⽰示真的、正確和成⽴立的意思
是⾮非真假
!71
運算結果 意
不是 0 真的 正確 成⽴立
0 假的 錯誤 不成⽴立
【補充】在 C++ 中,也可以⽤用 bool 資料類型來表⽰示
在 C 語⾔言標準中,關係與等號運算⼦子的運算結果有 不是 0 (成⽴立) 和 0 (不成⽴立) 兩種可能:
關係與等號運算⼦子
運算意義 運算符號
⼤大於 >
⼩小於 <
⼤大於等於 (不⼩小於) >=
⼩小於等於 (不⼤大於) <=
等於 ==
不等於 !=
!72
4 > 3 4 < 3 4 == 3 4 != 3
4 > 3 > 2
【補充】在 C++ 中,運算結果是 true 與 false 兩種可能
邏輯運算⼦子
在 C 語⾔言標準中,邏輯運算⼦子的運算結果有不是 0 (成⽴立) 與是 0 (不成⽴立) 兩種可能:
運算意義 運算符號 iso646.h
C++
⽽而且 (and) &&
and
或者 (or) ||
or
⾮非 (not) !
not
!73
4 > 3 && 4 < 3 4 > 3 || 4 < 3
3 > 2 && 1 > 2 1 || 0
4 > 3 && 3 > 2
!(3 > 2)
!3
運算⼦子優先順序表
運算符號 平⼿手時運算順序
( )
由左⾄至右!
由左⾄至右* / %
由左⾄至右+ -
由左⾄至右< > <= >=
由左⾄至右== !=
由左⾄至右=
由右⾄至左&& 由左⾄至右
|| 由左⾄至右
優先
不優先
!74
【補充】邏輯運算⼦子的特殊性
|| 與 && 運算⼦子都保證左邊運算元被算出後,才會 開始算右邊運算元的值。
其他運算⼦子不是喔!之前我們只保證運算⼦子的運算順序
|| 左邊運算元算出為⾮非 0 時,就不會去算右邊運 算元的值。反之當 && 左邊運算元算出為 0 時,就 不會去算右邊運算元的值。
為什麼可以這樣?
!75
if 關鍵字
if( 表⽰示式 ) { ... }
如果 表⽰示式 為真就 ...
什麼是真或假?
⾮非0 或 0、成⽴立或不成⽴立
if (80 >= 60) {
printf(“PASSED !\n”);
}
if (80 < 60) {
printf(“FAILED !\n”);
}
int grade = 80;
if (grade >= 60) {
printf(“PASSED !\n”);
}
if (grade < 60) {
printf(“FAILED !\n”);
}
!76
【範例】⽐比較兩數⼤大⼩小
試寫⼀一程式讓使⽤用者輸⼊入兩個數字後顯⽰示其中⽐比較⼤大 的給使⽤用者看 :
提⽰示 : (程式⽚片段)
請輸⼊入第⼀一個整數 : 3 請輸⼊入第⼆二個整數 : 4
⽐比較⼤大的整數是 : 4
int max;
if (num1 >= num2) { max = num1;
} if (num1 < num2) { max = num2;
}
printf(“⽐比較⼤大的整數是 %d\n”, max);
!77
【範例】 cmp.cpp
【練習】簡易版猜數字
試寫⼀一個程式,在程式內部預設⼀一個整數作為猜數字 遊戲的答案。當使⽤用者執⾏行程式後,需要輸⼊入⼀一個整 數,如果該整數與程式預設的答案不同,請顯⽰示是⽐比 較⼤大或者⽐比較⼩小;如果該整數與程式預設的答案相同,
請恭喜使⽤用者:
!
!
!
!
【思考】要如何讓使⽤用者可以⼀一直猜到答案正確?
請輸⼊入你的猜測 : 4 答對了!
!78
請輸⼊入你的猜測 : 5 太⼤大了!
請輸⼊入你的猜測 : 3 太⼩小了!
【補充】逐位元運算⼦子
!79
運算意義 運算符號
逐位元 AND &
逐位元 OR |
逐位元 XOR ^
逐位元 NOT ~
逐位元左移 <<
逐位元右移 >>
習題 [1]
[E0201] 試寫⼀一程式,印出下⾯面這個變數值 :
double x = 3000000000000000.5;
[E0202]* 試寫⼀一程式,印出下⾯面式⼦子的計算結果 :
3000000000000000.5+0.05
[E0203] 試寫⼀一程式,輸⼊入英哩換算後印出公⾥里 (四捨五⼊入⾄至⼩小數點後⼀一位) [公⾥里 = 英哩 * 1.6]
[E0204] 試寫⼀一程式印出 129263*54628 的結果
與 [E0110] 相同
[E0205]* 試寫⼀一程式算出 1292635428 三次⽅方 的值 (2159872744519190546127922752)
!80
習題 [2]
[E0206] 試寫⼀一程式,輸⼊入⼀一有號整數,顯⽰示該整 數是正整數 (>=0) 或負整數 (< 0)
[E0207] 試寫⼀一程式,輸⼊入⼀一字元,顯⽰示該字元是 數⼦子 (0-9)、英⽂文字元 (a-zA-Z) 或其他符號
字元 (char) 請在 scanf 內⽤用 %c 讀⼊入,在 printf 內
⽤用 %c 印出
[E0208] 試寫⼀一程式,輸⼊入⼀一個英⽂文⼩小寫字元,將 字元轉換為⼤大寫印出
[E0209] 試寫⼀一程式,輸⼊入⼀一個英⽂文字元,將字元 的⼤大寫印出 (不限制輸⼊入的字元為⼤大寫或⼩小寫)
!81
習題 [3]
[E0210] 試寫⼀一程式,輸⼊入兩個整數,將兩個整數 由⼩小到⼤大印出。
!
[E0211] 試寫⼀一程式,讓使⽤用者輸⼊入⼀一⼋八位整數然 後將數字直排顯⽰示。
範例輸⼊入⼀一: 3 6 範例輸出⼀一: 3 6 範例輸⼊入⼆二: 6 3 範例輸出⼆二: 3 6
!82
請輸⼊入⼀一個⼋八位數整數: 38603456
3 8
6 0
3 4
5 6
習題 [4]
[E0213] 試寫⼀一程式,讓使⽤用者輸⼊入⾝身分證字號的 前九碼後顯⽰示該⾝身分證字號的第⼗十碼 (驗證碼)
我們的檢查碼計算⽅方式 : (A: 10, B:11, C:12, ..., Z:36)
!
!
!
!
總和 = 1x1 + 0x9 + 1x8 + 2x7 + 3x6 + 4x5 + 5x4 + 6x3 + 7x2 + 8x1 = 121