C++ malloc invalid conversion from void* to int* 無效的轉換

這篇 ShengYu 介紹一下在 C++ 程式中使用 malloc 新手常遇到的 invalid conversion 編譯器報錯的問題,
在 C 語言你可以這樣寫,malloc 會回傳 void * 並自動地轉換成 int *

cpp-malloc-invalid-conversion.cpp
1
int *arr = malloc(10 * sizeof(int));

但在 C++ 中,這段程式編譯器會報錯,編譯時期的錯誤如下,

1
2
3
4
cpp-malloc-invalid-conversion.cpp: In function ‘int main()’:
cpp-malloc-invalid-conversion.cpp:5:22: error: invalid conversion from ‘void*’ to ‘int*’ [-fpermissive]
int *arr = malloc(10 * sizeof(int));
^

因為在 C++ 中不允許隱式轉換(implicit conversion),C++ 比 C 更重視型別安全,也就是說在 C++ 不會自動地將 void * 轉換為 int * 指標(或其它類型的指標),你需要用顯式轉換(explicit conversion)明確地告訴編譯器轉換類型,例如

1
int *arr = (int *)malloc(10 * sizeof(int));

這樣就可以編譯過了~~~

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
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 用法與範例
std::deque 用法與範例
std::vector 用法與範例

Python 寫檔,寫入 txt 文字檔

本篇介紹 Python 寫檔寫入 txt 文字檔的方法,Python 寫檔是檔案處理的必備技能,在 Python 程式中常需要將程式的資料或資訊輸出成 txt 文字檔,例如:log 日誌,接著就馬上開始學習用 Python 來寫檔吧!

以下 Python 寫檔的用法範例分為這幾部份,

  • Python 基本的寫檔範例
  • 寫入 list 資料到檔案
  • 用 print() 寫入檔案
  • 使用 with open() as
  • 添加模式附加資料在原本檔案的尾巴

Python 基本的寫檔範例

Python 處理檔案中寫檔案是最常見的 IO 操作,在上一篇我們已經介紹過怎麼開檔、讀檔、關檔了,這邊就直接介紹怎麼寫入 txt 檔案,

一開始開檔 open(filename, mode) 的第二個參數使用 'w' 開檔且寫入,這邊我們示範了3種方式,分別是將字串寫入txt檔案,將整數寫入txt檔案,將浮點數寫入txt檔案,

python3-txt-write.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

path = 'output.txt'
f = open(path, 'w')
f.write('Hello World')
f.write(123)
f.write(123.45)
f.close()

輸出:

output.txt
1
2
3
Hello World
123
123.45

寫入 list 資料到檔案

這邊 ShengYu 介紹將 list 資料一次寫入到檔案的方法,Python 的 f.writelines() 可以接受 list 作為參數,
但要注意的是直接使用 writelines() 函式並不會換行寫入,要在寫入的字串後面加 \n 才會換行,例如,

python3-txt-write2.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

path = 'output.txt'
f = open(path, 'w')
lines = ['Hello World\n', '123', '456\n', '789\n']
f.writelines(lines)
f.close()

結果輸出如下,有注意到有換行跟沒換行的差異了嗎?

output.txt
1
2
3
Hello World
123456
789

用 print() 寫入檔案

Python print() 函式預設是將資料輸出到標準螢幕輸出,不過 print() 也可以指定將資料輸出到檔案(當然也就不會輸出在螢幕輸出了),只要在 print() 增加 file 的參數就可以了,

python3-txt-write3.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

path = 'output.txt'
f = open(path, 'w')
print('Hello World', file=f)
print('123', file=f)
print('456', file=f)
print('789', file=f)
f.close()

使用 with open() as

使用 with 關鍵字來開檔的優點是不必在程式裡寫關檔 close(),因為 with 會在結束這個程式碼區塊時自動將它關閉,馬上來看看 Python with 寫檔的用法範例吧!

python3-txt-write4.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

path = 'output.txt'
with open(path, 'w') as f:
f.write('apple\n')
f.write('banana\n')
f.write('lemon\n')
f.write('tomato\n')

添加模式附加資料在原本檔案的尾巴

