C++[0]
C++ 小社課第一堂
課程目錄
課程目錄
甚麼是C++?
程式語言介紹
C++
是一種被廣泛使用的中階電腦程式設計語言。



組合語言
C++
Python
接近機器語言
可直接操作硬體與
記憶體
對機器抽象程度高
接近人類語言
介於兩者之間
競程方面
C++的效率高(較python而言)
有強大的標準模板庫(STL)
競程的線上題解、模板幾乎都以C++為主
......
總之C++適合競程
缺點/危險性
寫C++時,大部分時間會需要手動管理記憶體
然後有時候就會發生:
Memory leak
Dangling pointer
Buffer overflow(哈哈你迴圈是不是寫爛了)
Use-after-free
等各種導致記憶體炸掉的fatal error
還有其他例子
像 srcatch 當機只會是網頁,或者 App 本身
而 C++ 是可以干涉硬體運作的
怎麼寫C++?
編輯器、編譯器
編輯器與編譯器
你在打扣的時候,是在編輯器上打扣。
編譯器負責將你打的扣轉成電腦看得懂的編碼。
還會進行優化跟報錯
編輯器的選擇



VS code
Vim
Emacs
編輯器的介面

編輯器會將對你打的扣上色
讓你的扣會比較好讀
然後這份扣肉眼可見的難讀
不要學我都不空格
也不要main(100)
阿今天用甚麼
因為VS code、Vim這些不是安裝需要時間、就是門檻高
痾絕對不是因為我不會
所以今天用一個線上編輯器:online gdb

介面介紹

執行程式
除錯模式
強制中止程式

記得選語言(C++)才能編譯
介面介紹
執行程式後的介面(console)
顯示輸出

C++ 初始模板講解
要開始報錯囉
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, OCaml, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
#include <iostream>
int main()
{
std::cout<<"Hello World";
return 0;
}這是你在把語言調成C++後出現的扣
上面的/**...是註解,不影響程式,先把它砍了
#include <iostream>
int main()
{
std::cout << "Hello World";
return 0;
}你會發現,這份扣跟講義上的有點區別,講義有寫原因
請先將扣改成講義上的格式
記得大括號不要換行
#include <iostream>
using namespace std;
int main() {
cout << "Hello World";
return 0;
}跑跑看
會出現這個console,顯示你的輸出

小小小練習
請將編輯器中的扣全部刪掉,嘗試自己寫出一個完整的初始模板
過程中遇到報錯時可參考講義對應的解決方法
輸入輸出
大於小於不要寫反
cin 與 cout
cin >> a >> b;
cout << a << b;cin >> 的箭頭是向右,將輸入丟進變數裡
cout << 的箭頭是向左,將變數丟到輸出裡
輸入是在 console 裡輸入
變數怎麼做?

int
int a, b;int 是整數
宣告兩個變數,名稱為 a 與 b
順帶一提,如果宣告時沒有給定一個固定值的話,a 與 b 的值可能會亂跑,所以記得歸零

int a = 0, b = 0;
這裡講的變數其實就是 srcatch 的變數
只是能存的資料類型有限,下一單元講
endl
cout << a << endl;endl : end of line
用處是換行
記得要加,不然之後使用 vim 之類的編輯器會出事
小小小練習
int a, b;輸入 a 與 b 兩個整數,輸出 b 與 a 兩個整數,兩個數字中間要換行
輸入與輸出的數字順序相反
範例:
輸入 1 3
輸出
3
1
阿記得加分號
解答
int a, b;
cin >> a >> b;
cout << b << endl;
cout << a << endl;有記得加分號嗎
運算子(數學)
+-*/=
還有%
int a;
a = 1 + 2;
cout << a << endl; //3int a;
a = 1 * 2;
cout << a << endl; //2int a;
a = 1 - 2;
cout << a << endl; //-1加法
減 法
乘法
int a;
a = 3 / 2;
cout << a << endl; //1int a;
a = 5 % 3;
cout << a << endl; //2除法(取商)
取模(取餘數)
為甚麼 / 是取商?
下個單元會講
int a, b;
b = 3;
a = b;
cout << a << endl //3=(賦值)
將 = 右邊的值丟到左邊的變數裡
不要記反
喔對後面還會講 ==
不要打錯
小小小實作
輸入兩個數字 a,b
輸出 a+b 的值
cin >> a >> b;
cout << a + b << endl;資料型態
很多
各種資料型態
| 名稱 | 型態 |
|---|---|
| int | 整數 |
| long int | 整數 |
| long long int | 整數 |
| unsigned long long | 非負整數 |
| bool | |
| float | 小數 精度6~7位 |
| double | 小數 精度15~16位 |
| long double | 小數 精度18~21位 |
| char | 字元 |
| string | 字串(多個字元) |
long long int 非常重要
有時候競程會遇到這種題目
(輸入)
這時候,用 int 與 long long int 會有不同的結果

