# 一維陣列、字串與字元
## 一維陣列
### 宣告一維陣列
我們都學過`int`, `string`, `long long`...等,資料儲存類型,這些的特點都是**一個變數只能存一筆資料**。但如果今天有很多筆資料,像是有40筆資料,總不可能宣告40個變數來儲存,<span style="color:red; font-weight:bold">超級麻煩</span>。
所以有一個資料結構是**陣列(array)**,宣告一個以**索引(index)作為識別**,宣告方式:
```
資料型別 陣列名稱[n] = {預設值};
```
他會開好一個可以**存n筆資料的陣列**,固定大小為n**不可修改**,裡面存的資料型別都要跟宣告的型別**一樣**。
可以修改大小的是vector (動態陣列)。
-------
像這樣宣告大小同為10,但型別不同的陣列:
```cpp=
int number[10]; // 宣告 10 個元素的整數陣列
double score[10]; // 宣告 10 個元素的浮點數陣列
char ascii[10]; // 宣告 10 個元素的字元陣列
```
也可以後面接大括號直接**預設初始值**,後面接的資料比數不可以超過宣告的大小:
```cpp=
int number[5] = {0, 1, 2, 3, 4};
double score[5] = {87.0, 78.0, 99.5, 69.5, 82.5};
char ascii[5] = {'A', 'B', 'C', 'D', 'E'};
```
-------
如果宣告大小為5的陣列,只預設前兩項值,則後面空房間都會預設為**0**或**空字串**、**空字元**:
```cpp=
int number[5] = {0, 1}; // 實際長這樣 {0, 1, 0, 0, 0};
double score[5] = {87.0, 78.0, 99.5}; // {87.0, 78.0, 99.5, 0.0, 0.0};
char ascii[5] = {'A', 'B', 'C', 'D'}; // {'A', 'B', 'C', 'D', '\0'};
```
或是今天想要預設每一格值都是一樣的值,大括號包**一筆資料**:
```cpp=
int number[10] = {0}; // 十個位置都是0
double score[10] = {0.0};
char ascii[10] = {'\0'}; // '\0' 空字元
```
但如果今天:
```cpp=
int number[10] = {1}; // 他會變成 {1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
```
-------
你今天懶得宣告大小也可以**不宣告大小**直接**設初始值**,編譯器會自己判斷大小:
```cpp=
int number[] = {0, 1, 2, 3, 4}; // 自動宣告大小為 5 的陣列
double score[] = {87.0, 78.0, 99.5, 69.5, 82.5};
char ascii[] = {'A', 'B', 'C', 'D', 'E'};
```
### 索引值
陣列的每一個房間都有**自己的編號**,第一間房間(元素)編號是0、第二間是1...依此類推,第n間房間編號是n-1。這種陣列稱為**0-based陣列(零基索引陣列)**。
當要存取陣列中的值時,可以使用 **下標(Subscript運算子)[]** 加上 **索引(Index)**,指定要存取的陣列元素,如下。

下面這個簡單的程式示範如何**使用索引存取陣列元素**:
```cpp=
#include<iostream>
using namespace std;
int main() {
int n;
cin >> n; // 有 n 筆資料
int a[n];
for (int i=0; i<n; i++) {
cin >> a[i]; // 從 0 數到 n-1 對應索引值
}
for (int i=0; i<n; i++) {
cout << a[i] << ' '; // 輸出加空格
}
cout << endl; // 換行
}
```
### 小練習
班上有40個同學,小明想要知道11號到20號的分數各是多少,以及這十位同學的平均分數,請你幫幫他吧,每個人的分數用空格分開,第二行輸出一個數字,代表十位同學的平均分數。
* 輸入為一行含有40個數字,代表班上1~40號的分數,之後是一個換行字元。
* 請輸出11號到20號的分數,每個分數空格分開,第二行輸出一個**浮點數**,代表十位同學的平均分數。
輸入:
```cpp=
95 11 38 21 67 31 14 82 12 55 22 90 32 49 70 13 12 23 25 33 88 64 14 79 24 41 34 73 99 15 38 29 47 19 10 29 69 39 53 12
```
輸出:
```cpp=
22 90 32 49 70 13 12 23 25 33
36.9
```
<details>
<summary>解答</summary>
```cpp=
#include<iostream>
using namespace std;
int main() {
int a[40], total = 0;
for (int i=0; i<40; i++) {
cin >> a[i];
}
for (int i=10; i<20; i++) {
cout << a[i] << ' ';
total += a[i];
}
cout << endl;
double ans = total / 10.0;
cout << ans << endl;
}
```
</details>
## 字串與字元
### 宣告
**字元(char)** 顧名思義,他是一個元素,只能有**一個字**,字元以**單引號**表示` ' ' `。
```cpp=
'A' 'B' '0' 'w' '\n' ...
```
而**字串(string)** 跟**陣列**很像,每個字串都是一間一間的房間組成,而每一間房間都**存著一個字元**,所以字串就是一連串的字元組合而成。字串以**雙引號**表示` " " `。
字串幾乎**沒有長度限制**,就算有幾億個字元也都可以存,所以超過`int`, `long long`範圍的數字可以用`string`存。
```cpp=
"hello world" "apple" "A" ...
```
因此字串也可以索引存取值、也是**0-based**,如下。