Python open() 使用添加模式主要是可以將寫入的資料附加在原本檔案的尾巴,要使用添加模式需要在 open(filename, mode) 的第二個參數使用 'a' 來開檔,a 是 append 的意思,Python 添加模式範例如下,

python3-txt-write5.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

path = 'output.txt'
with open(path, 'a') as f:
f.write('apple\n')
f.write('banana\n')
f.write('tomato\n')

假設一開始沒有 output.txt,執行了三次後的結果如下,每一次的資料寫入都是從檔案尾巴開始添加,

1
2
3
4
5
6
7
8
9
apple
banana
tomato
apple
banana
tomato
apple
banana
tomato

在下一篇我將會介紹 Python 結合讀檔與寫檔的檔案讀寫範例。

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python 新手入門教學懶人包
Python 讀取 txt 文字檔
Python 讀寫檔案
Python 讀取 csv 檔案
Python 寫入 csv 檔案
Python 字串分割 split
Python 取代字元或取代字串 replace
Python 讓程式 sleep 延遲暫停時間
Python 產生 random 隨機不重複的數字 list
Python PyAutoGUI 使用教學
Python OpenCV resize 圖片縮放

git revert 與 git gui (gitk) 抵銷提交

本篇 ShengYu 來介紹 git revert commit,中文叫抵銷提交?撤銷提交?逆向提交?這個翻譯我一直不知道哪個比較能確切表達,哈哈!也許抵銷提交比較接近 git revert 的意思吧!git revert 用途是把某一筆的改動給抵銷,只不過這個抵銷的方式是用一筆commit來達成,

怎麼用 git revert 指令?

假設今天的 commit 如下,總共有四筆,最上面為最新的一筆 commit 12348

1
2
3
4
5
6
7
8
commit 12348
我是最新的一筆
commit 12347
我是第三筆
commit 12346
我是第二筆
commit 12345
我是第一筆

那我想要抵銷提交 git revert commit 12347 也就是第三筆的話,要怎麼做呢?

1
$ git revert 12347

結果就會產生新的一筆 commit 12349 是專門來抵銷 commit 12347 的更動

1
2
3
4
5
6
7
8
9
10
commit 12349
Revert "我是第三筆"
commit 12348
我是最新的一筆
commit 12347
我是第三筆
commit 12346
我是第二筆
commit 12345
我是第一筆

那怎麼把剛剛這筆 commit 12349 砍掉呢?就用我們之前學過的 git reset 來砍掉前一筆 commit,

1
$ git reset HEAD^ --hard

怎麼用 git gui (gitk) 來 revert?

待續…

為什麼選擇用 Hexo 來寫部落格?

本篇來介紹我為什麼選擇用 Hexo 來寫部落格,我會以免費、中文支援程度、網路資源、學習門檻這幾個面向來進行討論分析,

為什麼選擇用 Hexo 來寫部落格?

我自己在寫程式筆記很多年了,累積了超多技術筆記,一直都沒有很好的方式整理,我一直不斷地尋找一個好的方式來整理我的技術筆記,從一開始筆記只是放在電腦的檔案料夾,後來放到 Dropbox、Google Drive、Evernote,這些筆記躺在電腦裡最後還是躺在電腦裡,說不定那天還會被我誤刪了,多可惜呀!

發現程式碼需要配合文字說明才好理解,因為我就是從網路上自學這樣過來的呀!我開始尋找
到 BSP 系統,Blogger,Medium,我發現一直有一個痛點沒有獲得很好的解決,那就是程式碼區塊一直顯示的不是很好,作為一個技術筆記的地方,這個點一定是首先需要解決的,曾經也有自架 DowkuWiki,直到我看見了 Github Pages 將 markdown 變成網頁的程式碼區塊是多麽的漂亮清晰簡潔,後來我便研究怎麼架 Github Pages,尤其 Github Pages 是免費,後來 Hexo 很火紅,我驚訝靜態網站產生工具(Static Site Generator)也可以做出這樣厲害的網站呀!尤其是我可以用我最慣用的 markdown 方式寫,我試用後便覺得不錯,從那時候開始我就使用 Hexo 了,

目前靜態網站產生工具主流有三個,分別為 Jekyll、Hugo、Hexo

