National Yunlin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

雲林科技大學 AQI 56 27°C PM2.5 10
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 03

變數與資料型態

整數、浮點數、字元與布林,大小、範圍與型別轉換
Interaction實作 20 minute(s)

Learning Objectives

  • 宣告 int、long long、double、float、char、bool 變數,並說明各自適合存放的資料
  • 用 sizeof 與 numeric_limits 查看型態的大小與範圍,說明整數溢位
  • 說明 char 存的是字元編碼(ASCII),能用編碼做大小寫與數字字元的轉換
  • 分辨隱含轉換與 static_cast 明確轉型,避開整數除法造成的錯誤
  • 使用 const、auto 與三種初始化寫法,並說明區域變數沒有初始化的風險

為什麼要在意資料型態

變數是記憶體裡一塊有名字的空間,用來存放資料。C++ 的每個變數都要先宣告型態,型態決定三件事:

  1. 這塊空間有多大(佔幾個位元組)
  2. 能存放的值的範圍(例如 int 最大約 21 億)
  3. 能做哪些運算、運算的方式(整數相除和小數相除的結果不一樣)
int age = 19;        // 型態 變數名稱 = 初始值;

選錯型態不一定會編譯失敗,卻可能算出錯誤的結果:數字太大裝不下、小數被捨去。這一課看清楚每種型態的特性。

變數名稱的規則:由英文字母、數字、底線組成,不能以數字開頭,不能用 int、return 這類關鍵字,大小寫有別。 習慣上用有意義的英文,例如 studentCount 或 student_count,不要用 a1、tmp2。

基本資料型態

型態 存放 例子 常見大小
int 整數 19、-3 4 位元組
long long 範圍更大的整數 8000000000LL 8 位元組
double 浮點數(小數),倍精度 172.5、3.0 8 位元組
float 浮點數,單精度 63.2f 4 位元組
char 一個字元 'A'、'7'、' ' 1 位元組
bool 真假值 true、false 1 位元組

幾個細節:

  • 字元用單引號 'A',字串用雙引號 "A";字串是 std::string,不是基本型態
  • 小數預設是 double;要寫 float 的常數,在後面加 f
  • cout 印 bool 時預設顯示 1 或 0,加上 boolalpha 才會顯示 true、false
  • 大小由編譯器與平台決定,C++ 標準只規定最小值;表中是 Linux x86-64 上 g++ 的大小。要確定就用 sizeof 查

宣告變數與 sizeof

右邊的變數區會在每一行宣告完成後多出一個變數,並顯示它的值。注意 passed 在變數區顯示 true,但第 14 行用 cout 印出來是 1。最後三行用 sizeof 印出各型態佔幾個位元組。

範圍與溢位

4 個位元組有 32 個位元,int 能表示的範圍是 -2,147,483,648 到 2,147,483,647(約正負 21 億)。 long long 有 64 個位元,最大約 9.2 × 10¹⁸。用 <limits> 的 numeric_limits<型態>::max() 可以查到確切的值。

運算結果超出範圍叫做溢位(overflow)。有號整數溢位在 C++ 是未定義行為:常見的結果是「繞回去」變成負數, 但標準不保證,編譯器也不會在執行時提醒你。預期數字會很大(人口、金額以分計、階乘)時,就改用 long long。

浮點數則是精確度有限:float 大約 7 位有效數字、double 大約 15 位。小數在電腦裡多半無法精確表示, 所以一般計算用 double,不要用 == 比較兩個算出來的小數是否相等(第 4 課會再看到)。

溢位與精確度

第 11 行 biggest + 1 超出 int 的範圍,動畫會顯示警告,並用常見的繞回結果繼續執行。第 13~14 行先把值放進 long long 再加 1,就裝得下了。最後兩行用 12 位有效數字印出 1/3,看 float 從第幾位開始不準。

char 與 ASCII

char 存的其實是一個整數編碼,印出時才顯示成對應的字元。英文字母、數字、標點使用 ASCII 編碼:

字元 編碼 字元 編碼
'0'~'9' 48~57 ' '(空白) 32
'A'~'Z' 65~90 'a'~'z' 97~122

因為編碼是連續的,可以直接用運算處理字元:'A' + 1 是 'B' 的編碼,'a' - 'A' 是 32, '7' - '0' 是 7。注意 char 和 int 一起運算時,結果是 int,用 cout 印出來會是數字;要印成字元, 先存回 char 變數,或寫 char(…) 轉回字元。

一個 char 只有 1 個位元組,放不下中文字;中文要用 string 存放(UTF-8 編碼下一個中文字通常佔 3 個位元組)。

