Python selection sort 選擇排序法

本篇 ShengYu 介紹排序法中的選擇排序法 selection sort,並且由 Python 來實作選擇排序法 selection sort。

選擇排序法 selection sort 基本原理

選擇排序法 selection sort 的原理是先在所有資料中挑選出一個最小的數值放在放在第一個,再從第二個到尾端的資料中挑選出一個最小的數值放在第二個,這樣一直迭代下去,最終將能獲得排序好的升序串列(由小到大),
讓我來舉個簡單的例子吧!假如今天有一串數字串列 5,4,3,1,2 要使用選擇排序 selection sort,

第一次迴圈排序結果如下,所以第一次迴圈就從全部資料挑選出最小的數值 1 給交換放到第一個了,剩餘要排序的數值還有 4 個,

1
1,4,3,5,2

第二次迴圈排序結果如下,第二次迴圈就從第二個到尾端挑選出最小的數值 2 給交換放到第二個了,剩餘要排序的數值還有 3 個,

1
1,2,3,5,4

第三次迴圈排序結果如下,第三次迴圈就從第三個到尾端挑選出最小的數值 3 給交換放到第三個了,剩餘要排序的數值還有 2 個,

1
1,2,3,5,4

第四次迴圈排序結果如下,第四次迴圈就從第四個到尾端挑選出最小的數值 4 給交換放到第四個了,剩餘要排序的數值還有 1 個,

1
1,2,3,4,5

迴圈結束,排序完成,

Python 實作選擇排序法 selection sort

由上述的簡單例子推演可以了解了選擇排序 selection sort 基本原理後,接著就開始練習用 Python 來寫程式,那我們來看看 Python 選擇排序怎麼寫吧!

python3-selection-sort.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def bubble_sort(nums):
n = len(nums)
for i in range(n-1):
min_idx = i
for j in range(i+1, n):
if nums[j] < nums[min_idx]:
min_idx = j
# swap
nums[i], nums[min_idx] = nums[min_idx], nums[i]

nums = [5,4,3,1,2]
print("排序前 = %s" % nums)
bubble_sort(nums)
print("排序後 = %s" % nums)

Python 程式跑出來的結果如下,經過選擇排序法 selection sort 排序後的結果的確是由小排到大。

1
2
排序前 = [5, 4, 3, 1, 2]
排序後 = [1, 2, 3, 4, 5]

其它相關文章推薦
C/C++ selection sort 選擇排序法
Python 新手入門教學懶人包
Python 寫檔,寫入 txt 文字檔
Python 讀取 csv 檔案
Python 寫入 csv 檔案
Python 讀寫檔案
Python 產生 random 隨機不重複的數字 list
Python PyAutoGUI 使用教學
Python OpenCV resize 圖片縮放

Python bubble sort 泡沫排序法

本篇 ShengYu 介紹排序法中最簡單經典的泡沫排序法 bubble sort,並且由 Python 來實作泡沫排序法 bubble sort。

泡沫排序法 bubble sort 基本原理

泡沫排序法 bubble sort 的原理是將兩個相鄰的數值相比,假如前一個數值比後一個數值大時,就互相對調,實作時就是使用兩層迴圈,針對該串列掃兩次,最終將能獲得排序好的升序串列(由小到大),
讓我來舉個簡單的例子吧!假如今天有一串數字串列 3,2,4,5,1 要使用泡沫排序 bubble sort,

第一次迴圈排序步驟如下,所以第一次迴圈就能把最大的數值 5 給交換到最後了,剩餘要排序的數值還有 4 個,

1
2
3
4
2,3,4,5,1
2,3,4,5,1
2,3,4,5,1
2,3,4,1,5

第二次迴圈排序步驟如下,第二次迴圈,就把第二大的數值 4 給交換到倒數第二個了,剩餘要排序的數值還有 3 個,

1
2
3
2,3,4,1,5
2,3,4,1,5
2,3,1,4,5

第三次迴圈排序步驟如下,第三次迴圈,就把第三大的數值 3 給交換到倒數第三個了,剩餘要排序的數值還有 2 個,

1
2
2,3,1,4,5
2,1,3,4,5