Jekyll

Jekyll 是 Github 自家的產物,程式語言使用 ruby,ruby 我本身一直都沒有機會學,所以我也對沒什麼興趣

Hugo

Hugo 使用 Go 語言,特色是生成網頁的速度快,雖然目前 github 上的星星數已經比 Hexo 還多了,但論網路資源、主題、外掛比 Hexo 少太多了,畢竟會 Go 語言跟會 Javascript 的人數差太多了,你懂得~~~,但也許未來 Hugo 會紅。

Hexo

Hexo 是台灣人做的!台灣之光~ Hexo 使用 Nodejs,程式語言就是 Javascript,使用 Javascript 的優勢是會前端的人多少都會 Javascript,Javascript 開發者很多,自然就很多人貢獻,網路資源、主題、外掛多到不行,對新手友善好很多~

加上我自己本來就會 Javascript,自己改也比較方便,會網站架設的人絕對也逃避不了學習 Javascript,所以 Javascript 學會後好處多多!

缺點的話就是文章一多建置速度比 Hugo 慢,但這個缺點比起 Hexo 的優勢是我可以接受的。

如果你想學習如何在 Github Pages 架 Hexo,可以參考我之前的 Hexo 文章。

其它相關文章推薦
Hexo 使用 Google Analytics 進行網站流量分析
Hexo 本機測試時如何關閉 Google Analytics
Hexo codeblock 插入程式碼區塊與各種程式語言預覽
升級更新 Hexo upgrade
Ubuntu 安裝 Hexo
Mac OS 安裝 Hexo

Python 串列切片

本篇 ShengYu 介紹 Python 串列切片,Python 中有序序列都支援切片 slice,例如:list 串列, str 字串, tuple 元組,這篇介紹 Pyhton 的串列切片 list slice。

印出串列第1-3元素

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[0:3])

輸出結果如下,

1
[1, 2, 3]

印出串列第2-4元素

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[1:4])

輸出結果如下,

1
[2, 3, 4]

印出串列頭端到7個的元素

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[:7])

輸出結果如下,

1
[1, 2, 3, 4, 5, 6, 7]

印出串列第8到尾端的元素

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[7:])

輸出結果如下,

1
[8, 9]

印出串列第2,4,6,8元素,第三個參數為間格 step,

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[1:8:2])

輸出結果如下,

1
[2, 4, 6, 8]

印出串列倒數3個元素

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[-3:])

輸出結果如下,

1
[7, 8, 9]

印出串列第2個元素,跟上面不一樣唷!別搞混了~

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[-3])

輸出結果如下,

1
7

印出串列從尾端到頭端

1
2
l = [1,2,3,4,5,6,7,8,9]
print(l[::-1])

輸出結果如下,

1
[9, 8, 7, 6, 5, 4, 3, 2, 1]

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python list 串列
Python 新手入門教學懶人包
Python 讀檔,讀取 txt 文字檔
Python 字串分割 split
Python 取代字元或取代字串 replace
Python 產生 random 隨機不重複的數字 list
Python print 格式化輸出與排版
Python PIL 讀取圖片並顯示
Python OpenCV resize 圖片縮放

C/C++ selection sort 選擇排序法

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

如果不想自己刻一個排序法可以使用現成 C 提供的 qsort 或 C++ STL 標準函式庫提供的 std::sort
以下開始介紹選擇排序的原理,

選擇排序法 selection sort 基本原理

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

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

1
2 8 6 10 4

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

1
2 4 6 10 8

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

1
2 4 6 10 8

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

1
2 4 6 8 10

迴圈結束,排序完成,

C/C++ 實作選擇排序法 selection sort

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

cpp-selection-sort.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
32
33
34
35
// g++ cpp-selection-sort.cpp -o a.out
#include <stdio.h>

void selection_sort(int array[], int n) {
for (int i=0; i<n-1; i++) {
int min_idx = i;
for (int j=i+1; j<n; j++) {
if (array[j] < array[min_idx]) {
min_idx = j;
}
}
// swap
int temp = array[min_idx];
array[min_idx] = array[i];
array[i] = temp;
}
}

