~~ 2019/10 更新:終於把它寫完整了TvT 寫這篇寫了三年哈哈。補了彈出視窗, cin/cout, endian, stringstream. ~~

以下是我整理出來的課外筆記,會盡量避免正規 C/C++ 課堂會教的內容~

跟大家分享,希望能長知識喔~!

 

Input/Output


1. getch(), getche()

大家都有聽過 getchar(),但 getch() 就比較少人聽過了~

它的功能是,按下去鍵盤按鍵時,不需要按 Enter 就會直接讀進去,而且螢幕不會顯示!

在製作CMD小遊戲時還滿實用的,eg. 按w往上,按a往左,不用每個指令再按Enter 才能送出去

<conio.h>  ->  getch(): 不需按Enter, 螢幕不會顯示

getche(): 不需按Enter, 螢幕會顯示

 

2. kbhit()

可以偵測鍵盤在這瞬間有沒有被按下去~ 也是在 <conio.h> 裡面

這在製作小遊戲,特別是動態的互動式程式時,也很實用,

eg. 包在迴圈裡面,每次都檢查 if( kbhit() ),當有按按鍵時執行一些動作 (例如人物移動)

 

3. ungetc()

從stdin 讀進來後是不是就回不去了?

其實是可以再吐回去的,一次一個字元: ungetc(x, stdin)

C++也有C++ 的方法: cin.unget(),不需要指定回收什麼東西

 

4. 顯示兩位元寬的文字:%c%c

eg. 想要儲存一個磚塊 █,會需要兩個char,

char a[3] = "█";

想要印出一個它時,會需要兩個 %c%c 緊貼在一起,才能"拼湊"出 █ 喔!

printf("磚塊 = %c%c", a[0], a[1]);

註:中文字都是兩位元寬的喔~

 

5. Windows 彈出式視窗

首先 include <windows.h>,然後呼叫 MessageBoxW 函式,eg.

LPCWSTR text = L"Hello world";

LPCWSTR title = L"Hi";

MessageBoxW(NULL, text, title, 0x40);

注意,它需要先是 wide string,然後再轉成 LPCWSTR

至於最後一個參數,填不同值會有不同效果喔!

最後一位是按鈕,0=OK,1=OKCancel,4=YesNo,3=YesNoCancel。

倒數第二位是圖示,0=無,1=Stop,2=Question,3=Warning,4=Info。

(eg. 0x23 會有三個按鈕,然後圖示是問號)

 

6. cin / cout 比 printf / scanf 還要慢?

其實理論上應該要一樣快的,但因為有一些額外的機制,造成速度被拖慢了

主要的罪魁禍首是 flush,以及 C++C 的一個同步機制。(請見寫得很好的 這篇

cin / cout 變得跟 printf / scanf 一樣快的方法:

1) 在開頭加上:ios_base::sync_with_stdio(false);

2) 不要使用 endl,一律改用 cout << "\n";

3) 在開頭加上:cin.tie(NULL);

 

 

程式運作底層


1. Function 是右到左參數傳遞

這點老師可能會提到,就是當呼叫 foo(c++, c++, c++) 時,

void foo(int a, int b, int c){ ... } 函數裡面的 a 會最大,c 會最小。

 

2. Big-endian & Small-endian

這點老師可能也會提到。Big-endian 比較像是「我們想像中的」變數在記憶體中的樣子,

例如 0x01020304,在記憶體中,從低位置到高位置會是 [01]-[02]-[03]-[04]

但是 Little-endian 正好相反,會是 [04]-[03]-[02]-[01]

今天大多數的 CPU 都是 Little-endian,理由是效率比較好。

不信的話,你可以試試以下程式碼:

int x = 0x01020304; char c[4];
FILE* f = fopen("num", "rwb");
fwrite(&x, sizeof(int), 1, f);
fread(c, sizeof(char), 4, f);
printf("%d%d%d%d\n", c[0], c[1], c[2], c[3]);

 

 

操作其他檔案


1. 跟 CMD 合作