第四次迴圈排序步驟如下,第四次迴圈,就把第三大的數值 2 給交換到倒數第四個了,剩餘要排序的數值還有 1 個,

1
1,2,3,4,5

迴圈結束,排序完成,

Python 實作泡沫排序法 bubble sort

由上述的簡單例子推演可以了解了泡沫排序 bubble sort 基本原理後,接著就開始練習用 Python 來寫程式,那我們來看看 Python 泡沫排序怎麼寫吧!

python3-bubble-sort.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def bubble_sort(nums):
n = len(nums)
for i in range(n-1):
for j in range(n-i-1):
if nums[j] > nums[j+1]:
temp = nums[j]
nums[j] = nums[j+1]
nums[j+1] = temp

nums = [3,2,4,5,1]
print("排序前 = %s" % nums)
bubble_sort(nums)
print("排序後 = %s" % nums)

Python 程式跑出來的結果如下,經過泡沫排序法 bubble sort 排序後的結果的確是由小排到大。

1
2
排序前 = [3, 2, 4, 5, 1]
排序後 = [1, 2, 3, 4, 5]

下一篇介紹 selection sort 選擇排序法

其它相關文章推薦
C/C++ bubble sort 泡沫排序法
Python 新手入門教學懶人包
Python 寫檔,寫入 txt 文字檔
Python 讀取 csv 檔案
Python 寫入 csv 檔案
Python 讀寫檔案
Python 產生 random 隨機不重複的數字 list
Python PyAutoGUI 使用教學
Python OpenCV resize 圖片縮放

std::max 用法與範例

本篇介紹 C++ 的 std::max 用法與範例,

C++ std::max 兩數取最大值

C++ std::max 可以取各種變數類型的兩數最大值,包含 int, short, long, float, double 甚至是 char,
範例如下,其中比較 AB 就是 char 變數類型取最大值,

std-max.cpp
1
2
3
4
5
6
7
8
9
10
11
12
// g++ std-max.cpp -o a.out
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
cout << std::max(1, 99) << "\n";
cout << std::max('A', 'B') << "\n";
cout << std::max(2.5f, 4.3f) << "\n";
return 0;
}

輸出:

1
2
3
99
B
4.3

std::max 多個數值中取最大值 (C++11)

這個是 C++11 才加入的功能,讓 std::max 可以接受多個數值作為輸入,然後回傳這當中的最大值,
寫法如下,第一種直接用 { } 大括號的方式將數值帶入,然後它會呼叫到 std::initializer_list 建構子,
第二種寫法是直接先宣告好 std::initializer_list, 再將其變數帶入 std::max,
第三種就是懶人寫法 auto ~~~

std-max2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ std-max2.cpp -o a.out -std=c++11
#include <iostream>
#include <algorithm>
#include <typeinfo>

using namespace std;

int main() {
cout << std::max({1, 3, 5, 7}) << "\n";

std::initializer_list<int> array = {2, 4, 6, 8};
cout << std::max(array) << "\n";

auto array2 = {2, 4, 6, 8};
cout << std::max(array2) << "\n";
cout << typeid(array2).name() << "\n";

return 0;
}

輸出如下,這邊我們順便使用 typeid 來看看 auto 建立 array2 出來的變數類型是什麼,
關於 typeid 的用法可以參考這篇介紹,這邊只要知道它可以用來印出變數類型是什麼類型就好,
結果就是 St16initializer_listIiE,簡單說它就是 std::initializer_list,
所以編譯器會在編譯時期幫我們將 auto 自動轉換成 std::initializer_list,

1
2
3
4
7
8
8
St16initializer_listIiE

補充
如果想要在類似 vector 這種容器裡面取出最大值的方法請參考這篇

以上就是 std::max 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
std::max - cppreference.com
https://en.cppreference.com/w/cpp/algorithm/max

其它相關文章推薦
C/C++ 新手入門教學懶人包
std::max_element 用法與範例
std::min 用法與範例
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例

Shell Script sleep 延遲執行

本篇 ShengYu 介紹 Shell Script sleep 延遲執行 的用法,Shell Script 中偶爾需要延遲 sleep 幾秒鐘再繼續執行程式或腳本這個功能,例如我想要間隔1秒取得CPU使用量等等諸如此類的場合應用,本篇就介紹如何在 Shell Script 中使用 sleep 指令延遲或暫停,然後再繼續執行。