int main() {
int array[] = {10,8,6,2,4};
printf("排序前 = ");
for (int i=0; i<5; i++) {
printf("%d ", array[i]);
}
printf("\n");

selection_sort(array, 5);

printf("排序後 = ");
for (int i=0; i<5; i++) {
printf("%d ", array[i]);
}
printf("\n");
return 0;
}

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

1
2
排序前 = 10 8 6 2 4 
排序後 = 2 4 6 8 10

其它相關文章推薦
Python selection sort 選擇排序法
C/C++ 新手入門教學懶人包
std::sort 用法與範例
std::find 用法與範例

C++ 寫檔,寫入txt文字檔各種範例

本篇 ShengYu 介紹 C++ 寫檔,寫入txt文字檔各種範例,上一篇介紹了 C++ 讀取文字檔,不熟練的話可以先複習一下,
以下 C++ 寫入文字檔的介紹內容將分為這幾部份,

  • C++ std::ofstream 寫入文字檔
  • C++ 將 C-Style 字元陣列的資料寫入文字檔
  • C++ 將 vector<string> 的資料寫入文字檔

C++ std::ofstream 寫入文字檔

這邊示範用 C++ std::ofstream 來寫入 txt 文字檔,不管是 char 陣列或 std::string 還是 int,甚至 float 跟 double 通通放進 ofstream 流不用錢(誤),通通放進 ofs 流會自動將這些變數進行轉換,

cpp-txt-write.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-txt-write.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ofstream ofs;
int n = 123456;

ofs.open("output.txt");
if (!ofs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

ofs << "Hello world " << n << "\n";
ofs << "This is a output text example\n";
ofs.close();
return 0;
}

執行起來會獲得這樣的執行結果,

1
2
Hello world 123456
This is a output text example

上述例子是用 ofstream::open() 開檔,當然你也可以使用 fstream::open(),然後在指定是 std::ios::out 就可以了,

1
2
3
std::fstream ofs;
ofs.open("output.txt", std::ios::out);
// ...

C++ 將 C-Style 字元陣列的資料寫入文字檔

這邊示範 C++ 將 C-Style 字元陣列的資料寫入文字檔裡,我們以學生姓名與學生分數為裡,總共有四名學生的資料,學生姓名存放在 char 陣列裡(name),學生分數放在 int 陣列裡(score),接著用迴圈去迭代將資料寫出,但要先計算出迭代次數,這邊使用 sizeof(score) / sizeof(int) 來計算出陣列大小,不可使用 sizeof(name) / sizeof(char) 去計算出大小,這意義不同。

接下來就看看完整程式怎麼寫,

cpp-txt-write2.cpp
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-txt-write2.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ofstream ofs;
char name[4][256] = {"Alan", "John", "Tony", "Mary"};
int score[] = {75, 95, 60, 80};

ofs.open("output.txt");
if (!ofs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

int size = sizeof(score) / sizeof(int);
for (int i = 0; i < 4; i++) {
ofs << name[i] << " " << score[i] << "\n";
}
ofs.close();
return 0;
}

結果輸出如下,

1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

C++ 將 vector<string> 的資料寫入文字檔

這邊示範最常使用到的 std::vector 容器,將 std::vector 容器裡的元素(這邊示範 std::string) 寫入到文字檔裡,

cpp-txt-write3.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
// g++ cpp-txt-write3.cpp -o a.out -std=c++11
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