int a;
long long int b;
a = 1e15;
cout << a << endl;
b = 1e15;
cout << b << endl; 所以記得有些題目要開 long long int
例如暑訓小比賽
為何 int 做除法時只會得到商
int 做計算時,得出的答案型態也是 int
而 int 只能存整數,不能存小數
對於小數會進行向下取整
因此 3/2 再向下取整 -> 1
int a;
a = 3 / 2;
cout << a << endl; //1那這樣呢?
3 與 2 都是 int,int 運算得出的數值也是 int
即使 a 是浮點數,但 3/2的結果是 1
再用 = 賦值,a = 1
float a;
a = 3 / 2;
cout << a << endl; //???那這樣呢?
2.0 3.0 是浮點數,計算中有浮點數時,
得出的結果就是浮點數
所以三種狀況皆為 a = 1.5
float a;
a = 3 / 2.0;
cout << a << endl; //???
a = 3.0 / 2
cout << a << endl; //???
a = 3.0 / 2.0
cout << a << endl; //???精度是甚麼意思
4/3=1.333333......
那他會真的一直都是 3 嗎?
float a;
a = 4 / 3.0;
cout << a << endl; //1.33333
printf("%.7f\n",a); //輸出7位小數
printf("%.10f\n",a); //輸出10位小數
printf("%.15f\n",a); //輸出15位小數
float 的精度只有 7 位
也就是說小數超過 7 位的部分,float 會爛掉
而 double 與 long double則不會
精度是甚麼意思
double 與 long double 的精度較高
數值較為準確
在某些需要精確計算的時候很重要
double a;
a = 4 / 3.0;
cout << a << endl; //1.33333
printf("%.7f\n",a); //輸出7位小數
printf("%.10f\n",a); //輸出10位小數
printf("%.15f\n",a); //輸出15位小數long double a;
a = 4 / 3.0;
cout << a << endl; //1.33333
printf("%.7f\n",a); //輸出7位小數
printf("%.10f\n",a); //輸出10位小數
printf("%.15f\n",a); //輸出15位小數
運算子(邏輯)與邏輯判斷
記得前面講的 == 嗎
bool
bool 中存的 0 與 1,其實就是 false and true
bool a = true;
cout << a << endl; //1if
bool a = true; //也可以寫false
if(a) {
cout << "Hello World!" << endl;
}
else {
cout << "Nah this script won't run to here" << endl;
}這是判斷條件
如果條件成立,則執行此程式
如果條件不成立,則執行此程式
a 為甚麼可以放在這裡?
由於 C++ 中的條件判斷,也是回傳 true or false
所以 bool 放在這裡是沒有問題的
不如說這裡本來就是放 bool 的資料型態
而 a 為 true,所以此條件永遠成立
邏輯運算子
== 當兩邊的值相等,回傳 true,反之回傳 false
!= 當兩邊的值不相等,回傳 true,反之回傳 false
&& 當左右兩個條件皆為 true,回傳 true,反之回傳 false
|| 當左右兩個條件至少其中一個為 true,回傳 true,反之回傳 false
! 當條件為 true,回傳 false,反之回傳 true
範例
這是一個判斷奇偶的程式
int a;
cin >> a;
if (a % 2 == 1) {
cout << "odd" << endl;
}
else {
cout << "even" << endl;
}|| 與 && 的用法
這是一個判斷閏年的程式
如果 a 是 400 的倍數:閏年
否則如果 a 是 4 的倍數,且 a 不是 100 的倍數:閏年
......
int a;
cin >> a;
if (a % 400 == 0) {
cout << "leap year" << endl;
}
else if(a % 4 == 0 && a % 100 != 0) { //else if講義有細說
cout << "leap year" << endl;
}
else {
cout << "normal year" << endl;
}組合條件的用法
如果 a 是 2 的倍數,且 a 不是 3 的倍數,則做A
或者如果 a 是 5 的倍數,則做A
int a;
cin >> a;
if (a % 5 == 0 || (a % 2 == 0 && a % 3 != 0)) {
// 其實我不知道我這裡要放甚麼
} 小小實作
只使用一行 if 判斷閏年
int a;
cin >> a;
if (a % 400 == 0 || (a % 4 == 0 && a % 100 != 0)){
cout << "leap year" << endl;
}
else cout << "normal year" << endl;
return 0;提示:組合條件
ascii、字元與字串
你知道嗎,online gdb可以發出聲音喔

