Ruby @ Sprout 2023
Ruby@Sprout
C++ 小眉角
Ruby@Sprout
C++ 小眉角
Ruby@Sprout
Ruby@Sprout
C++ 小眉角
變數生命週期
生命週期 Life Cycle
Ruby@Sprout
C++ 小眉角 > 變數生命週期
變數生命週期指的是一個變數在程式運行期間存在的時間範圍,也就是
「 從變數被定義和分配空間到
該變數的空間被釋放為止 」
空間分配與釋放??
Ruby@Sprout
C++ 小眉角 > 變數生命週期
設想情境
如果每次執行程式,電腦(作業系統)都要分配記憶體給變數,但執行完畢後卻不會自動釋放空間,會發生什麼事?
執行一百次後的電腦:
空間配置與釋放 Memory Allocation & Releasing
Ruby@Sprout
C++ 小眉角 > 變數生命週期
程式執行
變數宣告
變數操作
READ
作業系統分配給程式的空間
編譯器分配給變數的空間
空間配置與釋放 Memory Allocation & Releasing
Ruby@Sprout
C++ 小眉角 > 變數生命週期
程式執行
變數宣告
變數死亡
變數操作
作業系統分配給程式的空間
編譯器分配給變數的空間
空間配置與釋放 Memory Allocation & Releasing
Ruby@Sprout
C++ 小眉角 > 變數生命週期
程式執行
變數宣告
變數死亡
變數操作
作業系統分配給程式的空間
程式結束
空間配置與釋放 Memory Allocation & Releasing
Ruby@Sprout
C++ 小眉角 > 變數生命週期
程式執行
變數宣告
變數死亡
變數操作
作業系統分配給程式的空間
程式結束
空間配置與釋放 Memory Allocation & Releasing
Ruby@Sprout
C++ 小眉角 > 變數生命週期
程式執行
變數宣告
變數死亡
變數操作
程式結束
以生命週期分類變數——全域及區域變數
Ruby@Sprout
C++ 小眉角 > 變數生命週期
全域變數
Global Variable
區域變數
Local Variable
Outside of function!
Inside of function!
int var = 5;
int main() {
cout << var << endl;
return 0;
}
int main() {
int var = 5;
cout << var << endl;
return 0;
}
全域變數 Global Variable
Ruby@Sprout
C++ 小眉角 > 變數生命週期
int var = 5;
void function() {
cout << var+1 << endl;
}
int main() {
cout << var << endl;
function();
return 0;
}
程式執行,分配空間給 var
在任意函式中皆可存取變數
在主函式中皆可存取變數
程式結束前,釋放 var 空間
區域變數 Local Variable
Ruby@Sprout
C++ 小眉角 > 變數生命週期
void f(int f_var) {
cout << f_var+1 << endl;
}
int main() {
int var = 5;
f(3);
cout << var << endl;
/* 編譯錯誤:f_var尚未定義 */
cout << f_var << endl;
}
main 被呼叫,分配 var 空間
f 被呼叫,分配 f_var 空間
f_var 還未被釋放,可以被存取
f 執行完畢,釋放 f_var 空間
var 還未被釋放,可以被存取
f_var 不在視野內,無法存取
main 執行完畢,釋放 var 空間
視野範圍?
Ruby@Sprout
C++ 小眉角 > 變數生命週期
C++ 小眉角
Ruby@Sprout
C++ 小眉角
Ruby@Sprout
Ruby@Sprout
C++ 小眉角
變數可視範圍
什麼是可視範圍(Scope)?
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
變數的可視範圍指的是在哪些地方可以使用該變數,即變數的有效範圍。C++ 的變數可視範圍被侷限在
「 宣告處最近的外層程式區塊 」
什麼是可視範圍(Scope)?
Ruby@Sprout
全域變數
Global Variable
區域變數
Local Variable
int var = 5;
int main() {
cout << var << endl;
return 0;
}
int main() {
int var = 5;
cout << var << endl;
return 0;
}
C++ 小眉角 > 變數可視範圍
var 的可視範圍
var 的可視範圍
什麼是可視範圍(Scope)?
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
無法於變數的可視範圍外,存取該變數!
void f(int f_var) {
cout << f_var+1 << endl;
}
int main() {
int var = 5;
f(3);
cout << var << endl;
/* 編譯錯誤:f_var尚未定義 */
cout << f_var << endl;
}
f_var 的可視範圍
var 的可視範圍
什麼是可視範圍(Scope)?
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
無法於變數的可視範圍外,存取該變數!
void f(int f_var) {
cout << f_var+1 << endl;
}
int main() {
int var = 5;
f(3);
cout << var << endl;
/* 編譯錯誤:f_var尚未定義 */
cout << f_var << endl;
}
f_var 的可視範圍
var 的可視範圍
不在 f_var 的可視範圍內
f_var 的可視範圍
什麼是可視範圍(Scope)?
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
變數的可視範圍指的是在哪些地方可以使用該變數,即變數的有效範圍。C++ 的變數可視範圍被侷限在
「 宣告處最近的外層程式區塊 」
{
}
什麼是可視範圍(Scope)?
Ruby@Sprout
int main() {
int var = 5;
{
int inside_var = 3;
cout << inside_var << endl;
}
/* 編譯錯誤:inside_var尚未定義 */
cout << inside_var << endl;
return 0;
}
C++ 小眉角 > 變數可視範圍
inside_var 的可視範圍
var 的可視範圍
重疊的可視範圍 Overlapping Scope——遮蔽效應
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
變數的可視範圍重疊,是一件常常發生的事。
若在兩同名變數可視範圍內存取該名字,會發生什麼事?
int var = 5;
int main() {
int var = 3;
cout << var << endl;
return 0;
}
全域 var 的可視範圍
main 中 var 的可視範圍
重疊的可視範圍 Overlapping Scope——遮蔽效應
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
在兩同名變數可視範圍內存取該名字,會存取到範圍最小的
int var = 5;
int main() {
int var = 3;
cout << var << endl;
return 0;
}
全域 var 的可視範圍
main 中 var 的可視範圍
Output: 3
重疊的可視範圍 Overlapping Scope——小試身手
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
int var = 1;
int f(int var) {
return var;
}
int main() {
int var = 2;
{
int var = f(3);
{
int var = 4;
}
cout << "var = " << var << endl;
}
return 0;
}
重疊的可視範圍 Overlapping Scope——小試身手
Ruby@Sprout
C++ 小眉角 > 變數可視範圍
int var = 1;
int f(int var) {
return var;
}
int main() {
int var = 2;
{
int var = f(3);
{
int var = 4;
}
cout << "var = " << var << endl;
}
return 0;
}
Output: 3
C++ 小眉角
Ruby@Sprout
C++ 小眉角
Ruby@Sprout
Ruby@Sprout
C++ 小眉角
修飾子
修飾子 Modifier
Ruby@Sprout
C++ 小眉角 > 修飾子
修飾子是指可以應用於變數、函式、類別等元素的關鍵字,它們可以影響這些程序元素的特性、行為和生命週期等。
常見的修飾子包括:short、long、const、static 等
修飾子 Modifier——long
Ruby@Sprout
C++ 小眉角 > 修飾子
long 表示需要更多的記憶體空間,所有可能的組合:
long、long long、long T、long long T
int main() {
int int_var = 5;
cout << sizeof(int_var);
long long_var = 5;
cout << sizeof(long_var);
long int long_int_var = 5;
cout << sizeof(long_int_var);
long long int long_long_int_var = 5;
cout << sizeof(long_long_int_var);
return 0;
}
修飾子 Modifier——short
Ruby@Sprout
C++ 小眉角 > 修飾子
short 表示需要更少的記憶體空間,所有可能的組合:
short、short int
int main() {
int int_var = 5;
cout << sizeof(int_var);
short short_var = 5;
cout << sizeof(short_var);
short int short_int_var = 5;
cout << sizeof(short_int_var);
/* 編譯錯誤 */
short short int short_short_int_var = 5;
cout << sizeof(short_short_int_var);
return 0;
}
修飾子 Modifier——const
Ruby@Sprout
C++ 小眉角 > 修飾子
const 表示該變數的值不能被修改。當使用const修飾一個變數時,該變數的值在初始化之後就不能再被修改了,如果試圖對其進行修改,編譯器就會報錯。
int main() {
const int VAR = 5;
cout << VAR << endl;
/* 編譯錯誤 */
VAR = 3;
return 0;
}
修飾子 Modifier——static
Ruby@Sprout
C++ 小眉角 > 修飾子
static 表示該變數在程序運行期間只會被初始化一次。 一但變數初始化後,其在整個程序生命週期中都將存在,不會被自動銷毀。
void f() {
static int f_var = 0;
++f_var;
cout << f_var << endl;
}
int main() {
f();
f();
f();
return 0;
}
修飾子 Modifier——static
Ruby@Sprout
C++ 小眉角 > 修飾子
static 變數常被作為函數呼叫的計數器
void f() {
static int f_var = 0;
++f_var;
cout << "f 被呼叫了 " << f_var << " 次" << endl;
}
int main() {
f();
f();
f();
return 0;
}
C++ 小眉角
Ruby@Sprout
C++ 小眉角
Ruby@Sprout
Ruby@Sprout
C++ 小眉角
轉型
什麼是轉型(Type Conversion)?
Ruby@Sprout
C++ 小眉角 > 轉型
轉型是指將一種資料型別的數值轉換成另一種資料型別的數值的過程。
轉型可以分為顯性轉型和隱性轉型兩種方式。顯性轉型需要明確地指定轉換的型別,而隱性轉型則是由編譯器自動進行轉換。
隱性轉型 Implicit Type Conversion
Ruby@Sprout
C++ 小眉角 > 轉型
隱性轉型是指在程式執行時,編譯器自動轉換變數的資料型態,使其符合運算需求,不需要開發者明確指定轉換方式。
int main() {
int i = 10;
float f = i;
cout << "i = " << i << endl;
cout << "f = " << f << endl;
return 0;
}
隱性轉型 Implicit Type Conversion
Ruby@Sprout
C++ 小眉角 > 轉型
int main() {
int a = 5;
cout << a / 3 << endl;
}
int main() {
int a = 5;
cout << a / 3. << endl;
}
整數與整數運算,無轉型發生
整數與浮點數運算,轉型發生
Output: 1
Output: 1.66667
插播:字面常數的型態 Type of Literals
Ruby@Sprout
C++ 小眉角 > 轉型
整數 int:12、3、1234、415 長整數 long:12L、3L、1234l、415l 長長整數 long long:12LL、3LL、1234ll、415ll 倍精浮點數 double:1.2、3.L、0.1234l、.415l 浮點數 float:1.2F、3.F、.1234f、.415f
double > float > long long > long > int
插播:字面常數的型態 Type of Literals
Ruby@Sprout
C++ 小眉角 > 轉型
double > float > long long > long > int
#include <typeinfo>
int main() {
cout << typeid(3).name() << endl;
cout << typeid(3LL + 3.1f).name() << endl;
cout << typeid(3 + 3L).name() << endl;
cout << typeid(3L + 3LL).name() << endl;
cout << typeid(3. + 3.1f).name() << endl;
cout << typeid(3 + 3.f).name() << endl;
cout << typeid(3 + 3.).name() << endl;
}
往大的型態轉!
插播:字面常數的型態 Type of Literals
Ruby@Sprout
C++ 小眉角 > 轉型
double > float > long long > long > int
#include <typeinfo>
int main() {
int a = 3;
cout << typeid(a).name() << endl;
cout << typeid(3LL + 3.1f).name() << endl;
cout << typeid(a + 3L).name() << endl;
cout << typeid(3L + 3LL).name() << endl;
cout << typeid(3. + 3.1f).name() << endl;
cout << typeid(a + 3.f).name() << endl;
cout << typeid(a + 3.).name() << endl;
}
往大的型態轉!
顯性轉型 Explicit Type Conversion
Ruby@Sprout
C++ 小眉角 > 轉型
顯性轉型是一種強制類型轉換的方式,通常用於以下情況:
顯性轉型 Explicit Type Conversion
Ruby@Sprout
C++ 小眉角 > 轉型
int main() {
double pi = 3.14;
cout << (int)pi << endl;
return 0;
}
C style cast
顯性轉型 Explicit Type Conversion
Ruby@Sprout
C++ 小眉角 > 轉型
int main() {
double pi = 3.14;
cout << (int)pi << endl;
return 0;
}
C style cast
int main() {
double pi = 3.14;
cout << static_cast<int>(pi) << endl;
return 0;
}
C++ static cast
Why is C++ static cast better?
Ruby@Sprout
C++ 小眉角 > 轉型
static_cast<>()
可以讓編譯器在編譯時檢查是否有潛在錯誤;C-Style cast 不能。static_cast<>()
較冗長,在 C++ code 較容易看到;C_Style cast 較難看到。謝謝大家
Brought to you by Ruby
Ruby@Sprout