int main() {
std::ofstream ofs;
std::vector<std::string> str;
str.push_back("Hello world\n");
str.push_back("12345\n");
str.push_back("This is a output text example\n");

ofs.open("output.txt");
if (!ofs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

for (auto &s : str) {
ofs << s;
}
ofs.close();
return 0;
}

結果輸出如下,

1
2
3
Hello world
12345
This is a output text example

以上就是 C++ 寫檔,寫入txt文字檔各種範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
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++ bubble sort 泡沫排序法

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

如果不想自己刻一個排序法可以使用現成 C 提供的 qsort 或 C++ STL 標準函式庫提供的 std::sort
以下開始介紹泡沫排序的原理,

泡沫排序法 bubble sort 基本原理

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

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

1
2
3
4
4 6 8 10 2
4 6 8 10 2
4 6 8 10 2
4 6 8 2 10

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

1
2
3
4 6 8 2 10
4 6 8 2 10
4 6 2 8 10

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

1
2
4 6 2 8 10
4 2 6 8 10

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

1
2 4 6 8 10

迴圈結束,排序完成。

C/C++ 實作泡沫排序法 bubble sort

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

cpp-bubble-sort.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
32
// g++ cpp-bubble-sort.cpp -o a.out
#include <stdio.h>

void bubble_sort(int array[], int n) {
for (int i=0; i<n-1; i++) {
for (int j=0; j<n-i-1; j++) {
if (array[j] > array[j+1]) {
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}

int main() {
int array[] = {6,4,8,10,2};
printf("排序前 = ");
for (int i=0; i<5; i++) {
printf("%d ", array[i]);
}
printf("\n");

bubble_sort(array, 5);

printf("排序後 = ");
for (int i=0; i<5; i++) {
printf("%d ", array[i]);
}
printf("\n");
return 0;
}

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

1
2
排序前 = 6 4 8 10 2 
排序後 = 2 4 6 8 10

氣泡排序法時間複雜度

氣泡排序法(Bubble Sort)的時間複雜度如下:
Worst 最壞時間複雜度:O(n^2)
Best 最佳時間複雜度:O(n)
Average 平均時間複雜度:O(n^2)

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

以上就是 C/C++ bubble sort 泡沫排序法介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
Python bubble sort 泡沫排序法
C/C++ 新手入門教學懶人包
std::sort 用法與範例
std::find 用法與範例

Visual Studio Code (VS Code) 跳至某一行的快捷鍵

有時候使用 Visual Studio Code (VS Code) 想要跳至某幾行,不知道 VS Code 有沒有快捷鍵可以使用?尤其要在一個數千數萬行的大型文件裡頭要用滑鼠一直滾,或者一直按 Page Down 會按到天荒地老,還沒看到要看的行數時,眼睛已經失焦甚至流目油了,實在是很不智慧的作法,這篇來介紹怎麼在 Visual Studio Code (VS Code) 開啟文件後快速地跳至某一行,

你只要按下 Ctrl + g 快捷鍵就會跳出一個輸入框,

接著在 : 冒號後面輸入你要跳去的行數,例如第10行

接著按下 Enter,你的游標就飛快地奔跑到第10行前面去了!這是不是很神奇:D
善用快捷鍵真的是很方便又快速呢~~~

其它相關文章推薦
Visual Studio Code 常用快捷鍵
Visual Studio Code 找對應大括號的快捷鍵
C/C++ clang-format 對程式碼風格排版格式化
Qt Creator 常用快捷鍵
vim 常用快捷鍵

C++ 讀檔,讀取txt文字檔各種範例

本篇 ShengYu 介紹 C++ 讀檔,讀取txt文字檔各種範例,C++ 讀檔是寫程式中很基礎且實用的技巧,尤其是讀取文字檔再作後續的處理算是很常會用到的功能,
以下 C++ 讀取文字檔的介紹內容將分為這幾部份,

  • C++ std::ifstream 讀取文字檔到 C-Style 陣列裡
  • C++ 一次讀取全部文字檔到 string 裡
  • C++ 一次一行逐行讀取到 C-Style 陣列裡
  • C++ 一次一行逐行讀取到 vector<string>

C++ std::ifstream 讀取文字檔到 C-Style 陣列裡

先來示範最簡單的讀取文字檔,建立完 ifstream 後使用 ifstream::open() 來開檔,之後使用 ifstream::read() 一次讀取全部文字檔,參數帶入 buffer 陣列以及要讀取的數量,要讀取的數量不能超過 buffer 的陣列大小,當然你也可以自行控制要讀取的數量,這邊只是示範讀取全部內容,

假如我們的文字檔長這樣

input.txt
1
2
Hello world
This is a input text example

讀進來後放到 buffer 後,這邊很簡單的用 cout 把它印出來,程式碼長這樣,

cpp-txt-read.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-txt-read.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs;
char buffer[256] = {0};

ifs.open("input.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

ifs.read(buffer, sizeof(buffer));
cout << buffer;
ifs.close();
return 0;
}

那麼會獲得這樣的執行結果,

1
2
Hello world
This is a input text example

上述例子是用 ifstream::open() 開檔,開檔時你也可以改使用 fstream::open(),然後再指定模式是 std::ios::in 就可以了,

1
2
3
std::fstream ifs;
ifs.open("output.txt", std::ios::in);
// ...

另外 txt 文字檔是放在資料下的話,不同作業系統下寫法稍有不同,
在 Windows 系統中 input.txt 放在 mydir 資料下的話,就這樣寫

1
ifs.open("mydir\\input.txt");

在 Linux 或 macOS 系統中 input.txt 放在 mydir 資料下的話,就這樣寫

1
ifs.open("mydir/input.txt");

C++ 一次讀取全部文字檔到 string 裡

這邊示範 C++ 將文字檔內容一次讀進 string 容器裡,開檔跟上個範例不同的是這次我們在 ifstream 建構時一併開檔,

第一種方法為先將 ifs.rdbuf() 串流到 stringstream ss 裡,再用 ss.str() 轉換成 std::string

cpp-txt-read2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-txt-read2.cpp -o a.out
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main() {
std::ifstream ifs("input.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1;
}

std::stringstream ss;
ss << ifs.rdbuf();
std::string str(ss.str());
cout << str;
ifs.close();
return 0;
}

第二種方法是使用 istreambuf_iterator 的方式,再建立 std::string
要注意的是 std::string str() 第一個引數裡有多一對 () 小括號,否則結果會截然不同,

cpp-txt-read3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// g++ cpp-txt-read3.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs("input.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1;
}

std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
cout << str;
ifs.close();
return 0;
}

C++ 一次一行逐行讀取到 C-Style 陣列裡

這次使用 ifstream::getline() 取得一行的檔案資料放入 C-Style 陣列,搭配 while 迴圈逐行讀入 C-Style 陣列直到檔尾,每一次的 getline 都會覆蓋之前的 buffer 資料而不是添加在後面,

cpp-txt-read4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// g++ cpp-txt-read4.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs;
char buffer[256] = {0};

ifs.open("input.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

while (!ifs.eof()) {
ifs.getline(buffer, sizeof(buffer));
cout << buffer << "\n";
}
ifs.close();
return 0;
}

C++ 一次一行逐行讀取到 vector<string>

那我們來個實際的例子,假如我們讀取一個txt文字檔裡面有學生姓名,txt文字檔內容如下,

input2.txt
1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

程式碼如下,使用 std::getline() 將 std::ifstream 每次讀取一行的結果放到 std::string 裡,接著用 cout 印出來確認看看,有時候也會放入 vector 容器裡讓之後的程式作後續處理,所以這裡宣告成 vector<string>,這樣就可以一直放入多個 string,

cpp-txt-read5.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
// g++ cpp-txt-read5.cpp -o a.out
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main() {
std::vector<std::string> names;
std::ifstream ifs("input2.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

std::string s;
while (std::getline(ifs, s)) {
cout << s << "\n";
names.push_back(s);
}
ifs.close();
return 0;
}

根據上個範例,假如我們這次是讀入某一個科目的學生分數資料進行處理的話,這個txt文字檔裡面有學生姓名與學生分數,txt文字檔內容如下,

input2.txt
1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

那我們這次要見識一下 >> operator 流的威力,實做方法如下:

cpp-txt-read6.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
// g++ cpp-txt-read6.cpp -o a.out
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main() {
std::vector<std::string> names;
std::vector<int> scores;
std::ifstream ifs("input3.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

std::string name;
int score;
while (ifs >> name >> score) {
cout << name << " " << score << "\n";
names.push_back(name);
scores.push_back(score);
}
ifs.close();
return 0;
}

輸出結果如下,>> operator 還可以幫你轉換成你要的變數型態,就像範例中的 score,不用自己在那邊,一切自動轉換~~夠快速方便懶惰了吧!

1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

那麼你可能會想問上面的範例是空白作分隔,那如果是 tab 作分隔呢?那如果是逗號作分隔呢?
關於這部分下次我再寫一篇給大家講解,

下一篇文章是 C++ 寫檔,寫入txt文字檔各種範例

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
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 用法與範例