以下的 Shell Script sleep 延遲執行用法與範例將分為這幾部分,

  • Shell Script 用 sleep 來延遲 1 秒執行
  • Shell Script sleep 延遲 1 秒以下
  • Shell Script sleep 延遲 2 分鐘
  • Shell Script sleep 延遲 x 分鐘 y 秒
  • Shell Script sleep 時間單位整理
  • Shell Script sleep 其他平台注意事項

以下就開始介紹 Shell Script sleep 寫法吧!

Shell Script 用 sleep 來延遲 1 秒執行

以下為 Shell Script sleep 延遲 1 秒執行的範例,s 表示延遲幾秒,

1
sleep 1s

Shell Script sleep 延遲 1 秒以下

如果是要 sleep 延遲 1 秒以下咧?別擔心,sleep 可以接受小數點,
要延遲 0.5 秒的話,

1
sleep 0.5

要延遲 0.01 秒的話,

1
sleep 0.01

那我要怎知道 sleep 延遲的準不準? Linux 有提供一個 time 指令來測量程式執行多久用,那我們馬上來用用看,

1
2
3
4
5
6
7
8
9
10
11
12
$ time sleep 1s
real 0m1.002s
user 0m0.000s
sys 0m0.000s
$ time sleep 0.5
real 0m0.501s
user 0m0.000s
sys 0m0.000s
$ time sleep 0.01
real 0m0.012s
user 0m0.000s
sys 0m0.000s

使用 time 指令計算 sleep 執行時間的結果在我的機器上看起來還蠻準的,

Shell Script sleep 延遲 2 分鐘

那如果要 sleep 延遲 5 分鐘咧?恩,我要寫成 sleep 300s
有沒有不想心算的偷懶方式呢?有!用 m 來表示分鐘,

1
sleep 2m

依此累推的話,欲 sleep 延遲3小時的話,

1
sleep 3h

那 sleep 延遲4天的話就會是這樣,

1
sleep 4d

Shell Script sleep 延遲 x 分鐘 y 秒

有人會問,那 sleep 延遲 2 分鐘 30 秒呢?
很簡單呀!不就是 150 秒嘛!

1
sleep 150s

如果答案只能這樣的話未免也令人太灰心了吧!
另一種人性化的答案就是將前面的招式融會貫通組合起來,

1
sleep 2m 30s

Shell Script sleep 時間單位整理

整理一下 sleep 後面接受的時間單位,
語法:sleep NUMBER[SUFFIX]...

  • s:秒 seconds (預設)
  • m:分鐘 minutes.
  • h:小時 hours.
  • d:天 days.

Shell Script sleep 其他平台注意事項

macOS 下的 sleep 指令只能接受秒的參數

其他參考
sleep(1) - Linux manual page
https://man7.org/linux/man-pages/man1/sleep.1.html
Linux Sleep Command (Pause a Bash Script) | Linuxize
https://linuxize.com/post/how-to-use-linux-sleep-command-to-pause-a-bash-script/
Linux sleep 如何暫停半秒、微秒 – Tsung’s Blog
https://blog.longwin.com.tw/2018/06/linux-bash-shell-sleep-half-millisecond-2018/

其它相關文章推薦
Shell Script 新手入門教學
Shell Script 四則運算,變數相加、相減、相乘、相除
Shell Script if 條件判斷
Shell Script for 迴圈
Shell Script while 迴圈
Shell Script 讀檔,讀取 txt 文字檔
Linux sed 字串取代用法與範例
Linux cut 字串處理用法與範例
Linux tail 持續監看檔案輸出用法與範例
Linux find 尋找檔案/尋找資料夾用法與範例
Linux kill 指令砍掉指定的 process name
Linux tee 同時螢幕標準輸出和輸出到檔案用法與範例
Linux grep/ack/ag 搜尋字串用法與範例

C/C++ 字串轉數字的4種方法

本篇介紹 C/C++ 字串轉數字 string to integer 的方法,總共將會介紹4種方法,

