# 函數呼叫&字串函數
2020 Clang, 0w1
---
### 函數?

----
> 從輸入值集合 X 到可能的輸出值集合 Y 的函數 f 記作 f : X → Y 是 X 與 Y 的關係,滿足如下條件:
> 1. f 是完全的
> 2. f 是多對一的
----
f 是完全的
->
對輸入值集合 X 裡的任何元素 x
輸出值集合 Y 裡存在 f(x)
----
f 是多對一的
->
允許 f(x) = f(y), x $\neq$ y
不允許 f(x) = a, f(x) = b, a $\neq$ b
----

----
想成他是一個黑盒子就好,東西進去,東西出來。

----
國中數學課本裡的例子:
函數:販賣機
輸入:錢 + 想買的飲料的編號
輸出:飲料 + 找零 or 找零(錢不夠)
---
### Your first function
```c++
int main() {
return 0;
}
```
---
### 函數的長相
一般的函數大概會長這樣:
```c++
回傳的型態 函數名稱(參數 1, 參數 2, ...) {
各種處理
return 回傳值;
}
```
----
### 函數宣告/呼叫
要使用定義好的函數,我們只要看清楚函數宣告的第一行:
```c++
int add(int a, int b) ...
```
```c++
int x = add(3, 4); // x = 7
int y = add(3, add(4, 5)); // y = 12
```
---
### C++ Library
* 裡面有很多常用函數
* 需要你明確引入(include) 才可以使用
* 參閱 https://zh.cppreference.com
----
### 高中生熟悉的函數們
請 include cmath
```cpp
std::log10(100); // 2
std::abs(-3); // 3
std::exp2(10); // 1024
std::pow(3, 2); // 9
std::sqrt(9); // 3
std::sin(0); // 0
std::acos(-1); // 3.14159
```
----
### 好用的函數們
請 include algorithm
```cpp
std::min(2, 3); // 2
std::max(2, 3); // 3
std::swap(x, y);
```
---
### 函數回傳值
----
* 有些函數沒有回傳值
```cpp
int x = 3, y = 5;
std::swap(x, y); // x = 5, y = 3
```
----
* 有些函數有回傳值
* 語法上可以直接當他是個值
```cpp
std::min(3, std::max(1, 2));
// == std::min(3, 2)
// == 2
```
----
* 函數呼叫時參數的處理順序沒有規範
* 避免會相互影響的東西出現在參數欄位
* 否則結果為何端看你的編譯器
```cpp
int x = 3, y = 5;
std::min(y = x, x = y); // what happens?
```
---
### 字串常用函數
這節介紹一些實用的字串相關函數 :P
---
### 字串複習
----
```cpp
char a;
```
a 是字元,亦是一個 0~255 的整數
----
```cpp
char a[] = "...";
```
a 是字串 (C-style),亦是字元的陣列
----
* C-style 字串結尾是 0
```c++
char a[] = "ABC";
int x = a[3];
std::cout << x; // 0
```
----
### 輸入
```cpp
char a[10];
std::cin >> a; // 讀到空白字元(會捨棄空白字元)
std::cin.getline(a, 10); // 讀到換行字元(會捨棄換行字元)
std::cin.getline(a, 10, 'x'); // 讀到x(會捨棄 x)
```
----
### 輸出
* 會依序輸出 a 的字元,直到 0
```cpp
char a[] = "ABCD";
std::cout << a; // ABCD
a[2] = 0;
std::cout << a; // AB
```
----
* 這裡介紹 C-style 字串的函數
* 可以在 cstring 裡找到
* 勿與 C++ 字串 string 搞混
----
* C-style string to C++style string
```cpp
char a[] = "ABC";
std::string b = string(a);
```
----
* C++style string to C-style string
```cpp
std::string a = "ABC";
std::strlen(a.c_str()); // 3
```
---
### 字符分類
* int isXXX(char)
* true -> 非零值
----
```cpp
isalnum() // is alphabet or number
islower() // is lowercase
isdigit() // is digit
isblank() // \n, \t, \0, etc.
```
---
### 字符操作
* int tolower(int)
* int toupper(int)
----
```cpp
char a = std::tolower('A'); // 'a'
char b = std::tolower('b'); // 'b'
```
---
### 數值轉換
* int atoi(char [])
* long long atoll(char [])
----
```cpp
int a = std::atoi("34"); // a = 34
int b = std::atoi("3.4b"); // b = 3
int c = std::atoi("abc3"); // c = 0
```
---
### 字串操作
* strcpy(dest, src)
* strncpy(dest, src, count)
* strcat(dest, src)
* strncat(dest, src, count)
----
```cpp
char a[5] = "AB";
std::strcpy(a, "CD"); // a = "CD"
char b[5] = "AB";
std::strncpy(b, "EFG", 1); // b = "EB"
char c[5] = "AB";
std::strcat(c, "CD"); // c = "ABCD"
char d[5] = "AB";
std::strncat(d, "EFG", 1); // d = "ABE"
```
----
* 當 dest 不夠大,行為未定義
---
### 字串檢測
* int strlen(char a[])
* int strcmp(char l[], char r[])
* int strncmp(char l[], char r[], count)
----
```cpp
std::strlen("ABC"); // 3
std::strcmp("ABC", "AB"); // 1, note that it's > 0
std::strncmp("ABC", "AB", 2); // 0
```
----
strlen:
* 若 a 所指向的字元數組中無空字元,則行為未定義。
----
strcmp:
* 若 l 或 r 不是指向空終止位元組字元串的指針,則行為未定義。
----
strncmp:
* 若出現越過 l 或 r 結尾的訪問,則行為未定義。
* 若 l 或 r 為空指針,則行為未定義。
---
### 數組操作
* memset(dest, ch, count)
----
```cpp
int a[5]; // sizeof(a) = 5 * 4 = 20
std::memset(a, 1, sizeof(a)); // a[0..4] = 1465341783
std::memset(a, 256, sizeof(a)); // a[0..4] = 0
std::memset(a, 255, sizeof(a)); // a[0..4] = -1
```
---
### 常見不良習慣
```cpp
char s[] = "ABCD...";
for (int i = 0; i < std::strlen(s); ++i) {
// ...
}
```
---
### 練習 - NEOJ 894

{"metaMigratedAt":"2023-06-15T05:39:33.558Z","metaMigratedFrom":"Content","title":"函數呼叫&字串函數","breaks":true,"contributors":"[{\"id\":\"dec33987-0cd9-4214-9d3e-825262921019\",\"add\":8785,\"del\":4579}]"}