# Ch08 字元字串處理
> 上一章: [Ch07 陣列]( https://hackmd.io/@sunfrancis12/BJ__b0sz6)
> 下一章: [Ch09 函式與遞迴]( https://hackmd.io/@sunfrancis12/BykpM0iza)
> 回目錄: [NTCU程式戰鬥營C講義](https://hackmd.io/@sunfrancis12/ByfdXdjG6)
## 字元 Char
字元`Char` 是一種變數型態,專門儲存個各種字(`*`,`%`,`a`,`?`)
在程式的世界裡面又把上述的那些字稱作**字元**
char變數只能儲存一個字元:
```c=
char c = 'a'; //創建一個名稱為c的char,並初始化値'a'
char s = '&'; //創建一個名稱為c的char,並初始化値'&'
char abc = ':'; //創建一個名稱為abc的char,並初始化値':'
```
**Char的資料型態**
| 資料型態 | 格式化字串 | 變數範圍 |
| -------- | ---------- | --------------------- |
| char | %c | -128至127 (ASCII編碼) |
輸出三個字元:
```c=
#include<stdio.h>
int main(){
char c = 'a'; //創建一個名稱為c的char,並初始化値'a'
char s = '&'; //創建一個名稱為c的char,並初始化値'&'
char abc = ':'; //創建一個名稱為abc的char,並初始化値':'
printf("char c: %c\n",c);
printf("char s: %c\n",s);
printf("char abc: %c",abc);
}
```
輸出結果:
```c=
char c: a
char s: &
char abc: :
```
使用`scanf()`輸入字元並輸出:
```c=
#include<stdio.h>
int main(){
char a;
printf("input char a: ");
scanf("%c",&a);
printf("char a: %c\n",a);
}
```
輸入內容:
```c=
g
```
輸出內容:
```c=
input char a: g
char a: g
```
除了scanf()以外,我們也可以使用其他的函式來完成字元的輸入輸出
* `getchar()` 輸入一個字元
* `putchar()` 輸出一個字元
```c=
#include<stdio.h>
int main(){
char a;
printf("input a: ");
a = getchar(); //義同於scanf("%c",&a);
printf("a value: ");
putchar(a); //義同於prinf("%c",a);
}
```
輸入內容:
```c=
c
```
輸出結果:
```c=
input a: c
a value: c
```
### 特殊字元
特殊字元跟我們常見的字母、數字和符號等字元不太一樣
他們會用於一些特殊的情況,比如換行`\n`、空字元`\0`
他們的格式都是以`\`作為開頭
常見的特殊字元:
* 換行: `\n`
* 空字串: `\0`
* tab: `\t`
* 字元`"`: `\"`
* 字元`\`: `\\`
<a style="color:orange">【例題】</a>
> 請寫一個程式,計算在輸入換行("\n")前總共輸入了多少字元,並將結果輸出
>
> *註: 換行就是指當鍵盤按下Enter*
範例輸入:
```c=
apple
```
範例輸出:
```c=
總共輸入了5個字元
```
範例程式:
```c=
#include<stdio.h>
int main(){
char input;
int sum=0;
while(input = getchar()){
if(input == '\n') break;
sum++;
}
printf("總共輸入了%d個字元",sum);
}
```
## Char的本質 ASCII
在電腦(計算機)的世界裡是沒有**字元**這個概念的,如果想要讓電腦紀錄字元的話,我們需要把字元表示成一個整數
為此我們有了ASCII TABLE,這個圖表上的每個字元都有相對應的一個整數

輸出字元的ASCII値:
```c=
#include<stdio.h>
int main(){
char ascii='a';
printf("ascii value: %d\n",ascii);
printf("ascii value 97: %c",97);
}
```
輸出結果:
```c=
ascii value: 97
ascii value 97: a
```
## String 字串
上面介紹了字元,一次可以記錄一個字
如果我們今天要記錄一個句子的話,那我們就必須記錄許多個字元
因此我們需要建立一個**字元的陣列**,也就是**字串**
```c=
char c ='A'; //建立一個字元c
char s[20] = "Apple" //建立一個長度為20的字串s
```
:::info
字元的初始化要使用單引號`'`,而字串的話則是雙引號`"`
:::
要輸入一個字串的話,我們可以使用格式化字串`%s`
```c=
#include<stdio.h>
int main(){
char str[20];
scanf("%s",str);
printf("你輸入的字串為: %s",str);
}
```
輸入內容:
```c=
banana
hello how are you
```
輸出結果:
```c=
你輸入的字串為: banana
你輸入的字串為: hello
```
:::info
scanf("%s")的話遇到空格就會輸入完成,空格後面的字元不會被輸入
:::
如果希望遇到空格還可以繼續輸入的話可以使用`gets()`,他會持續輸入直到遇到換行`\n`為止
* `gets()`: 輸入一個字串,且遇到`\n`才會停止輸入
* `puts()`: 輸出一個字串
```c=
#include<stdio.h>
int main(){
char str[30];
gets(str);
printf("你輸入的字串為: ");
puts(str);
}
```
輸入內容:
```c=
i love you
```
輸出結果:
```c=
你輸入的字串為: i love you
```
## 字串處理
在C語言裡有`string.h`的函式庫,裡面有許多常用於字串處理的工具
### `String.h`
`string.h`是C標準庫的標頭檔,其中包含了宏(巨集)定義、常數以及函數和類型的聲明,涉及的內容除了字串處理之外,還包括大量的記憶體處理常式
> [維基百科 -String.h](https://zh.wikipedia.org/zh-tw/String.h)
**<string.h>的實用函數:**
* `size_t strlen(const char *)`: 返回一個字串的長度
- strlen("15ff") => 4
* `char *strcpy(char* str1, const char* str2)`: 將str2拷貝給str1
- strcpy(a,b) => 等同於a = b的值
* `char *strcat(char *dest, const char *src)`: 在字串dest之後連接上src
- strcat(a,b) => 等同於 a = a + b
* `int strcmp(const char *, const char *)`: 基於字典順序比較兩個字串
- 如果返回值<0,則表明str1小於str2
- 如果返回值,如果> 0,則表明str2 小於 str1
- **如果返回值= 0,則表明str1 等於str2**
> [取自 strcmp() -GITBOOK.NET](https://tw.gitbook.net/c_standard_library/c_function_strcmp.html)
上述`string.h`函式的範例程式:
```c=
#include<stdio.h>
#include<string.h>
int main(){
char str1[20]="hi",str2[20]="hello";
printf("str2的字串長度為: %d\n",strlen(str2));
printf("str1: %s,str2: %s\n",str1,str2);
strcat(str1,str2);
printf("\n執行strcat(str1,str2)...\n");
printf("str1: %s,str2: %s\n",str1,str2);
strcpy(str1,str2);
printf("\n執行strcpy(str1,str2)...\n");
printf("str1: %s,str2: %s\n",str1,str2);
printf("\n比較str1,str2是否相同...\n");
printf("strcmp(str1,str2): %d\n",strcmp(str1,str2));
if(strcmp(str1,str2)==0) printf("str1和str2相同");
else printf("str1和str2不相同");
}
```
輸出結果:
```c=
str2的字串長度為: 5
str1: hi,str2: hello
執行strcat(str1,str2)...
str1: hihello,str2: hello
執行strcpy(str1,str2)...
str1: hello,str2: hello
比較str1,str2是否相同...
strcmp(str1,str2): 0
str1和str2相同
```
<a style="color:orange">【例題】</a>
> 輸入一個字串,並將其翻轉後的結果輸出
範例輸入:
```c=
nice day how are you?
```
範例輸出:
```c=
原始字串: nice day how are you?
翻轉後的字串: ?uoy era woh yad ecin
```
範例解答:
```c=
#include<stdio.h>
#include<string.h>
int main(){
char str[30];
gets(str);
printf("原始字串: %s\n",str);
printf("翻轉後的字串: ");
for(int i=strlen(str)-1;i>=0;i--){
printf("%c",str[i]);
}
}
```
<a style="color:orange">【例題】</a>
> 程上題,只有單字的位置翻轉,文字順序並未改變
範例輸入:
```c=
nice day how are you
```
範例輸出:
```c=
原始字串: nice day how are you
翻轉後的字串: you are how day nice
```
範例程式:
```c=
#include<stdio.h>
#include<string.h>
int main(){
char str[100];
gets(str);
printf("原始字串: %s\n",str);
printf("翻轉後的字串: ");
for(int i=strlen(str)-1;i>=-1;i--){
if(str[i]==' ' || i==-1){
for(int j=i+1;str[j]!=' '&& j<strlen(str);j++) putchar(str[j]);
putchar(' ');
}
}
}
```
<a style="color:orange">【例題】</a>
> 請判斷輸入的文字是否為"迴文"(字串的每個字元都前後對稱)
範例輸入:
```c=
chjgffgjhc
asdfghjkllkjhgfdsa
appleapple
```
範例輸出:
```c=
輸入的字串: chjgffgjhc
字串: chjgffgjhc是迴文
輸入的字串: asdfghjkllkjhgfdsa
字串: asdfghjkllkjhgfdsa是迴文
輸入的字串: appleapple
字串: appleapple不是迴文
```
範例程式:
```c=
int main(){
char str[100];
gets(str);
printf("輸入的字串: %s\n",str);
printf("字串: %s");
int sum=0;
for(int i=0;i<=(strlen(str)-1)/2;i++){
if(str[i] != str[strlen(str)-1-i]) sum++;
}
if(sum>0) printf("不是迴文");
else printf("是迴文");
}
```
<a style="color:orange">【例題】</a>
> 請將輸入的字串的小寫字母轉成大寫字母,並輸出
範例輸入:
```c=
Apple
BAnasdin sidFFjnSJ ASD
MAmaLiLijJDUfSAFudDG^(*&@#@HGR*9 3hd7g328)
```
範例輸出:
```c=
輸入的字串: Apple
轉換後的字串: APPLE
輸入的字串: BAnasdin sidFFjnSJ ASD
轉換後的字串: BANASDIN SIDFFJNSJ ASD
輸入的字串: MAmaLiLijJDUfSAFudDG^(*&@#@HGR*9 3hd7g328)
轉換後的字串: MAMALILIJJDUFSAFUDDG^(*&@#@HGR*9 3HD7G328)
```
範例程式:
```c=
#include<stdio.h>
#include<string.h>
int main(){
char str[100];
gets(str);
printf("輸入的字串: %s\n",str);
for(int i=0;i<strlen(str);i++){
if('a'<=str[i] && str[i]<='z') str[i] -= 32;
}
printf("轉換後的字串: %s");
}
```
---
> 上一章: [Ch07 陣列]( https://hackmd.io/@sunfrancis12/BJ__b0sz6)
> 下一章: [Ch09 函式與遞迴]( https://hackmd.io/@sunfrancis12/BykpM0iza)
> 回目錄: [NTCU程式戰鬥營C講義](https://hackmd.io/@sunfrancis12/ByfdXdjG6)