字元A跟字串A雖然輸出長一樣,但他們型別不同。
字串是字元陣列,而且尾端會有`\0`**(null terminator)**,所以實際上字串A有兩個字元。
```cpp=
char c = 'A';
string s = "A";
cout << c << ' ' << s;
// 輸出 A A
```
-------
字元aaa是不合法的 **(multi-character character constant)**,在 C++ 標準裡,這種寫法雖然有定義(會轉成一個整數值),但幾乎沒人用,因為不可讀又不直覺。
```cpp=
char c = 'aaa';
cout << c;
// 可能會輸出 6381921
```
### string的索引值
因為string的每個房間都是char,所以當我們索引取值的時候:
```cpp=
string s = "hello";
char c = s[0]; // 取出之值是字元
cout << c;
// 輸出 字元h
```
也可以直接修改字串:
```cpp=
string s = "Hello World";
s[0] = 'h'; // 用字元修改
s[6] = 'w';
cout << s;
// 輸出 hello world
```
### 字串長度
C++ 有提供一個函式,可以取得字串有效字元的長度,使用方法:
```cpp=
int len = 字串變數名稱.length();
```
字串尾端的` \0 `不是有效字元,所以不會計入長度。
```cpp=
string s = "apple";
cout << s.length();
// 輸出 5
```
-------
所以今天想要知道字串最後一個字元是什麼,可以:
```cpp=
string s = "world";
cout << s[s.length()-1]; // 0-based 最後一項是 字串長度-1
// 輸出 d
```
### 小練習
小美想要練習翻轉字串,輸入一個字串,把字串全部倒過來。
* 第一行輸入一個n,代表有n筆字串,接下來有n行,每行皆有一個字串,保證不包含空格。
* 輸出有n行,1~n行代表第幾筆翻轉過的字串。
> hint: 使用for迴圈從字串尾端遍歷回去。
輸入:
```cpp=
3
i
like
school
```
輸出:
```cpp=
i
ekil
loohcs
```
<details>
<summary>解答</summary>
```cpp=
#include<iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i=0; i<n; i++) {
string s;
cin >> s;
for (int j=s.length()-1; j>=0; j--) {
cout << s[j];
}
cout << endl;
}
}
```
</details>
## ASCII
### ASCII 是什麼
**ASCII(American Standard Code for Information Interchange)** 是一種**字元編碼標準**,把字元對應到數字。範圍0~127,共**128個編碼**。
- 例如:
- 'A' → 65
- 'a' → 97
- '0' → 48
- '\n' → 10 (換行)

### 取得字元ASCII值
隱式轉型:
```cpp=
char c = 'A';
int ascii = c;
cout << ascii;
// 輸出 65
```
顯式轉型:
```cpp=
#include<iostream>
using namespace std;
int main() {
cout << (int)'A';
// 輸出 65
}
```
### ASCII 的應用
1. 字母轉大寫
小寫字母-32會變成大寫(大小寫差值)。
```cpp=
char c = 'a';
char upper = c - 32; // 'A'
```
2. 字母轉小寫
反過來是+32。
```cpp=
char c = 'A';
char lower = c + 32; // 'a'
```
3. 判斷是否是數字
如果字元c的ascii介於0~9的ascii值之間,則為數字。
```cpp=
char c = '7';
if (c >= '0' && c <= '9') {
cout << "digit";
} else {
cout << "not digit";
}
// 輸出digit
```
4. 字母差值
a~c的距離為2
```cpp=
cout << ('c' - 'a');
// 輸出 2
```
5. 字元數字轉整數
數字ascii差值剛好為實際數字
```cpp=
char c = '9';
cout << c - '0';
// 輸出 9
```
### 小練習
智明想要知道一個數字所有位數的值加起來是多少,請你幫他計算。
> 這個數字會有700位數,請使用字串處理。
* 輸入僅有一個數字。
* 輸出此數字所有位數之合。
輸入:
```cpp=
8319735824609581720364957201948756109238745610928374561029384756109283745610928374561092837456109283746501928374659102837465908172364598127364598172364598172364598172364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589712364589765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321012345678901234567890123456789012345678901234567890123456789012345678901789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
```
輸出:
```cpp=
3249
```
<details>
<summary>解答</summary>
```cpp=
#include<iostream>
using namespace std;
int main() {
string s;
cin >> s;
int total = 0;
for (int i=0; i<s.length(); i++) {
total += s[i] - '0';
}
cout << total << endl;
}
```
</details>
## Zerojudge
[c290. APCS 2017-0304-1秘密差](https://zerojudge.tw/ShowProblem?problemid=c290)
[g595. 1. 修補圍籬](https://zerojudge.tw/ShowProblem?problemid=g595)