網站首頁 編程語言 正文
字符串檢驗
strlen
函數原型
/// @brief 返回給定空終止字符串的長度,即首元素為 str 所指,且不包含首個空字符的字符數組中的字符數
/// @param str 指向要檢測的字符串的指針
/// @return 字符串 str 的長度
size_t strlen( const char *str );
空終止字符串即 C 語言中以 ‘\0’ 作為終止符的字符串,strlen 計算字符串的長度并返回,返回的長度不包含 ‘\0’。
char arr[] = "qgw";
// num 的值是 3
int num = strlen(arr);
模擬實現
下面的實現方式比較簡單,采用遍歷字符串的方式,遇到 ‘\0’ 就退出循環,返回結果。
size_t my_strlen(const char* str) {
size_t cnt = 0;
while (*str != '\0') {
++str;
++cnt;
}
return cnt;
}
strcmp
函數原型
/// @brief 以字典序比較二個字符串
/// @param str rhs 要比較的兩字符串
/// @return 相等返回 0
int strcmp(const char* lhs, const char* rhs);
返回值:
- 兩字符串字典序相同,返回 0
- lhs 字典序大于 rhs,返回一個正數
- lhs 字典序小于 rhs,返回一個負數
模擬實現
實現的思路是:遍歷兩個字符串,直到出現不同或有字符串結束。
res 存儲兩字符串比較的結果,如果等于 0 循環繼續,不等于 0 直接退出,lhs 指向的字符大于 rhs 指向的字符就為正數,否則反之。
若 lhs 先結束,rhs 還沒結束,此時 res 為負數,\0 的 ASCII 碼為 0,是最小的。若 rhs 先結束,lhs 還沒結束,此時 res 為正數。若同時結束,res 剛好為 0 返回。
int my_strcmp(const char* lhs, const char* rhs) {
int res = 0;
while ((res = *lhs - *rhs) == 0 && *lhs != '\0' && *rhs != '\0') {
++lhs;
++rhs;
}
return res;
}
strstr
函數原型
/// @brief 在 str 中查找 substr 子串
/// @param str 指向要檢驗的空終止字符串的指針
/// @param substr 指向要查找的空終止字節字符串的指針
/// @return 指向于 str 中找到的子串首字符的指針,或若找不到該子串則為空指針
char *strstr( const char* str, const char* substr );
若 substr 指向空,則會返回 str。
模擬實現
下面實現的方法為暴力匹配子串,實際中可以使用 KMP 或 BM 等字符串搜索函數優化這一過程。
char* my_strstr(const char* str, const char* substr) {
if (substr == NULL) {
return str;
}
// 遍歷 str 所有字符,看以其起始字符是否匹配
while (*str != '\0') {
const char* backStr = str;
const char* backSub = substr;
while (*backStr != '\0' && *backSub != '\0' && *backStr == *backSub) {
++backStr;
++backSub;
}
// 如果 substr 走完了,說明匹配成功了,返回此時的 str
if (*backSub == '\0') {
return str;
}
++str;
}
}
字符串操作
strcpy
函數原型
/// @brief 復制 src 所指向的空終止字符串,包含空終止符,到首元素為 dest 所指的字符數組
/// @param dest 指向要寫入的字符數組的指針
/// @param src 指向要復制的空終止字符串的指針
/// @return 返回 dest 的副本
char *strcpy( char *dest, const char *src );
需要注意的是:
1.若 dest 數組長度不足則行為未定義
即 dest 數組不足以包含 src 中所有元素,此時大概率會因越屆訪問崩潰
2.若字符串覆蓋則行為未定義
現在主流編譯器都可以處理有覆蓋的情況,比如:MSVC、GCC
3.若 dest 不是指向字符數組的指針或 src 不是指向空終止字符串的指針則行為未定義
模擬實現
下面的方法先記錄要返回的地址,最后遍歷 src 遇到 \0,此時退出循環。
注意:該實現方法并不能解決字符串有覆蓋的情況。
char* my_strcpy(char* dest, const char* src) {
char* res = dest;
while (*dest = *src) {
++dest;
++src;
}
return res;
}
strcat
函數原型
/// @brief 后附 src 所指向的空終止字符串的副本到 dest 所指向的空終止字符串的結尾
/// @param dest 指向要后附到的空終止字符串的指針
/// @param src 指向作為復制來源的空終止字符串的指針
/// @return 返回 dest 的副本
char *strcat( char *dest, const char *src );
需要注意的是:
會用字符 src[0] 替換 dest 末尾的 \0
若目標數組對于 src 和 dest 的內容以及空終止符不夠大,則行為未定義
若字符串重疊,則行為未定義
若 dest 或 src 不是指向空終止字符串的指針,則行為未定義
模擬實現
因為會先用 src 第一個字符替換 dest 結尾的 \0,所以要先找到 dest 結尾 \0。然后再遍歷 src,將其添加到 dest 結尾。
char* my_strcat(char* dest, const char* src) {
char res = dest;
// 先找 \0 的位置
while (*dest != '\0') {
++dest;
}
// 追加到 dest 后面
while (*dest = *src) {
++dest;
++src;
}
return res;
}
內存操作
memcpy
函數原型
/// @brief 從 src 所指向的對象復制 count 個字符到 dest 所指向的對象
/// @param dest 指向要復制的對象的指針
/// @param src 指向復制來源對象的指針
/// @param count 復制的字節數
/// @return 返回 dest 的副本
void* memcpy(void* dest, const void* src, size_t count);
要注意的是:
若訪問發生在 dest 數組結尾后則行為未定義
若對象重疊,則行為未定義
也就是說在標準中 memcpy 也不能處理對象重疊的情況
若 dest 或 src 為非法或空指針則行為未定義
模擬實現
下面給出的實現方式與 strcpy 相似,不過是改用 count 變量來控制循環次數。
memcpy 是最快的內存到內存復制子程序。它通常比必須掃描其所復制數據的 strcpy,或必須預防以處理重疊輸入的 memmove更高效。
void* my_memcpy(void* dest, const void* src, size_t count) {
void* res = dest;
while (count--) {
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
return res;
}
memmove
函數原型
/// @brief 從 src 所指向的對象復制 count 個字節到 dest 所指向的對象
/// @param dest 指向要復制的對象的指針
/// @param src 指向復制來源對象的指針
/// @param count 復制的字節數
/// @return 返回 dest 的副本
void* memmove(void* dest, const void* src, size_t count);
memmove 是不是看起來和 memcpy 一模一樣,但 memmove 可以處理內存重疊的情況,這也就說明它要做一些檢查,來保證能夠處理內存重疊的情況。
1.無重疊
直接調用更高校的 memcpy
2.有重疊,dest 在 src 之前,正常正向復制
3.有重疊,dest 在 src 之后,需要反向復制
模擬實現
通過對上圖的觀察,我們可以發現:若 dest 在 src 的后面并且存在內存重疊,就需要反向復制。
我們可以簡化這一函數,對無重疊的情況不去調用 memcpy 而是包含在下面兩種情況中。
dest 在 src 之前,采用正向復制
dest 在 src 之后,采用反向復制
void* my_memmove(void* dest, const void* src, size_t count) {
void* res = dest;
if (dest < src) {
while (count--) {
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
} else {
while (count--) {
*((char*)dest + count) = *((char*)src + count);
}
}
}
原文鏈接:https://blog.csdn.net/qq_40080842/article/details/128671029
相關推薦
- 2022-05-14 pytorch中with?torch.no_grad():的用法實例_python
- 2022-08-07 使用pd.merge表連接出現多余行的問題解決_python
- 2023-03-25 Excel?VBA指定條件刪除整行整列的實現_vbs
- 2023-07-08 echarts多個series進行自定義tooltip的數據顯示
- 2022-06-09 ASP.NET?Core基于現有數據庫創建EF模型_實用技巧
- 2022-09-18 iOS開發探索多線程GCD隊列示例詳解_IOS
- 2022-12-29 R語言中dnorm,pnorm,qnorm和rnorm的區別淺析_R語言
- 2022-09-03 pandas?如何保存數據到excel,csv_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支