---
# System prepended metadata

title: 一維陣列、字串與字元

---

# 一維陣列、字串與字元

## 一維陣列
### 宣告一維陣列
我們都學過`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）**，指定要存取的陣列元素，如下。
![image](https://hackmd.io/_uploads/Byla4akf-g.png)

下面這個簡單的程式示範如何**使用索引存取陣列元素**：
```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**，如下。
![image](https://hackmd.io/_uploads/SJd8i7SMWx.png)
    
字元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 (換行)

![IMG_1851](https://hackmd.io/_uploads/Hkx55NBzbe.png)

### 取得字元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)
