---
tags: 2021CRC Extra Resources
title: 社課額外補充教材:變數與運算
---
# 社課額外補充教材 : 變數與運算
如果你覺得社課還算輕鬆,這裡提供你一些額外的補充教材。
這些是我們在備課的時候覺得稍微進階,或是篇幅太多,而沒有放在正式社課的內容。
---
這裡有目錄,左邊也有,可以跳到自己想看的地方
[TOC]
---
建議必看的地方 :
* 記憶體的觀念
* 有關字串的補充(第二部分)
* 字元運算
---
### 記憶體的觀念
記憶體是我們寫程式的好朋友,當我們宣告一個變數,就等同於在記憶體上畫出一個空間,
讓這個空間存放變數的值。所以你可以把變數理解成 **"一塊儲存可變動的值的記憶體空間"**。
記憶體在之後的指標跟資料結構的時候都會再提到,
#### 各種資料型態的記憶體空間
整數
* int、unsigned int : 4 bytes
* long long、unsigned long long : 8 bytes
浮點數
* float : 4 bytes
* double : 8 bytes
字元跟字串
* char : 1 byte
* string : 長度+1 bytes
---
### 字元與ASCII的範例Code
### 字元運算
整數、大寫字母、小寫字母的ASCII Code
分別都是連續的
```cpp=
char a = 'A';
a = char( a + 1 ); // a 的值由 A 變成 B
// 當然你也可以寫 char( int(a) + 1 )
```
```cpp=
#include<iostream>
using namespace std;
int main(){
char a = '0';
cout << a << endl;
cout << (int) a << endl;
a += 1; // a == '1'
if (a == '1') cout << "Yes" << endl;
cout << a << endl;
cout << a + 1 << endl;
}
```
---
### 有關字串的補充(第一部分)
其實字串是由字元所組成,最後會在結尾加上 '\0' 表結束
```cpp=
#include<iostream>
#include<string>
int main(){
char a[6] = {'h','e','l','l','o','\0'};
std::string b = "hello";
//和a一樣都是"hello"
char c[6] = "hello";
//也可以這樣寫
char d[5] = "hello";
//但不能這樣寫,記住要連'\0'也算進去
char e[] = "hello";
//也可以這樣寫,e的長度是6
}
```
那為什麼要用 std::string ?
因為 std::string 可以這樣
```cpp=
#include<iostream>
#include<string>
int main()
{
std::string b;
std::cin >> b; //可以輸入任意長度的字串
std::cout << b;
char a[] = "hello"; //a 的長度被限制在6
std::cin >> a; //輸入超過6-1個字會爆掉
}
```
怎麼做到的?
查查指標陣列吧,但看看就好
References:
[TutorialsPoint](http://www.tutorialspoint.com/cprogramming/c_strings.htm)
[W3School C++ : String](https://www.w3schools.com/cpp/cpp_strings.asp)
慎入:
[Microsoft Docs](https://docs.microsoft.com/zh-tw/dotnet/api/system.string.-ctor?view=net-5.0)
---
### 有關字串的補充(第二部分) : stoi and to_string
上課的時候我們有給過這張圖片:

其中有兩個函式 stoi(s) 跟 to_string(i)是在比較新的C\++版本,從**C\++11**之後才出現的。而因為DevC\++的默認C\++版本是很古老的C\++98,所以如果需要使用這兩個函式實作時,你會發現 compiler 一直跟你說:
**"to_string" / "stoi" is not declared in this scope.**
所以如果需要使用這兩個函式,我們需要把DevC\++的版本提高。
依序點開**Tools -> Compiler Options**,並在General的第一個方框內打上 **"-std=c++11"** ,即可把你的C\++版本手動升級到C\++11囉!

---
### 有關浮點數的補充
- 我想四捨五入怎麼做?
為您隆重介紹,std::setprecision!!
```cpp=
#include<iomanip> //setprecision要用的函式庫
#include<iostream>
int main(){
std::cout << std::setprecision(3);
//注意!此效果是全域的
//3表示的是總長度
std::cout << 3.1415926 << '\n'; //結果會是 3.14
std::cout << 13.75 << '\n'; //結果會是13.8
}
```
要怎麼只動到小數點後的位數?
```cpp=
#include<iomanip> //setprecision要用的函式庫
#include<iostream>
int main(){
std::cout << std::fixed << std::setprecision(3);
//加在setprecision前後都沒關係,效果一樣是全域
std::cout << 13.14159; //結果會是13.142
std::cout << 1.2; //結果會是1.200
}
```
沒錯,加了fixed後會自動補0
那要怎麼還原?
```cpp=
#include<iomanip> //setprecision要用的函式庫
#include<iostream>
int main(){
std::cout << std::fixed << std::setprecision(3);
//加在setprecision前後都沒關係,效果一樣是全域
std::cout.unsetf(ios::fixed);//這能將fixed效果關掉
//不過setprecision並不是能關的函式,只能還原成預設值
std::setprecision(6); //預設是6
//以下的輸出即是預設輸出
std::cout << 3.1415926; //結果會是3.14159
std::cout << 13.1415926; //結果會是13.1416
}
```
除此之外,有關輸出對齊的功能也一併放在iomanip
以下是解說
[Microsoft Doc](https://docs.microsoft.com/zh-tw/cpp/standard-library/iomanip-functions?view=msvc-160)
---
### 前綴詞
- 常數 const
- 正數 unsigned
- 加長 long
- 變短 short
```cpp=
const int a = 1;
//a之後就不能在程式中任意更改了
unsigned int b;
//b的長度比int大1,從0 ~ 4,294,967,295
long long (int) c;
//前一個long是前贅詞,後一個long是資料型態
short (int) d;
//比int還短,能存的值更少,最多到32767
```
#### const比你想的常見
```cpp=
1 的型態是 const int
'1' 的型態是 const char
"1" 的型態是 const char[2]
1.0 的型態是 const double
1.0f 的型態是 const float
```
#### 不過沒有所謂的 const bool
true和false是保留字
---
### 後綴詞
這要從auto說起
```cpp=
auto a = 1 //a的型態是int
auto b = '1' //b的型態是char
```
看出來了嗎?
auto會隨著後面指定的值轉換型態
可是我想讓a變成long long怎麼辦?
這時候就是後綴詞出馬的時候了
#### 各個資料型態的後綴
* u : 表示 unsigned
* l : 表示 long 或 long double
* ll : 表示 long long
* ul : 表示 unsigned long
* ull : 表示 unsigned long long
* f : 表示float
#### 用法
```cpp=
1l //型態為long
1.0l //型態為long double
1u //型態為unsigned int
1.0f //型態為float
1.0 //依編譯器不同,可能為float或double
//然而大部分都是double
```
#### 其他類似的用法
* 十六進位要加前導0x
```cpp=
0xA1 //等於161
```
---
### 有關左右值
[Microsoft Docs](https://docs.microsoft.com/zh-tw/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=msvc-160)
說人話
```cpp=
int a;
4 = a; //不合法,4是右值不能放左邊
const int b;
b = 5; //不合法,const是不能改的左值(non-modifiable lvalue)
a = b; //合法
```
---
### \++的好玩之處 : a\++ 和 \++a 差別
```cpp=
int a = 4;
int b;
b = a++;
std::cout << "a = " << a << " , ";
std::cout << "b = " << b;
//結果是 a = 5 , b = 4
int c = 4;
int d;
d = ++c;
std::cout << "c = " << c << " , ";
std::cout << "d = " << d;
//結果是 c = 5 , d = 5
```
a\++會先回傳a的值,再把a + 1
\++a會先把a + 1,再回傳a的值
說人話:
a\++是先運算後再加 , \++a是先加後再運算
猜猜看:
```cpp=
int a = 10;
int b;
int c = 5;
b = ++a - c++;
std::cout << b++ + a++ + c;
```
答案是15 * 6 - 10 / 2 + 7 - 69的值喔
##### 當然 a-\- 還有 --a 是相同的概念喔
---
## 有關輸入、輸出
- 為何要用cin/cout?
```cpp=
std::cout << "因為" << "cout" << "可以這樣做" << '\n';
printf("當然printf也可以這樣做\n");
std::cout << "但我相信這樣子" << '\n' << "比";
printf("這樣子做\n直觀");
```
當然scanf和cin也是相同的概念
- 有人說scanf/printf的速度比較快?
一般情況下不否認,但那是因為cin/cout有比較多的功能
那把那些功能關掉呢?
[C++的輸出入cin/cout和scanf/printf誰比較快?](https://chino.taipei/note-2016-0311C-%E7%9A%84%E8%BC%B8%E5%87%BA%E5%85%A5cin-cout%E5%92%8Cscanf-printf%E8%AA%B0%E6%AF%94%E8%BC%83%E5%BF%AB%EF%BC%9F/)
### 為什麼要用endl?
這要提到緩衝區的觀念
從上面的實驗也可以知道緩衝區也拖慢了速度
那為什麼要有緩衝區,或著說,甚麼是緩衝區?
### 緩衝區(buffer)
緩衝區大小:看各電腦系統
Windows是32768個字元
超過時就會直接輸入
在讀取輸入的時候分為三種
1. 字緩衝
2. 行緩衝
3. 全緩衝
---
#### 字緩衝
字緩衝以空格' '為分界,當遇到空格時會將前面的東西寫入程式,再把空格清除。
常用的cin >> , printf都是這樣
---
#### 行緩衝
行緩衝以行'\n'為分界,當用戶按下enter的時候才會把前面的東西寫入程式。
在 C++ 中可以用 getline() 來達到這件事
```cpp=
#include<iostream>
#include<string>
int main(){
std::string a;
getline(std::cin,a);
//這意思是把cin中讀取到的東西寫入a那裏
std::cout << a; //a 可以連空格也一起讀取
}
```
---
#### 全緩衝
全緩衝直到buffer滿了之後才會寫入,或是使用特殊的函式強制寫入緩衝區的內容
用法:我不知道
---
#### 所以為什麼要有緩衝區?
因為將讀取到的東西寫入很花時間,
所以比起一個字一個字的寫入,還不如一次寫入多個資料效率較高
---
#### 那有沒有不緩衝的
有,像是cerr就是因為必須要盡快輸出錯誤訊息所以沒有緩衝區
也可以使用cin.get()
```cpp=
include<iostream>
int main(){
char a = char(std::cin.get())
//因為cin.get()回傳的是ASCII碼,要把它換回字元
std::cout << a;
}
```
---
#### 邪教---不用變數的輸入
```cpp=
#include<iostream>
int main(){
std::cout << char(std::cin.get());
//只能讀一個字元
return 0;
}
```
---
#### 強制清空buffer
可以使用 std::flush 或 std::fflush(stdout)
```cpp=
std::cout << std::flush;
std::cout << std::fflush(stdout);
//這兩行是相同的意思
```
---
#### 所以什麼是endl
```cpp=
std::cout << endl;
std::cout << '\n' << std::flush;
std::cout << '\n' << std::fflush(stdout);
//沒錯這三行是一樣的
```
---
#### 所以這到底什麼時候會用到?
當有人嘗試要用std::fstream的時候。
std::ofstream中寫到的東西是全緩衝,直到程式結束後才會輸入。
聽不懂嗎 ? 聽不懂沒關係我們**不會**教(絕對不會在正課教)。
有興趣的我們放連結在下面:
[Microsoft Doc](https://docs.microsoft.com/zh-tw/cpp/standard-library/fstream?view=msvc-160)
[W3School C++ Files](https://www.w3schools.com/cpp/cpp_files.asp)
---
#### buffer overflow
自己查不想教
還有這東西現在基本上都有應對方式
###### 或是問問網管小組的,他們都超電(小聲
---