以下 C/C++ 字串轉數字的4種方法分別是,

  • C 的字串轉數字 atoi()
  • C++ 字串轉數字 std::atoi()
  • C++11 的字串轉數字 std::stoi()
  • 自製 atoi()

那我們就開始吧!

C 的字串轉數字 atoi()

在標準 C 字串轉數字的話可以使用 atoi(),使用方法如下,
標準 C 要使用 atoi() 話,需要引入的標頭檔: <stdlib.h>

cpp-atoi.cpp
1
2
3
4
5
6
7
8
9
10
// g++ cpp-atoi.cpp -o a.out
#include <stdio.h>
#include <stdlib.h>

int main() {
char buffer[128] = "123";
int integer = atoi(buffer);
printf("str to int: %d\n", integer);
return 0;
}

輸出如下,

1
str to int: 123

C++ 字串轉數字 std::atoi()

在 C++ 字串轉數字的話可以使用 std::atoi()
C++ 要使用 std::atoi() 話,需要引入的標頭檔: <cstdlib>

cpp-string-to-integer.cpp
1
2
3
4
5
6
7
8
9
10
// g++ cpp-string-to-integer.cpp -o a.out
#include <stdio.h>
#include <cstdlib>

int main() {
char buffer[128] = "456";
int integer = std::atoi(buffer);
printf("str to int: %d\n", integer);
return 0;
}

輸出如下,

1
str to int: 456

要使用 std::string 字串轉數字的話,要碼就轉成傳統字串在使用之前介紹的 api,

cpp-string-to-integer2.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ cpp-string-to-integer2.cpp -o a.out
#include <stdio.h>
#include <string>
#include <cstdlib>

int main() {
std::string str = "456";
int integer = std::atoi(str.c_str());
printf("str to int: %d\n", integer);
return 0;
}

C++11 的字串轉數字 std::stoi()

但 C++11 支援了直接使用 std::string 作為輸入參數,這邊就要介紹 C++11 新增的 std::stoi() 函式用來字串轉整數,
C++11 要使用 std::stoi() 話,需要引入的標頭檔: <string>
趕緊來看看怎麼寫吧!

cpp-string-to-integer3.cpp
1
2
3
4
5
6
7
8
9
10
// g++ cpp-string-to-integer3.cpp -o a.out -std=c++11
#include <iostream>
#include <string>

int main() {
std::string str = "789";
int integer = std::stoi(str);
printf("str to int: %d\n", integer);
return 0;
}

輸出如下,

1
str to int: 789

自製 atoi()

這邊示範一下如果要自己寫一個 atoi 要怎麼寫,有時候面試考題也會出現,所以多學一些是好事,另外要注意的是 atoi 可能會與標準函式庫提供的同名重複定義,要確認輸入型別是否不一樣,否則的話就換個名字,避免衝突,

cpp-string-to-integer4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// g++ cpp-string-to-integer4.cpp -o a.out
#include <stdio.h>
#include <ctype.h>

int myatoi(const char *s) {
int sum = 0;
int i = 0;
int sign = 1;

if (s[i] == '-') {
sign = -1;
i++;
}

while (isdigit(s[i])) {
sum = sum * 10 + s[i] - '0';
i++;
}
return sum * sign;
}

int main() {
char buffer[] = "12345";
int integer = myatoi(buffer);
printf("str to int: %d\n", integer);

char buffer2[] = "-12345";
int integer2 = myatoi(buffer2);
printf("str to int: %d\n", integer2);
return 0;
}

輸出如下,

1
2
str to int: 12345
str to int: -12345

以上就是 C/C++ 字串轉數字的4種方法的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!
如果你想了解 C/C++ 整數轉字串的方法可以參考這篇

參考
atoi - C++ Reference
https://www.cplusplus.com/reference/cstdlib/atoi/
std::atoi, std::atol, std::atoll - cppreference.com
https://en.cppreference.com/w/cpp/string/byte/atoi
c++11 - What is the difference between std::atoi() and std::stoi? - Stack Overflow
https://stackoverflow.com/questions/20583945/what-is-the-difference-between-stdatoi-and-stdstoi

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 整數轉字串的方法與範例
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例

C/C++ 不定長度參數