char
可存放一個字元
char a='O'
cout << a << endl; //O" " 與 ' '
嘗試打出這個程式,你會發現......
char a="O";
因為 " " 裡可以包多個字元,並且 " " 自身的資料型態與 char 不同,是 char 無法存儲的。
而 ' ' 裡包的一定要是單個字元,資料型態即為 char
順帶一提,一個全形符號與中文字占三個字元
多個字元(字串)
那 " " 應該要用哪個資料型態存?
string a="WOW";String 可以存儲多個字元
並且 string 不能存儲用 ' ' 包起來的單個字元

string a='O';string a="O";
ascii

ascii code使用在早期美國的通訊中
每個字元對應一個二進位編碼,電腦才看得懂
ascii表就是為了固定一套編碼,防止因為出現多個編碼導致電腦混亂的狀況出現
int('A')
int a;
a = int('A');
cout << a << endl;//65int() 能夠將括號中的值轉成 int
而將字元轉成 int,就能得到其對應的 ascii code
禮拜五的密碼學應該會提到凱薩加密
將每個字元按照字母表往前或往後移動固定單位
方法就是將每個字元的 ascii 值改變一個固定數值

移動距離為 3 的情況
控制字元

回想剛剛的 ascii 表
是不是少了甚麼?
32 以前的 ascii code 呢?
<32、127 的 ascii 對應的是控制字元
而 ascii code 7 是響鈴
這就是讓 gdb 發出聲音的方法
叮~~
char a;
a = char (7);
cout << a << endl;char() 可以將括號內的值轉成字元型態
而 char(7) 即是將 ascii code 轉成字元
將其輸出你就能聽到響鈴聲

順帶一提,'\n'是換行
ascii code 為 10

cout << '\n';再順帶一提,windows的enter是'\r\n'
ascii code 分別為 13,10
游標回到行首,並且換行
好用標頭檔
還醒著嗎
標頭檔
講義最開始有講 iostream 這個標頭檔
他可以幹嘛?
透過 iostream 的引入,編譯器得以識別 cin 為某某種類型的標準輸入物件,並利用相關的運算子重載與函式來完成輸入邏輯
可以試試把 iostream 拔掉之後做 cin cout 的動作
你會發現他報錯了
可以簡單理解為:引入 iostream 後,cin cout 的動作才能順利進行
#include <algorithm>(等一下講)
int n;
int a[n];
sort (a, a+n);將陣列由小到大排序
int n, target = 3;
int a[n];
lower_bound(a, a+n, target);取得陣列中第一個大於等於target 值的位置(限陣列為以排序狀態)
int n, target = 3;
int a[n];
upper_bound(a, a+n, target);取得陣列中第一個大於target 值的位置(限陣列為以排序狀態)
int a = 3, b = 5;
cout << min (a, b) << endl; //3
cout << max (a, b) << endl; //5min( , ) 獲取兩值中較小的一個
max( , ) 獲取兩值中較大的一個
#include <cmath>
long double pi = 3.14159365358979323
long double a = 90 * pi / 180; //弧度
cout << sin(a) << endl; //正弦,輸出為1三角函數
int a = 10;
cout << log(a) << endl; //2.30259......log(以 e 為底)
e = 2.718281828...
int a = 4;
cout << sqrt(a) << endl;//2根號
int a = -3;
cout << abs(a) << endl;//3絕對值
float a = 4.5
cout << floor(a) << endl;// 4
cout << ceil(a) << endl;// 5
cout << round(a) << endl;// 5向下取整
向上取整
四捨五入
#include <utillty>
int a = 3, b = 5;
swap(a, b);
cout << a << ' ' << b << endl //5 3交換括號內的兩個值
#include <bits/stdc++.h>
哈哈你剛剛都白學了
一次引入C++中幾十個常用的函式庫
包含但不限於上述的三個函式庫
(只適用在競賽中,不適用在專案製作)