用編碼處理字元

比較第 10 行和第 11 行:同樣是 letter + 1,存進 char 變數再印,顯示 B;直接印運算結果,顯示的是數字 66。

想一想:型態、範圍與字元

1.

下面的程式會印出什麼?

char c = 'C';
cout << c + 2;
2.

在 Linux x86-64 上用 g++ 編譯,下面的程式會印出什麼?

cout << sizeof(int) + sizeof(double);
3.

要存放全世界的人口數(約 80 億),用哪個型態最合適?

第 1 次作答

型別轉換

不同型態的值放在一起時,C++ 會自動轉換,叫做隱含轉換:

情況 結果
double price = 30; int 轉 double,沒有損失
int count = 3.99; double 轉 int,小數直接捨去(不是四捨五入),得到 3
bool flag = 5; 0 轉成 false,其他數字都是 true
int 和 double 一起運算 int 先轉成 double,結果是 double

最常見的錯誤是整數除法:兩個 int 相除,結果還是 int,小數部分被捨去。double avg = 7 / 2; 會得到 3, 因為 7 / 2 在存進 avg 之前就已經算成 3 了。

要明確地轉換型態,用 static_cast<目標型態>(值):

double avg = static_cast<double>(total) / people;   // 先把 total 轉成 double,再做小數除法

你可能也會看到 C 語言的寫法 (double)total,效果相同;C++ 建議用 static_cast,比較容易搜尋,意圖也比較清楚。

隱含轉換與 static_cast

注意第 10 行和第 11 行的差別:avg1 的除法發生在轉型之前,只得到 3;avg2 先轉型再除,得到 3.5。

初始化、const 與 auto

初始化的三種寫法,效果相同:

int a = 5;
int b(6);
int c{7};     // 大括號初始化(C++11)

大括號初始化比較嚴格:int c{3.5}; 會編譯錯誤,因為 double 轉 int 會損失資料(稱為縮窄轉換); int c = 3.5; 則只會悄悄捨去小數。用大括號可以讓編譯器幫你抓出這類錯誤。

const:宣告時給值,之後不能再改,改了就是編譯錯誤。用在不會變的數值(稅率、圓周率、班級人數上限), 名稱常用全大寫,例如 const double TAX_RATE = 0.05;。

auto(C++11):讓編譯器依初始值推斷型態,auto qty = 4; 是 int、auto price = 120.0; 是 double。 auto 變數一定要有初始值;推斷出來的型態宣告後就固定,不會變。型態名稱很長時(例如第 11 課標準模板庫的迭代器)特別好用。

沒有初始化的區域變數:在函式裡寫 int sum;,C++ 不會自動設成 0,裡面是那塊記憶體之前留下的值(垃圾值)。 讀取它是未定義行為。養成習慣:宣告時就給初始值。

初始化、const、auto 與未初始化的變數

sum 宣告時沒有給值,變數區顯示「?」。第 15 行讀取它時,動畫會停下來說明。真正的程式不會停,而是拿垃圾值去算,印出一個看不出道理的數字;每次執行還可能不一樣。

想一想:轉換與初始化

1.

下面的程式會印出什麼?

int a = 7, b = 2;
double r = a / b;
cout << r;
2.

下面的程式執行結果是什麼?

int x{2.5};
cout << x;
3.

下面的程式會印出什麼?

auto p = 9 / 2;
auto q = 9 / 2.0;
cout << p << " " << q;
第 1 次作答

動手寫:溫度換算

把攝氏 37 度換算成華氏(華氏 = 攝氏 × 9 ÷ 5 + 32),並把單位字元 f 轉成大寫 F。預期輸出:

37 C = 98.6 F
你的輸出
預期輸出

重點回顧

  • 變數要先宣告型態:int、long long 存整數,double、float 存小數,char 存一個字元,bool 存 true/false
  • sizeof 查大小、numeric_limits<T>::max() 查範圍;int 約正負 21 億,超出範圍會溢位(有號整數溢位是未定義行為)
  • char 存的是編碼:'A' 是 65、'a' 是 97、'0' 是 48;char 與 int 運算的結果是 int
  • double 轉 int 會捨去小數;兩個 int 相除是整數除法,要小數結果就先用 static_cast<double>(…) 轉型
  • int c{7}; 大括號初始化會擋下縮窄轉換;const 宣告後不能改;auto 依初始值推斷型態
  • 區域變數不會自動設成 0,宣告時就要給初始值
這一課完成了!
Next lesson:運算子
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。