本篇介紹 C/C++ 的 variable length argument 不定長度參數用法,在某些情況下需要自己寫個能夠接受可變長度參數的函式,接下來文章內容會教你如何撰寫能夠接受可變長度參數 variable length argument 的函式。


要使用不定長度參數的話,需要引入的標頭檔: <stdarg.h>

C/C++ 不定長度參數的範例

範例中的 myprintf() 可以接受可變長度參數,可以接受一個參數也可以接受兩個參數,
甚至三個四個以上等等,就像 printf() 那樣使用~

基本上是由 va_start()va_end() 這兩個函式之間來處理所有的不定長度參數,
這個範例是將這些參數全部都格式化成字串 buf,讓稍後的 printf() 來輸出。

variable-length-argument
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// g++ cpp-variable-length-argument.cpp -o a.out -std=c++11
#include <stdio.h>
#include <stdarg.h>

void myprintf(const char* fmt, ...)
{
char buf[128];

va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);

printf("%s", buf);
}

int main(void)
{
myprintf("%d\n", 1);
myprintf("%d %d\n", 1, 2);
myprintf("%d %d %s\n", 1, 2, "Hello World");
return 0;
}

輸出如下,
可以看到 myprintf() 接受不同種參數長度的輸出結果~

1
2
3
1
1 2
1 2 Hello World

參考
variadic functions - Variable number of arguments in C++? - Stack Overflow
https://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c
va_start - C++ Reference
http://www.cplusplus.com/reference/cstdarg/va_start/
Variadic functions - cppreference.com
https://en.cppreference.com/w/cpp/utility/variadic
Variable Length Argument in C - GeeksforGeeks
https://www.geeksforgeeks.org/variable-length-argument-c/
具有變數引數清單的函式 (C++) | Microsoft Docs
https://docs.microsoft.com/zh-tw/cpp/cpp/functions-with-variable-argument-lists-cpp?view=msvc-160
C 語言:讓自己寫的 function 也能使用 … (不具名參數, 參數個數不確定) @ 傑克! 真是太神奇了! :: 痞客邦 ::
https://magicjackting.pixnet.net/blog/post/60401034

其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例

C/C++ getpid 取得行程 pid

本篇介紹 C/C++ 在 Linux 下取得行程的方法,在 Linux 下要取得 pid 的話要使用 getpid 這個函式,以下為 Linux getpid 函式用法與範例。

getpid 函式適用 Linux / macOS,但 Windows 不適用


要使用 Linux getpid 取得行程 pid 的話,需要引入的標頭檔: <unistd.h>
另外 pid_t 這個變數類型定義會需要引入 <sys/types.h> 標頭檔

Linux getpid 使用範例

以下為 getpid 的使用範例,要用 pid_t 這個變數類型來儲存 getpid 的回傳結果,
pid_t 這個變數類型在 x64 上定義為 int,
之後用 printf 將這個 pid 印出來,這個 pid 就是這個小程式的 process id 了,

cpp-getpid.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ cpp-getpid.cpp -o a.out
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
pid_t pid = getpid();
printf("pid: %d\n", pid);

return 0;
}

輸出:

1
pid: 11564

補充

如果你只是單純的印出 pid 的話,可以不用引用<sys/types.h> 標頭檔

1
printf("pid: %d\n", getpid());

其他參考
getpid(2) - Linux manual page
https://man7.org/linux/man-pages/man2/getpid.2.html
C语言getpid()函数:获取进程识别码_C语言中文网
http://c.biancheng.net/cpp/html/280.html
How to get the running process’ pid in C / C++? - SysTutorials
https://www.systutorials.com/how-to-get-the-running-process-pid-in-c-c/
Code Snippets for .NET and Linux: Get process id by name in Linux using C++
http://proswdev.blogspot.com/2012/02/get-process-id-by-name-in-linux-using-c.html

其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例

Linux Android 行程記憶體使用量

本篇介紹在Linux下檢查行程記憶體使用量,本文介紹的方法同樣適用於 Android,

要確認行程的記憶體使用量可以透過 top 指令或者查看 /proc/[pid]/status 檔案內容,

1
cat /proc/[pid]/status

或者使用pidof指令來查詢程式的 pid

1
cat /proc/$(pidof <progname>)/status

可以 man proc 查詢一下 VmSize 的說明