C/C++ 可以直接在 CMD 執行指令,只需要包在 system("...") 裡面就可以了,

eg. system("shutdown -s"),  system("cls") -> 清空螢幕(可以拿來製作動態使用者介面)

 

2. 呼叫其他程式同步執行 (Multi-Thread)

呼叫其他程式還不簡單?可以直接透過 CMD 呼叫: system("D:\\folder\\programB.exe");

但是要做到 "同步" 執行,就需要 multi-thread(多執行緒) 了~

<process.h> 底下,可以用 spawnl(),

例如: spawnl(P_NOWAIT, "D:\\folder\\programB.exe", "D:\\folder\\programB.exe", "13", "apple", NULL);

P_NOWAIT 就是不用等它跑完,第二個參數是exe 的 path,第三個以後是 argv[0], argv[1], argv[2], ....,最後一個固定都是填 NULL,

它的回傳值,就會是程式的回傳值,如果順利執行就是 0。

更多參數可參考: 這篇

 

3. 取得資料夾名稱

透過 CMD 是有能力把資料夾名稱列表輸入進檔案裡的,eg. dir/b > D:\folder\direct.txt

然後執行完指令,再用讀檔的方式來取得資料夾資訊!

但其實也可以省去 CMD 當中間人,直接取得資料夾資訊喔,

<dirent.h> 底下,先宣告代表資料夾的指標 DIR* dir;  以及讀進相關資訊的指標 struct dirent *info;

再來有點像是C 的開檔讀檔,dir=opendir("D:\\folder\\2016example"),之後就可以用它來讀資訊啦,info=readdir(dir)

可以顯示檔名 info->d_name,或者檔名的長度 info->d_reclen,最後記得要關閉資料流 closedir(dir);

(不過不能有中文的資料夾名稱,其實不是很好用XD)

 

 

C++功能學不完


1. C++ Container 不會 buffer overflow

如題,Cpp 的容器都是動態的 (eg. string, vector, list, ...)

所以基本上還滿安全的,想要透過 buffer overflow 來駭進 C++ 程式沒那麼容易嘿嘿~

不同 container 特性以及有什麼功能,請多多參訪 cppreference

 

2. 如何清空 stringstream

你可能會想說,清空 stringstream 還不簡單,不就是 ss.str("") 就好了嗎?(假設 ss 是你的 stringstream)

NO!因為當你把 stringstream 讀完了以後,你會發現你無法再寫新的資料進去了!

所以正確的方式是:ss.str(""),ss.clear() 才對。

 

3. Iterator

不曉得老師會不會教這個,基本上C++ 每種容器都含有各自的 iterator 給你用,

iterator(疊代器) 是類似指標的概念,宣告時: list<string>::iterator  itS;  注意它需要註明是哪種容器的 iterator 喔~

使用時可以 for(itA=v.begin; itA!=itB; itA++)

 

4. Insert/Erase

很多C++ 的容器都有 inserterase 功能,所以 vector 也可以拿來當 list, queue 來使用 XP

用法都是需要透過 iterator,假設 itV 指向 vector 第五個元素,那麼可以 v.insert(itV, 3),就會在第五個元素之前插入一個 3

假設 itV2 指向 vector 第八個元素,那麼 v.erase(itV, itV2),就會移除元素 5, 6, 7,因為不會包含最後一個 [A, B)

不過,如果你講求程式效率的話,最好了解一下他們的時間複雜度(complexity),有些容器insert/erase 會花不少時間的喔!可以去cppreference 查詢~

 

5. freopen / rdbuf

在 C,可以使用 freopen("input.txt", "r", stdin),讓 file stream 如同 stdin 一樣被讀近來,

所以之後所有的 scanf 都會從檔案讀進來

C++,可以使用 cin.rdbuf( fin.rdbuf() ),將 fin 導向 cin,也會有同樣的效果

如果要把 cerr 關掉,也可以 cerr.rdbuf(NULL),讓它導向 NULL

 

 

arrow
arrow

    Davidhu127 發表在 痞客邦 留言(0) 人氣()