?????? ????????????????Hi~!這里是奮斗的小羊,很榮幸各位能閱讀我的文章,誠請評論指點,關注+收藏,歡迎歡迎~~? ? ?
????????????????????????💥個人主頁:小羊在奮斗
????????????????????????💥所屬專欄:C語言? ?
????????本系列文章為個人學習筆記,在這里撰寫成文一為鞏固知識,二為同樣是初學者的學友展示一些我的學習過程及心得。文筆、排版拙劣,望見諒。?
????????????????????????????????1、字符分類函數
????????????????????????????????2、字符轉換函數
????????????????????????????????3、strlen 的使用和模擬實現
????????????????????????????????4、strcpy?的使用和模擬實現
????????????????????????????????5、strcat?的使用和模擬實現
1、字符分類函數
? ? ? ? C語言中有一些專門作字符分類的函數,使用這些函數需要包含頭文件 ctype.h 。
isalnum | 檢查一個字符是否是字母或數字 (函數) |
isalpha | 檢查一個字符是否是字母 (函數) |
islower | 檢查一個字符是否是小寫字母 (函數) |
isupper | 檢查一個字符是否是大寫字母 (函數) |
isdigit | 檢查字符是否為數字 (函數) |
isxdigit | 檢查一個字符是否是十六進制的字符 (函數) |
iscntrl | 檢查一個字符是否是控制字符 (函數) |
isgraph | 檢查一個字符是否是圖形字符 (函數) |
isspace | 檢查一個字符是否是空白字符 (函數) |
isblank (C99) | 檢查一個字符是否是空格字符 (函數) |
isprint | 檢查一個字符是否是可打印字符 (函數) |
ispunct | 檢查一個字符是否是標點字符 |
? ? ? ? 更多詳細內容請點擊跳轉閱讀 —>?C 標準庫頭文件 - cppreference.com?
? ? ? ? 這些函數的使用方法、返回值等基本是一致的,這里就以 islower 函數為例,寫一個將字符串中非大寫的字母轉化為大寫字母的示例。
?
?2、字符轉換函數
? ? ? ? C語言中有兩個實現大小寫轉換的函數,tolower(將大寫字母轉小寫)?和 toupper(將小寫字母轉大寫)。
????????那既然有了這兩個函數,上面將字符串中的小寫字母轉換為大寫字母的代碼就可以簡化一下了。
?
3、strlen 的使用和模擬實現
? ? ? ? 3.1 strlen 的返回值
? ? ? ? strlen 函數我們已經非常的熟悉,之前也介紹了兩種模擬 strlen 函數的方法,這里再關于strlen 的使用做一些補充,同時再介紹另一種 strlen 的模擬實現方法。
????????
? ? ? ? 以前我們在使用 strlen 函數的時候,可能沒有細心地關注過 strlen 的返回值類型,有時候我們使用 int 類型來接收它的返回值好像也沒出現什么問題,但其實這是一個很值得我們去注意的一個問題。來看下面的示例:
? ? ? ? 按道理來說-3小于0應該打印的是“<=”,但結果卻并不是。其中的原因就在于 strlen 的返回值類型是 size_t 類型,兩個 size_t 類型的值相減還是 size_t 類型,而我們知道整型是以補碼的形式存儲的,所以 size_t 類型會把-3的補碼當做一個很大的正整數,這個數當然是大于0的,所以結果是打印出了 “>”。而如果我們想讓它輸出我們想要的結果,只需要強制類型轉換就行。
? ? ? ? 3.2 strlen 的模擬實現?
?????????之前的文章中我們用了指針遍歷數組和指針-指針兩種方法來模擬 strlen 函數,這里我們再使用另一種方法來模擬實現——遞歸。
#include <stdio.h>
#include <assert.h>size_t my_strlen(char* str)
{assert(str != NULL);if (*str != '\0'){return 1 + my_strlen(++str);}else{return 0;}
}int main()
{char str[] = "Are you ok?";size_t len = my_strlen(str);printf("%zd\n", len);return 0;
}
? ? ? ? 我們之前說過,遞歸就是一個把大事化小的過程,適合于解決一些簡單重復的操作,就像上面重復讀取一個字符并判斷的過程。這個方法很簡單,一眼就能明白其中的原理,我就不過多闡述了。值得一說的是,這個方法并沒有創建新變量,這是區別于前兩種方法的地方。?
4、strcpy 的使用和模擬實現
? ? ? ? 4.1 strcpy 的用法?
? ? ? ? strcpy 是一個字符串拷貝函數,它的作用是把第二個參數所指的字符串拷貝給第一個參數所指的字符串數組中,注意不要搞反了。
????????更多詳細介紹請點擊查閱 —>?strcpy, strcpy_s - cppreference.com
?????????
? ? ? ? 使用 strcpy 也需要包含頭文件 <string.h>,是比較簡單的,但是有幾個需要特別注意的點。?
(1)源字符串必須以 ‘\0’ 結束;
? ? ? ? 就像 strlen 函數一樣,strcpy 函數也需要知道它應該在哪里停止拷貝。?
(2)會將源字符串中的 ‘\0’ 拷貝到目標空間;
? ? ? ? ?在上面的代碼中我們使用 strlen 函數證明了這點。
(3)目標空間必須足夠大,以確保能放得下字符串;
? ? ? ? 以上面的代碼為例,如果我們定義的字符數組 str2 太小,程序就會出錯。
??
(4)目標空間必須可修改。
? ? ? ? ?這里舉個反例來證明這一點。
? ? ? ? 將常量字符串 “abc” 存到字符指針變量 ps 中,前面說過常量字符串是不能被修改的,所以程序就出錯了。?
? ? ? ? 4.2 strcpy 的模擬實現?
? ? ? ? 就像 strlen 函數一樣,我們同樣也可以模擬實現一個 strcpy 函數,完成字符串拷貝的功能。?
#include <stdio.h>
#include <assert.h>
#include <string.h>void my_strcpy(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);while (*sour != '\0'){*dest = *sour;sour++;dest++;}*dest = *sour;//\0
}int main()
{char str1[] = "what can I say? man.";char str2[50] = { 0 };my_strcpy(str2, str1);printf("%s\n", str2);printf("%zd\n", strlen(str2));return 0;
}
? ? ? ? 邏輯也是特別簡單的,只不過我們要特別注意字符 ‘\0’ 也需要拷貝過去。
? ? ? ? 4.3 strcpy 的返回值?
? ? ? ? 關于 strcpy 函數我們可能會忽略了它的返回值,因為我們會覺得這個函數并不需要什么返回值,但其實它是有返回值的,既然有返回值,那它的返回值就有用,所以嚴格來說我們上面模擬實現的 strcpy 函數返回值應該為 char * 而不是 void 。strcpy 函數返回的是目標字符串的首地址,這使得 strcpy 可以鏈式操作。
? ? ? ??所以上面的代碼可以更新為:
#include <stdio.h>
#include <assert.h>
#include <string.h>char* my_strcpy(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);char* pd = dest;while (*sour != '\0'){*dest = *sour;sour++;dest++;}*dest = *sour;//\0return pd;
}int main()
{char str1[] = "what can I say? man.";char str2[50] = { 0 };char* ps = my_strcpy(str2, str1);printf("%s\n", ps);printf("%s\n", my_strcpy(str2, str1));printf("%zd\n", strlen(str2));return 0;
}
? ? ? ? 4.4 strcpy 模擬實現的優化?
? ? ? ? 雖然我們已經完成了 strcpy 函數的模擬實現,但上面的代碼還可以優化。因為字符‘\0’的特殊,上面的代碼中我們是將普通字符和‘\0’字符分開處理的,那是否可以有個辦法將這兩步合在一起呢?
? ? ? ? 來體會下面這條代碼:
? ? ? ? 我們用一條代碼就實現了拷貝字符串,包括拷貝字符‘\0’。其中的原理也是非常簡單,當字符‘\0’拷貝到目的空間后,括號中表達式的值為0,就自動跳出了循環。需要說明的是兩個指針變量都是先解引用,然后再自增的。
5、strcat 的使用和模擬實現
?????????5.1 strcat 的用法
? ? ? ? strcat 函數的作用是將源字符串拼接到目標字符串的后面,跟 strcpy 函數類似,strcat 是將第二個參數所指的字符串拼接到第一個參數所指的字符串后面。
? ? ? ? 更多詳細的介紹請點擊閱讀 —>?strcat, strcat_s - cppreference.com
? ? ? ? 同樣的,strcat 函數也有幾個需要注意的點:?
? ? ? ? (1)源字符串必須以‘\0’結束;
? ? ? ? (2)目標字符串中也得有‘\0’,否則沒法知道拼接在哪里;
? ? ? ? (3)目標空間必須足夠大;
? ? ? ? (4)目標空間必須可修改。
? ? ? ? 5.2 strcat 的返回值
? ? ? ? 類比 strcpy,strcat 也是有返回值的,并且返回值也是目標字符串的首地址。
? ? ? ? 5.3 strcat 的模擬實現
? ? ? ? 我們依然可以自己寫一個函數來模擬實現 strcat 的功能,方法很簡單,類似于模擬實現 strcpy 的方法,我們只需要想辦法將源字符串拼接到目標字符串末尾就行,相信對于現在有點基礎的我們來說這并不是什么難事。
#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);char* pd = dest;while (*dest++);dest--;//覆蓋掉目標字符串中的\0while (*dest++ = *sour++);return pd;
}int main()
{char str1[20] = "hello ";char str2[] = "world";char *ps = my_strcat(str1, str2);printf("%s\n", ps);return 0;
}
? ? ? ? 上面我們是將一個字符串與另一個字符串拼接在一起,那能不能將一個字符串拼接到自己的末尾呢?
? ? ? ? 可以看到,用我們自己寫的函數不能實現字符串自己拼接到自己后面,這是因為拼接的過程是在目標字符串末尾的 ‘\0’ 處開始拼接的,也就是說目標字符串的第一個字符會覆蓋掉它自己末尾的 ‘\0’,那函數的第二個參數指針就永遠也找不到 ‘\0’ 以結束拼接,就會陷入死循環。
????????但是 strcat 函數可以,不過?strcat 函數并不能保證這件事情,也就是說上面能成功是偶然的。?
? ? ? ? ? ?如果覺得我的文章還不錯,請點贊、收藏 + 關注支持一下,我會持續更新更好的文章。?