VmPeak:行程所使用的虛擬記憶體的峰值
VmSize:行程目前使用的虛擬記憶體的大小
VmLck:已經鎖定的物理記憶體的大小 (鎖定的物理記憶體不能交換到硬盤)
VmHWM:行程所使用的物理記憶體的峰值
VmRSS:行程目前使用的物理記憶體的大小 (對應top & procrank指令的RSS欄位)
VmData:行程佔用的資料段大小
VmStk:行程佔用的堆疊大小
VmExe:行程佔用的程式指令碼段大小
VmLib:行程所加載的動態庫所佔用的記憶體大小
VmPTE:行程佔用的頁表大小
VmSwap:行程所使用的交換區的大小

參考
查看Linux & Android中内存占用方法_MyArrow的专栏-CSDN博客
https://blog.csdn.net/myarrow/article/details/7703296
Linux中查看进程占用内存的情况 - 胡桃夹子
http://hutaow.com/blog/2014/08/28/display-process-memory-in-linux/
linux查看某个进程内存占用情况以及/proc/pid/status解释 - youxin - 博客园
https://www.cnblogs.com/youxin/p/5976194.html

其它相關文章推薦
Linux 常用指令教學懶人包
Linux sed 字串取代用法與範例
Linux cut 字串處理用法與範例
Linux tail 持續監看檔案輸出用法與範例
Linux find 尋找檔案/尋找資料夾用法與範例
Linux kill 指令砍掉指定的 process name
Linux tee 同時螢幕標準輸出和輸出到檔案用法與範例
Linux grep/ack/ag 搜尋字串用法與範例

C++ exception 例外處理

本篇介紹 c++ exception 例外處理,程式在執行過程中可能會發生一些特殊情況的異常,例如:記憶體不夠、越界存取,所以我們可以用 try catch 來處理這種例外情形

C++ 基本的 try… catch… 例外處理

最簡單的例外處理的寫法如下,使用 try... catch... 所組成,
用 try 包住可能會發生例外的程式碼區段,
用 catch 來處理這個 try 區域所發生的例外,
what() 是 exception 類別提供的一個 public method,exception 類別會被所有子類重載,所以不管發生哪種例外,只要呼叫 exception 類的 what() 方法,就會取得該種例外的發生的原因,這個機制是用 C++ virtual 所完成的,程式碼中的 e.what() 將回傳例外產生的原因字串。

另外,catch 裡面的 exception 變數應該要用 reference 的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <exception>

using namespace std;

int main()
{
try {
// ...
} catch (std::exception &e) { // exception should be caught by reference
cout << "exception: " << e.what() << "\n";
}

return 0;
}

接下來我們來看看實戰中的例外範例,

C++ vector 的 out_of_range 例外處理

C++ vector 存取元素的方式有兩種,一種是使用 [] operator,例如:v[0] = 0
另一種是使用 at(),例如:v.at(0) = 0
這兩個的差別在於使用 [] operator 存取超界時不會丟出例外 exception,
所以像下面這個例子中的 v[3] 實際上是讀取了不知名的記憶體位置的數值,
使用 at() 存取超界時會丟出 std::out_of_range 的例外 exception,
所以下面這個範例我們嘗試捕捉看看例外,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// g++ cpp-exception.cpp -o a.out -std=c++11
#include <iostream>
#include <vector>
#include <exception>

using namespace std;

int main()
{
vector<int> v = {1,2,3};
try {
cout << v[0] << "\n";
cout << v[1] << "\n";
cout << v[2] << "\n";
cout << v[3] << "\n";
cout << v.at(0) << "\n";
cout << v.at(1) << "\n";
cout << v.at(2) << "\n";
cout << v.at(3) << "\n";
} catch (std::exception &e) {
cout << "exception: " << e.what() << "\n";
}

return 0;
}

程式輸出如下,可以發現 使用 v[3] operator 存取超界用 try... catch... 是捕捉不到例外的,
但是當程式執行到 v.at(3) 時存取超界拋出了例外 exception,

1
2
3
4
5
6
7
8
1
2
3
0
1
2
3
exception: vector::_M_range_check: __n (which is 3) >= this->size() (which is 3)

常見的 exception 例外

