20220319 字元&字串
盧冠綸 @ Sprout 2022
字元
什麼是字元?
一種資料型態,寫做 char。
例如:
數字:'0'、'1'、'2'、'3'...
字母:'a'、'B'、'c'、'D'...
簡單符號:','、'.'、'@'、'!'、';'...
其他:'\n'、'\t'、'\''、'\\'...
(複習:跳脫字元)
字元
字元的宣告與賦值:
char a;
a = 'x';
char b = 'A';
字元的內容,要用' '括起來。
字元
來猜猜這支程式的輸出?
#include <iostream>
int main(){
char a = 'A';
std::cout << a << std::endl;
}
A
字元
來猜猜這支程式的輸出?
#include <iostream>
int main(){
char a = 'A';
std::cout << 'a' << std::endl;
}
a
ASCII Code
來猜猜這支程式的輸出?
#include <iostream>
int main(){
char a = 65;
std::cout << a << std::endl;
}
A
蛤?
ASCII Code
其實字元同時就是整數。
每個字元都可以用整數來寫。
#include <iostream>
int main(){
if ('A' == 65){
std::cout << "\'A\' == 65" << std::endl;
}else{
std::cout << "\'A\' != 65" << std::endl;
}
}
'A' == 65
ASCII Code
ASCII Code
既然字元是整數...
那當然也可以用來做運算!
#include <iostream>
int main(){
if ('a' == 'b' - 1){
std::cout << "\'a\' == \'b\' - 1" << std::endl;
}
if ('1' == '0' + 1){
std::cout << "\'1\' == \'0\' + 1" << std::endl;
}
}
'a' == 'b' - 1
'1' == '0' + 1
ASCII Code
注意:'0' != 0
'1' != 1 ......
不要混淆了!!
事實上,0其實是'\0'。
字串
什麼是字串?
就是字元陣列!!
上半堂教過的:
char s[7] = {'s', 'p', 'r', 'o', 'u', 't'};
或者是:
char s[7] = "sprout";
字串是用雙引號包起來
字串
char s[7] = {'s', 'p', 'r', 'o', 'u', 't'};
注意:字串只有宣告的同時可以直接賦值。
char s[7] = "sprout";
宣告完後不能再用 = 來修改內容。
Q:如果宣告完後想再修改怎麼辦?
A:一個字元一個字元來改 (用迴圈!)。
或者...用strcpy(等等會講)
字串
char s[7] = {'s', 'p', 'r', 'o', 'u', 't'};
char s[7] = "sprout";
答:為了在最後面放 '\0'(即整數的0)。
'\0' 代表的是字串的結束。
問:為何陣列大小要開7,而不是6?:
字串
小複習:上半堂的內容。
字串的輸出
'\0' 很重要!!
#include <iostream>
int main(){
char s[7] = {'s', 'p', 'r', 'o', 'u', 't', '\0'};
std::cout << s << std::endl;
}
sprout
在 cout 字串的時候,程式會一直印,
直到遇到 '\0' 才停止。
字串的輸出
小測試:這個程式會輸出什麼?
#include <iostream>
int main(){
char s[7] = {'s', 'p', 'r', '\0', 'u', 't', '\0'};
std::cout << s << std::endl;
}
spr
字串的輸出
再一個小測試:這個程式會輸出什麼?
#include <iostream>
int main(){
char s[6] = {'s', 'p', 'r', 'o', 'u', 't'};
std::cout << s << std::endl;
}
答案是:我也不知道。每台電腦不一樣。
所以,字串結尾請一定要記得放 '\0',
以免意想不到的錯誤。
字串的輸入
字串的輸入是以 ' ' 或 '\t' 或 '\n' 為分界。
#include <iostream>
int main(){
char s[20];
std::cin >> s;
std::cout << s << std::endl;
}
Hello World
以上圖為例。如果輸入是
那輸出就是
Hello
字串的輸入
小補充:如果我就是想輸入內含 ' ' 的字串...
#include <iostream>
int main(){
char s[20];
std::cin.getline(s, 20);
std::cout << s << std::endl;
}
Hello World
以上圖為例。如果輸入是
那輸出就是
Hello World
小練習
小提示:
'a' 的 ASCII Code 是 97。
'b' 的 ASCII Code 是 98。
......
'z' 的 ASCII Code 是 122。
小提示:我要怎麼知道字串有多長?
答:看到 '\0' 就表示字串結束了。
小練習
#include <iostream>
int main(){
// 宣告字串
// 輸入字串
// for (int i=0 ; 字串還沒結束 ; i++){
// 調整字串的第 i 個字母
// }
// std::cout << 字串 << std::endl;
}
可參考的思路:
小練習
#include <iostream>
int main(){
char s[505];
std::cin >> s;
for (int i=0 ; s[i] != '\0' ; i++){
if ((s[i] >= 'a') && (s[i] <= 'w')){
s[i] = s[i] + 3;
}else{
s[i] = s[i] + 3 - 26;
}
}
std::cout << s << std::endl;
}
參考解答:
(不要直接複製貼上欸 我們都看得到!!)
strlen(s)
#include <cstring>
Q:我要怎麼算字串 s 的長度?
方法二:
用 strlen(s)。
方法一:
還記得剛剛的凱薩密碼嗎?我們剛剛怎麼做的?
-> 用迴圈一個一個找,直到找到 '\0' 為止。
兩個方法是一樣的~
strlen(s)
#include <cstring>
strlen(s):回傳字串長度。
#include <iostream>
#include <cstring>
int main(){
char s[20] = "Sprout";
std::cout << strlen(s) << std::endl;
}
6
strlen(s)
#include <cstring>
strlen(s):回傳字串長度。
#include <iostream>
#include <cstring>
int main(){
char s[20] = "Sprout 2022";
std::cout << strlen(s) << std::endl;
}
11
strlen(s)
#include <cstring>
下面這個程式有什麼缺點?
char s[20000];
std::cin >> s;
for (int i=0 ; i<strlen(s) ; i++){
std::cout << s[i] << std::endl;
}
strlen() 會被重複執行好幾次,每次都會重複用迴圈找 '\0',浪費時間。
strlen(s)
#include <cstring>
如何改進剛剛的程式的缺點?
char s[20000];
std::cin >> s;
int len = strlen(s);
for (int i=0 ; i<len ; i++){
std::cout << s[i] << std::endl;
}
把 strlen() 拿到迴圈外面就好。
strcmp(a, b)
#include <cstring>
Q:我想比較兩個字串一不一樣,可是結果怪怪的...
#include <iostream>
// THIS CODE IS WRONG !!
int main(){
char a[20], b[20];
std::cin >> a >> b;
if (a == b){
std::cout << "a == b" << std::endl;
}
}
A:不要用 ==、>、< 等來比較字串。
用 strcmp()。
strcmp(a, b)
#include <cstring>
strcmp(a, b):比較 a 和 b 這兩個字串。
0:表示 a 和 b 內容一模一樣。
>0:表示 a 的字典序 ASCII 比 b 大。
<0:表示 a 的字典序 ASCII 比 b 小。
strcmp(a, b)
#include <cstring>
#include <iostream>
#include <cstring>
int main(){
char a[20] = "abcde";
char b[20] = "bcdef";
char B[20] = "bcdef";
std::cout << strcmp(a,b) << std::endl;
std::cout << strcmp(b,B) << std::endl;
}
-1
0
strcpy(dest, src)
#include <cstring>
Q:下面這個程式無法編譯...
陣列好像不能用 b = a 之類的方式賦值...
#include <iostream>
// THIS CODE IS WRONG !!
int main(){
char a[20] = "Sprout";
char b[20] = a; // error
}
A:用 strcpy()。
strcpy(dest, src)
#include <cstring>
#include <cstring>
strcpy(dest, src):
把src的內容複製給 dest。
strcpy(dest, src)
#include <cstring>
#include <cstring>
#include <iostream>
#include <cstring>
int main(){
char a[20] = "Sprout ", b[20] = "2022";
std::cout << "a is " << a << std::endl;
strcpy(a, b);
std::cout << "a is " << a << std::endl;
}
a is Sprout
a is 2022
strcat(dest, src)
#include <cstring>
Q:下面這個程式無法編譯...
我希望 c 是 "yo! battle",但陣列不能直接加法...
#include <iostream>
// THIS CODE IS WRONG !!
int main(){
char a[20] = "yo! ";
char b[20] = "battle";
char c[20] = a + b; // error
}
A:用 strcat()。
strcat(dest, src)
#include <cstring>
strcat(dest, src):
把src的內容接在 dest 的後面。
strcat(dest, src)
#include <cstring>
#include <iostream>
#include <cstring>
int main(){
char a[20] = "yo! ", b[20] = "battle";
std::cout << "a is " << a << std::endl;
strcat(a, b);
std::cout << "a is " << a << std::endl;
}
a is yo!
a is yo! battle
其他字串相關函式
#include <cstring>
Q:strcmp會比較整個字串,
strcpy 會複製整個字串,
strcat 會銜接整個字串,
那如果,我不想 比較/複製/銜接 整個字串,
我只想 比較/複製/銜接 一部份字串,怎麼辦?
A:用 strncmp、strncpy、strncat。
strncmp(a, b, count)
#include <cstring>
strncmp(a, b, count):
比較 a 和 b 這兩個字串的前 count 個字元。
0:表示兩者前 count 個字元內容一模一樣。
>0:表示 a 的前 count 個字元的字典序比較大。
<0:表示 a 的前 count 個字元的字典序比較小。
strncmp(a, b, count)
#include <cstring>
#include <iostream>
int main(){
char a[20] = "Sprout 2021";
char b[20] = "Sprout 2022";
std::cout << strcmp(a, b) << std::endl;
std::cout << strncmp(a, b, 6) << std::endl;
}
-1
0
在這裡,strncmp() 比的是 a 和 b 的前 6 個字元,
分別是 "Sprout" 和 "Sprout" ,兩者一樣。
strncpy(dest, src, count)
#include <cstring>
#include <cstring>
strncpy(dest, src, count):
把src的前 count 個字元複製給 dest。
strncpy(dest, src, count)
#include <cstring>
#include <cstring>
#include <iostream>
int main(){
char a[20] = "Sprout ", b[20] = "2022";
std::cout << "a is " << a << std::endl;
strncpy(a, b, 2);
std::cout << "a is " << a << std::endl;
}
a is Sprout
a is 20rout
好像怪怪的?
strncpy(dest, src, count)
#include <cstring>
#include <cstring>
注意:
strncpy 不會幫你把 '\0' 也複製過去,
使用 strncpy 後要記得自己補上 '\0'。
(不補的話可能會出錯)
strncpy(dest, src, count)
#include <cstring>
#include <cstring>
#include <iostream>
int main(){
char a[20] = "Sprout ", b[20] = "2022";
std::cout << "a is " << a << std::endl;
strncpy(a, b, 2);
a[2] = '\0';
std::cout << "a is " << a << std::endl;
}
a is Sprout
a is 20
strncat(dest, src, count)
#include <cstring>
#include <cstring>
strncat(dest, src, count):
把src的前 count 個字元接在 dest 之後。
strncat(dest, src, count)
#include <cstring>
#include <cstring>
#include <iostream>
int main(){
char a[20] = "Sprout ", b[20] = "2022";
std::cout << "a is " << a << std::endl;
strncat(a, b, 2);
std::cout << "a is " << a << std::endl;
}
a is Sprout
a is Sprout 20
小練習
思路一:直接用 strncpy 和 strncat。
思路二:用迴圈,一個一個字元來處理。
以下提供兩種可行的思路:
小練習
思路一:
#include <iostream>
#include <cstring>
int main(){
char a[105], b[105], ans[205];
std::cin >> a >> b;
int m, n;
std::cin >> m >> n;
strncpy(ans, a, m);
ans[m] = '\0';
strncat(ans, b, n);
std::cout << ans << std::endl;
std::cout << ans << std::endl;
std::cout << ans << std::endl;
}
小練習
思路二:
#include <iostream>
#include <cstring>
int main(){
char a[105], b[105], ans[205];
std::cin >> a >> b;
int m, n;
std::cin >> m >> n;
for (int i=0 ; i<m ; i++){
ans[i] = a[i];
}
for (int i=0 ; i<n ; i++){
ans[m+i] = b[i];
}
ans[m+n] = '\0';
std::cout << ans << std::endl;
std::cout << ans << std::endl;
std::cout << ans << std::endl;
}
謝謝大家
20220319 字元&字串
By allen522019
20220319 字元&字串
- 735