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