以下幾乎是所以有的 exception 例外種類,C++11 以及之後加入的 exception 未列在下面,

例外種類 說明
std::exception 所有標準 C++ 例外的父類
std::bad_alloc new 配置記憶體失敗時拋出,可能是記憶體不足
std::bad_cast dynamic_cast 失敗時拋出
std::bad_exception 無法預期的例外
std::bad_typeid typeid 拋出
std::logic_error 程式碼邏輯異常拋出
std::runtime_error 執行期間的例外
std::domain_error Domain error exception
std::invalid_argument 無效的參數時拋出
std::length_error 建立長度太長時拋出,例外:std::string
std::out_of_range 存取越界時拋出,例如:std::vector
std::overflow_error 溢位時拋出
std::range_error Range error exception
std::underflow_error 算術下溢時拋出

重新拋出例外 exception

在 C++ 中有時候這個例外 exception 捕捉到了,但是某些原因未去處理或還不想處理,想要將該例外重新拋出,就需要使用 throw 這個關鍵字,
重新拋出例外 exception 後,讓該例外交給更外層的例外捕捉處理,

1
2
3
4
5
6
try {
// ...
} catch (execption &e) {
cout<< e.what() << "\n";
throw; // 重新拋出例外
}

參考
Exceptions - C++ Tutorials
http://www.cplusplus.com/doc/tutorial/exceptions/
exception - C++ Reference
http://www.cplusplus.com/reference/exception/exception/
std::exception - cppreference.com
https://en.cppreference.com/w/cpp/error/exception
簡介例外處理
https://openhome.cc/Gossip/CppGossip/ExceptionHandling.html
C++ 异常处理 | 菜鸟教程
https://www.runoob.com/cplusplus/cpp-exceptions-handling.html
Throwing out of range exception in C++ - Stack Overflow
https://stackoverflow.com/questions/2709719/throwing-out-of-range-exception-in-c/2709733
XYZ的筆記本: C++ 捕捉不到 vector 超出範圍的例外 ?
https://xyz.cinc.biz/2013/10/c-vector-try-catch-out-of-range-exception.html

其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例

Python tkinter filedialog.askdirectory 選擇資料夾

本篇介紹如何在 Python tkinter 中的 filedialog.askdirectory() 選擇資料夾對話框用法與範例,這邊使用 python 內建的 Tkinter 來 filedialog 為示範,

Pyhton Tkinter 要叫出選擇資料夾對話框要使用 filedialog.askdirectory(),最簡單的使用方法為

1
file_path = filedialog.askdirectory()

完整的 python 3 使用範例如下,

python3-filedialog-askdirectory.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog

root = tk.Tk()
root.withdraw()
file_path = filedialog.askdirectory()
print(file_path)

如果是 python 2 的話稍微有點不同,不過大同小異,

python-tkFileDialog-askdirectory.py
1
2
3
4
5
6
7
8
#!/usr/bin/python
# -*- coding: utf-8 -*-
import Tkinter, tkFileDialog

root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askdirectory()
print(file_path)

接著就把程式執行起來看看吧!程式啟動後會彈出一個開啟資料夾的對話框,如下圖所示,

接著選好資料夾後,按下OK確定按鈕後 askdirectory() 就會回傳資料夾路徑了。

指定一個初始的目錄來選擇資料夾

通常會有個初始的目錄讓使用者去選,但預設的目錄可能離最終目標的目錄差很多層,這樣使用者要點很多次,很不方便,所以會給一個初始目錄,

python3-filedialog-askdirectory2.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog

root = tk.Tk()
root.withdraw()
file_path = filedialog.askdirectory(parent=root,
initialdir='~/')

以上就是 Python tkinter filedialog.askdirectory() 選擇資料夾對話框用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
python - what is default value of filedialog.askdirectory()? - Stack Overflow
https://stackoverflow.com/questions/56052144/what-is-default-value-of-filedialog-askdirectory
openfiledialog - Quick and easy file dialog in Python? - Stack Overflow
https://stackoverflow.com/questions/9319317/quick-and-easy-file-dialog-in-python

其它相關文章推薦
Python tkinter 開啟檔案對話框
Python 新手入門教學懶人包
Python tkinter 新手入門教學