阿記得空格
然後不要main (100)
陣列
第一個是第零個
陣列是甚麼
像是一個橫向的櫃子,存放著多個值
一個位址對應一個值
值(value)
位址(index)
一個位置存放一個值,像櫃子一樣
位置是從0開始!!!!!
此陣列的第 0 個位址,存放的數字是 1
人通常會將最左邊的當作第一個
但是電腦是從 0 開始,這很重要
int a[5];宣告
int 為此陣列中值的資料型態
a 為此陣列的名稱
[5] 為此陣列的大小
int a[5] = {1, 2, 3, 4, 5};大括號為此陣列內容,可加可不加
int a[5] = {1, 2, 3, 4, 5};
cout << a[0] << endl; //1
cout << a[4] << endl; //5記得,陣列的位址是從 0 開始
同時結尾的位址是其大小減一
稱為 0-based
int a[5] = {0};int a[5] = {1, 2, 3, 4, 5};同樣的,int 的資料也要歸零
歸零的程式長這樣
迴圈
迴圈是甚麼?
假設我今天想要輸出一個陣列裡的所有值
int a[5] = {1, 2, 3, 4, 5};
cout << a[0] << ' ';
cout << a[1] << ' ';
cout << a[2] << ' ';
cout << a[3] << ' ';
cout << a[4] << ' ' << endl;但如果陣列長這樣呢?
int a[30000] = {......};總不可能要寫 30000 次 cout 吧?
這時候就需要用到迴圈,迴圈可以方便的做重複執行的動作
FOR 迴圈
int a[30000] = {......};
for (int i = 0 ; i < 30000 ; i++) {
cout << a[i] << ' ';
}
cout << endl;for 裡面要放三個東西
1. 宣告一個計數器變數
2. 設定一個條件,在這個條件成立時,繼續迴圈
3. 每次迴圈重新開始時,要做的事情(通常是計數器 +1)
每個東西用分號隔開
i++ 即為 i = i + 1
這就是 C++ 中 ++ 的意義
FOR 迴圈
int a[30000] = {......};
for (int i = 0 ; i < 30000 ; i++) {
cout << a[i] << ' ';
}
cout << endl;迴圈進行的流程:
計數器宣告
確認條件是否成立
進行迴圈
結束後回到開頭
計數器 +1
確認條件是否成立
進行迴圈
......
再提醒一次,陣列的位址是從 0 開始
最後一個的位址是大小減一
所以計數器的初始值為 0
條件是 <30000(到 30000 時離開迴圈)
int a[30000] = {......};
for (int i = 0 ; i < 30000 ; i++) {
cin >> a[i];
}
for (int i = 0 ; i < 30000 ; i++) {
cout << a[i] << ' ';
}
cout << endl;當然,輸入時也需要迴圈
WHILE 迴圈
有聽過 3n+1 問題嗎?
給定一個正整數,如果是奇數,則將此數字 *3+1
如果是偶數,則將此數字 /2
重複進行,會發現每個數字到最後都會變成 1
進入 1 -> 4 -> 2 -> 1 的循環
怎麼用 while 迴圈實作?
while(條件) {
//執行的程式
}WHILE 迴圈
while() 的括號中放的是條件
符合條件時則繼續進行此迴圈
while(條件) {
//執行的程式
}int a;
cin >> a;
while (a != 1) {
cout << a << ' ';
if (a % 2 == 1) a = a * 3 + 1;
else a = a / 2;
}
cout << a << endl;當 a 不等於 1 時,繼續迴圈
換言之,當 a 等於 1 時,離開迴圈
小實作
給定一個正整數 n,作為陣列大小
給定一個長度為 n 的整數陣列 a
給定兩個非零整數 l, r,l <= r
求此 l~r此區間內(包含 l 與 r)所有數字的總和
0<=l,r<=n-1,也就是說 l 與 r 為 0-based
範例:
input:
5
1 2 3 4 5
1 2
ouput: 5
小實作答案
int n;
cin >> n; //輸入n
int a[n]; //宣告陣列 a,大小為n
for (int i = 0 ; i < n ; i++) {
cin >> a[i]; //輸入整個陣列
}
int l, r;
cin >> l >> r; //輸入 l 與 r
int sum = 0; //記得宣告時要歸零,否則 sum 初始值會亂跑
for (int i = l ; i <= r ; i++) {
sum = sum + a[i]; //加總
}
cout << sum << endl; //輸出答案buffer overflow
int a[5];
cout << a[5]; //???會發生甚麼事呢?
陣列是存取在記憶體當中
而陣列長度只有 5 ,沒有 a[5]
所以當編譯器在記憶體中抓不到 a[5]的時候,他就會亂抓,導致輸出一個隨機的數字
int a[5];
cout << a[10000]; //???如果是這種更極端的情況呢?
報錯,回傳 code 139
當你看到 code 139 時,記得檢查迴圈條件是不是設錯了

continue 與 break
for (int i = 0 ; i < 10 ; i++) {
if (i < 5) continue;
cout << i << ' ';
}for (int i = 0 ; i < 10 ; i++) {
if (i > 4) break;
cout << i << ' ';
}continue:
不執行 continue 之後的程式碼,跑完一次迴圈到開頭
output:
5 6 7 8 9
break:
離開迴圈
output:
0 1 2 3 4
EOF(end of file)

輸入直到讀取到檔案結尾(end of file)
int a;
while (cin >> a) {
//do something
}每次輸入時,都會進行迴圈
讀取到檔案結尾時,會被視作 -1
此時就回離開迴圈
do while
do {
//do something
}
while (條件);先執行迴圈,再判斷要不要繼續進行
while 後面記得加分號
結束啦 :D
C++基本語法
By 硼/Boron
C++基本語法
- 176