輕松拿捏C語言——【字符串函數】的使用及模擬實現

🥰歡迎關注?輕松拿捏C語言系列,來和 小哇 一起進步!?

🎉創作不易,請多多支持🎉

🌈感謝大家的閱讀、點贊、收藏和關注💕

🌹如有問題,歡迎指正 感謝


目錄

一、 strlen的使用和模擬實現

二、strcpy的使用和模擬實現

三、strcat的使用和模擬實現

四、strcmp的使用和模擬實現

五、strncpy的使用和模擬實現

六、strncat的使用和模擬實現

七、strncmp的使用和模擬實現

八、strstr的使用和模擬實現

九、strtok的使用和模擬實現

十、strerror的使用和模擬實現


一、 strlen的使用和模擬實現

size_t strlen ( const char * str );

注意:?

? 字符串以 '\0' 作為結束標志,strlen函數返回的是在字符串中 '\0' 出現前面的字符個數(不包含 '\0' )。

? 參數指向的字符串必須要以 '\0' 結束。

? 注意函數的返回值為 size_t,是無符號的( 易錯 )

? strlen的使用需要包含頭文件?

#include <stdio.h>
#include <string.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if(strlen(str2)-strlen(str1)>0){printf("str2>str1\n");} else{printf("srt1>str2\n");}return 0;
}

因為strlen返回值為無符號整型,所以if條件中的不是 3 - 6 = -3,而應該是-3的補碼 一個大于0的數字,所以打印 str2>str1?

#include <stdio.h>
#include <string.h>
int main()
{//char arr[] = "abcdef";char arr[] = { 'a', 'b','c' };size_t len = strlen(arr);printf("%zd\n", len);return 0;
}

無\0,打印出的是隨機值?

模擬實現

法一:計算器方式

//計數器?式
int my_strlen(const char * str)
{int count = 0;assert(str);while(*str){count++;str++;}return count;
}

法二: 遞歸的方式

int my_strlen(const char * str)
{assert(str);if(*str == '\0')return 0;elsereturn 1+my_strlen(str+1);
}

法三:指針相減

size_t my_strlen(const char* str)
{const char* start = str;assert(str != NULL);while (*str != '\0'){str++;}return str - start;
}

二、strcpy的使用和模擬實現

char* strcpy(char * destination, const char * source );

注意:

? 源字符串必須以 '\0' 結束。

? 會將源字符串中的 '\0' 拷貝到目標空間。

? 目標空間必須足夠大,以確保能存放源字符串。

? 目標空間必須可修改。?

正確使用:

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "hello world";char arr2[20] = {0};//1個元素strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}

錯誤使用:

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "hello world";char* p = "xxxxxxxxxxxxxxxxxxxx";//常量字符串-不能修改strcpy(p, arr1);//errprintf("%s\n", p);return 0;
}

模擬實現:?

strcpy函數返回的是目標空間的起始地址

char* my_strcpy(char* dest, const char* src)
{//assert(dest != NULL);//assert(src != NULL);assert(dest && src);char* ret = dest;while (*src != '\0'){*dest = *src;src++;dest++;}*dest = *src;//拷貝\0return ret;//返回目標空間的起始地址
}

優化:


char* my_strcpy(char* dest, const char* src)
{//assert(dest != NULL);//assert(src != NULL);assert(dest && src);char* ret = dest;while (*dest++ = *src++)//拷貝過去字符后,判斷表達式的值,當\0拷貝過去后,判斷為假,停止循環{;}return ret;//返回目標空間的起始地址
}

三、strcat的使用和模擬實現

char * strcat ( char * destination, const char * source );

注意:

? 源字符串必須以 '\0' 結束。

? 目標字符串中也得有 \0 ,否則沒辦法知道追加從哪里開始。

? 目標空間必須有足夠的大,能容納下源字符串的內容。

? 目標空間必須可修改。

? 字符串自己給自己追加,如何?不能保證?

使用:

int main()
{char arr1[20] = "he\0lloxxxxx";char arr2[] = "world";strcat(arr1, arr2);//字符串追加printf("%s\n", arr1);return 0;
}

從第一個\0開始追加

?

模擬實現:

#include<stdio.h>
#include<assert.h>
//要返回目標空間的起始地址
char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1. 找目標空間的\0while (*dest != '\0')dest++;//2. 拷貝while (*dest++ = *src++);return ret;
}

四、strcmp的使用和模擬實現

int strcmp ( const char * str1, const char * str2 );

注意:

第?個字符串大于第?個字符串,則返回大于0的數字 ?

第?個字符串等于第?個字符串,則返回0 ?

第?個字符串小于第?個字符串,則返回小于0的數字 ?

(在vs上,大于0返回的1,小于0返回的-1)

那么如何判斷兩個字符串? 比較兩個字符串中對應位置上字符ASCII碼值的大小。?

使用:

#include<stdio.h>
#include<string.h>int main()
{char arr1[] = "abq";char arr2[] = "abcdef";int ret = strcmp(arr1, arr2);//printf("%d\n", ret);if (ret >0){printf(">\n");}else{printf("<=\n");}return 0;
}

打印 >

模擬實現 :

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}return (*str1 - *str2);	
}

五、strncpy的使用和模擬實現

?char * strncpy ( char * destination, const char * source, size_t num );

注意?:

? 拷貝num個字符從源字符串到目標空間。

? 如果源字符串的長度小于num,則拷貝完源字符串之后,在目標的后邊追加0,直到num個。

?

使用:

#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "abcdef";char arr2[20] = "xxxxxxxxxxx";strncpy(arr2, arr1, 8);printf("%s\n", arr2);return 0;
}

模擬實現(如有問題,歡迎指正):

//用函數實現strncpy的功能
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strncpy(char* dest, char* source,size_t n)
{assert(dest && source);char* ret = dest;char* temp = source;while((*dest++ = *source++ )&&(source<temp + n)){;}return ret;
}
int main()
{char arr1[20] = "abcdef";char arr2[20] = "xxxxxxxxxx";size_t num;while(scanf("%zd", &num)!=EOF)//多次循環輸入{/*strncpy(arr2, arr1, num);printf("%s\n", arr2);*/char* ret = my_strncpy(arr2, arr1, num);printf("%s\n", ret);}return 0;
}

?

六、strncat的使用和模擬實現

char * strncat ( char * destination, const char * source, size_t num );

注意:

?將source指向字符串的前num個字符追加到destination指向的字符串末尾,再追加?個 \0 字 符。

?如果source 指向的字符串的長度小于num的時候,只會將字符串中到 \0 的內容追加到destination指向的字符串末尾?

使用:

int main()
{char arr1[20] = "abcdef\0yyyyyyyy";char arr2[20] = "xxxxxxxx";strncat(arr1, arr2, 3);printf("%s\n", arr1);return 0;
}

模擬實現(如有問題,歡迎指正):

#include<stdio.h>
//實現strncat的功能
#include<assert.h>
char* my_strncat(char* dest,const char* source, int num)
{assert(dest && source);char* ret = dest;char* temp = source;while (*dest){dest++;}while ((*dest++ = *source++) && (source < temp+num)){;}return ret;
}
int main()
{char a[20] = "abcdef";char* b = "hhhhhh";int n;scanf("%d", &n);char* ret = my_strncat(a,b,n);printf("%s\n", ret);return 0;
}

七、strncmp的使用

int strncmp ( const char * str1, const char * str2, size_t num );

比較str1和str2的前num個字符,如果相等就繼續往后比較,最多比較num個字?,如果提前發現不? 樣,就提前結束,大的字符所在的字符串大于另外?個。如果num個字符都相等,就是相等返回0.?

#include<stdio.h>
#include<string.h>
int main()
{char arr1[20] = "abcdef";char arr2[20] = "ab";int ret = strncmp(arr1, arr2, 4);printf("%d\n", ret);return 0;
}

八、strstr的使用和模擬實現

char * strstr ( const char * str1, const char * str2);

在str1中找str2字符串第一次出現的位置, 找到了就返回第一次出現的起始地址,找不到返回NULL;

注意:?

?函數返回字符串str2在字符串str1中第?次出現的位置;

字符串的比較匹配不包含 \0 字符,以 \0 作為結束標志。

使用:

#include<string.h>
int main()
{char arr[] = "abcdefabcdef";char* p = "cdefa";char* ret = strstr(arr, p);if (ret == NULL){printf("不存在\n");}else{printf("%s\n", ret);}return 0;
}

?

模擬實現(如有問題,歡迎指正):

#include<stdio.h>
//模擬實現strstr
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* s1 = NULL;const char* s2 = NULL;const char* cur = str1;if (*str2 == '\0')return str1;while (*cur){s1 = cur;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return cur;cur++;}return NULL;
}
int main()
{char arr[] = "KIKU is JJY,an Idol and actress ";char* p = "JJY";const char* ret =my_strstr(arr, p);if (ret == NULL)printf("找不到");elseprintf("%s\n", ret);return 0;
}

九、strtok的使用

char * strtok ( char * str, const char * sep);

?注意:

? sep參數指向?個字符串,定義了用作分隔符的字符集合

? 第?個參數指定?個字符串,它包含了0個或者多個由sep字符串中?個或者多個分隔符分割的標 記。

? strtok函數找到str中的下?個標記,并將其用\0 結尾,返回?個指向這個標記的指針。(注: strtok函數會改變被操作的字符串,所以被strtok函數切分的字符串?般都是臨時拷貝的內容并且 可修改。)

? strtok函數的第?個參數不為 NULL ,函數將找到str中第?個標記,strtok函數將保存它在字符串 中的位置。

? strtok函數的第?個參數為 NULL ,函數將在同?個字符串中被保存的位置開始,查找下?個標 記。

? 如果字符串中不存在更多的標記,則返回 NULL 指針

?

什么意思呢?通俗來講就是,

第一次使用strtok函數時,

在第一個參數指向的字符串中去找分隔符sep,找到后把這個分隔符變成\0,

記住\0的地址即要查找的下一部分的起始地址,返回值就是\0前面這部分的地址。

然后后面再調用的話,第一個參數變成NULL,從記住的\0位置開始往后繼續找分隔符,

找到了就又把這個分隔符變成\0并記住它的地址,返回值時這個\0前的這部分字符串的地址。

使用:

1、不用循環

#include <stdio.h>
#include <string.h>
//strtok函數使用
int main()
{char arr[] = "BaoGengXiaoWa@yeah.net@hehe.haha#ttttt";char buf[256] = { 0 };strcpy(buf, arr);//"BaoGengXiaoWa@yeah.net@hehe.haha#ttttt"//char sep[] = "@.";char* sep = "@.";/*char* ret = NULL;for (ret = strtok(buf, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}*/char* ret = strtok(buf, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);return 0;
}

?

2、使用循環

#include<stdio.h>
#include<string.h>
//strtok函數使用
int main()
{char arr[] = "BaoGengXiaoWa@yeah.net@hehe.haha#ttttt";char buf[256] = { 0 };strcpy(buf, arr);//"BaoGengXiaoWa@yeah.net@hehe.haha#ttttt"//char sep[] = "@.";char* sep = "@.";char* ret = NULL;for (ret = strtok(buf, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}/*char* ret = strtok(buf, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);*/return 0;
}

?

十、strerror的使用和模擬實現

char* strerror ( int errnum );

strerror 函數可以把參數部分錯誤碼對應的錯誤信息的字符串地址返回來。

在不同的系統和C語言標準庫的實現中都規定了?些錯誤碼,?般是放在 errno.h 這個頭文件中說明的

C語言程序啟動的時候就會使用?個全局的變量errno來記錄程序的當前錯誤碼,只不過程序啟動的時候errno是0,表示沒有錯誤

當我們在使用標準庫中的函數的時候發生了某種錯誤,就會將對應的錯誤碼,存放在errno中,而?個錯誤碼的數字是整數很難理解是什么意思,所以每?個錯誤碼都是有對應的錯誤信息的。

strerror函數就可以將錯誤對應的錯誤信息字符串的地址返回。?

我們打印?下0~10這些錯誤碼對應的信息:

#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{int i = 0;for (i = 0; i <= 10; i++) {printf("%s\n", strerror(i));}return 0;
}

舉例:?

#include<stdio.h>
#include <string.h>
#include <errno.h>
int main()
{//打開文件FILE* pf = fopen("data.txt", "r");//"r"- 讀,以讀文件的形式,打來文件,如果這個文件不存在,就打開失敗if (pf == NULL){printf("打開文件失敗,原因是: %s", strerror(errno));return 1;}else{printf("打開文件成功\n");//.....fclose(pf);pf = NULL;}return 0;
}

也可以使用 perror 函數,perror函數相當于?次將上述代碼中的代碼

????????printf("打開文件失敗,原因是: %s", strerror(errno));

完成了,直接將錯誤信息打印出來。

perror函數打印完參數部分的字符串后,再打印?個冒號和?個空格,再打印錯誤信息。?

?

int main()
{//打開文件FILE* pf = fopen("data.txt", "r");//"r"- 讀,以讀文件的形式,打來文件,如果這個文件不存在,就打開失敗if (pf == NULL){perror("打開文件失敗,原因是");//		//perror == printf + strerrorreturn 1;}else{printf("打開文件成功\n");//.....fclose(pf);pf = NULL;}return 0;
}

?🎉🎉🎉本文內容結束啦,希望各位大佬多多指教!

🌹🌹感謝大家三連支持

💕敬請期待下篇文章吧~

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15159.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15159.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15159.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql 拼接兩個字段的值 使用CONCAT的函數

CONCAT()函數拼接兩個不用字段的值&#xff0c;最后在一個字段里面顯示出來&#xff0c;具體實例如下&#xff1a; 下面這個案例就行把SSSHENGBH、SSSBH、SSXBH、SSXZBH字段值拼接到一個字段里面進行顯示 select CONCAT(SSSHENGBH,SSSBH,SSXBH,SSXZBH) FROM BLT_JBXXJLB

3D 生成重建013-ProlificDreamer將SDS拓展到VSD算法進行高質量的3D生成

3D 生成重建013-ProlificDreamer將SDS拓展到VSD算法進行高質量的3D生成 文章目錄 0論文工作1論文方法2效果 0論文工作 **分數蒸餾采樣&#xff08;SDS&#xff09;**通過提取預先訓練好的大規模文本到圖像擴散模型&#xff0c;在文本到3d生成方面顯示出了巨大的前景&#xff0…

Windows VS2022 C語言使用 sqlite3.dll 訪問 SQLite數據庫

今天接到一個學生C語言訪問SQLite數據庫的的需求: 第一步,SQLite Download Page下載 sqlite3.dll 庫 下載解壓,發現只有兩個文件: 于是使用x64 Native Tools Command Prompt 終端 生成 sqlite3.lib 和 sqlite3.exp文件 LIB -def:sqlite3.def -out:sqlite3.lib -machin…

廣告圈策劃大師課:活動策劃到品牌企劃的深度解析

對于剛接觸營銷策劃的新人來說&#xff0c;在這個知識密集型行業里生存&#xff0c;要學習非常多各種意思相近的概念&#xff0c;常常讓人感到頭疼&#xff0c;難以區分。 這里對這些策劃概念進行深入解析&#xff0c;幫助您輕松理清各自的含義和區別。 1. 活動策劃&#xff…

C++ 字符串處理-將字符串轉成大寫或小寫

1. 關鍵詞2. strutil.h3. strutil.cpp4. 測試代碼5. 運行結果6. 源碼地址 1. 關鍵詞 C 字符串處理 將字符串轉成大寫或小寫 跨平臺 2. strutil.h #include <string> namespace cutl {/*** brief Convert a string to upper case.** param str the string to be conve…

微信小程序自定義頭部

1.在對應界面的json文件&#xff0c;將navigationStyle屬性設置為“custom” "navigationStyle":"custom" 2. 狀態欄的高度可以通過 wx.getSystemInfo() 獲取。 膠囊按鈕的信息可以通過 wx.getMenuButtonBoundingClientRect() 獲取。 導航欄高度狀態欄…

截圖工具PixPin(比Snipaste更強大)

PixPin官網鏈接&#xff1a;https://pixpinapp.com/ 最近新出的一款截圖工具PixPin&#xff0c;比Snipaste功能多一些。在Snipaste功能基礎上&#xff0c;還支持長截圖&#xff0c;截動圖&#xff0c;文本識別。

C++11-獨占指針unique_ptr原理實現

獨占指針&#xff08;unique_ptr&#xff09;是C11標準引入的一種智能指針&#xff0c;用于獨占管理動態分配對象的生命周期。unique_ptr確保對象在同一時間只有一個所有者&#xff0c;防止對象被多個指針共享。下面是unique_ptr的實現原理及其內存管理機制。 unique_ptr 的基…

618好物推薦,省心省力省錢包!

一年一度的“618”購物狂歡節又來啦&#xff01;大家都心動了吧&#xff0c;購物車也早就堆滿了心儀的好物。別急&#xff0c;別急&#xff0c;讓我給你們推薦幾款真正值得入手的寶貝&#xff0c;讓你們省心、省力還省錢包&#xff01;不管是給自己添置點新裝備&#xff0c;還是…

Vue實現一個動態添加行的表格?

在Vue中實現一個動態添加行的表格可以通過以下步驟來完成&#xff0c;如下所示。 步驟 1&#xff1a;設置表格的數據模型 在Vue組件中定義表格的數據模型&#xff0c;通常使用一個數組來存儲表格的數據。每一行數據可以是一個對象&#xff0c;對象的屬性對應表格的列。 data(…

MFC 編程:Windows 桌面應用程序開發框架

目錄 一.概述 二.MFC 與 Win32 的關系 三.CObject 類 1.CObject 類的主要功能 2.CObject 類的派生類 3.CObject 類成員函數 4.內存管理 對象的創建 對象的銷毀 引用計數 復制對象 5.序列化 序列化的概念 CObject 類的序列化功能 序列化示例 6.運行時類型信息 …

uniapp App去除iOS底部安全區域白邊

未設置的情況下&#xff0c;iOS底部安全區域白邊 如圖&#xff1a; 去除方法&#xff1a; 在 mainfest.json 中加入一下代碼&#xff1a; "safearea" : {"bottom" : {"offset" : "none"} }, 去除效果展示&#xff1a;

Git使用筆記

Git使用筆記 介紹Git推送指定的提交 介紹 Git推送指定的提交 在Git中&#xff0c;如果只想推送一個特定的提交&#xff08;commit&#xff09;&#xff0c;而不是整個分支&#xff0c;可以使用以下步驟&#xff1a; 首先&#xff0c;找到你想要推送的提交的哈希值。通過運行g…

開放式耳機2024超值推薦!教你如何選擇藍牙耳機!

開放式耳機的便利性讓它在我們的日常生活中變得越來越重要。它讓我們擺脫了傳統耳機的限制&#xff0c;享受到了更多的自由。不過&#xff0c;市面上的開放式耳機種類繁多&#xff0c;挑選一款既實用又實惠的產品確實需要一些小竅門。作為一位對開放式耳機頗有研究的用戶&#…

SOLC install 中的問題

solc.install 總是卡死&#xff0c;他拉取的網站出問題了 直接把所有的包都下載下來 sudo add-apt-repository ppa:ethereum/ethereum sudo apt-get update sudo apt-get install solc pip install py-solc-x 文檔 https://web3py.readthedocs.io/en/stable/web3.contract.h…

[WUSTCTF2020]funnyre

ida打開 mian 函數 不能反匯編&#xff0c;往下翻有一處報紅&#xff0c;一看是花指令&#xff0c;還怪長&#xff0c;報紅的都nop后&#xff0c;全選按P重新生成函數 三百多個變量&#xff0c;也是不太可能一個個去解了&#xff0c;剛好前兩天簡單練了一下 angr &#xff08;…

C++多生產者,多消費者模型

C11實現多生產者&#xff0c;多消費者模型 在C標準庫中實現多生產者多消費者模型&#xff0c;可以使用std::thread、std::queue、互斥鎖(std::mutex)、條件變量(std::condition_variable)等組件。下面是一個簡單的示例&#xff0c;展示如何創建多生產者和多消費者模型&#xf…

3款錄屏錄制軟件,打造專業級視頻內容

隨著技術的不斷發展&#xff0c;人們在日常工作和學習中經常會遇到記錄電腦屏幕的需求&#xff0c;例如錄制游戲過程、制作教程、保存會議記錄等。為了解決這一需求&#xff0c;許多錄屏錄制軟件應運而生。本文將介紹三款常見的錄屏錄制軟件&#xff0c;通過分析它們的特點和使…

一文帶你搞懂DiT(Diffusion Transformer)

節前&#xff0c;我們組織了一場算法崗技術&面試討論會&#xff0c;邀請了一些互聯網大廠朋友、今年參加社招和校招面試的同學。 針對大模型技術趨勢、大模型落地項目經驗分享、新手如何入門算法崗、該如何準備面試攻略、面試常考點等熱門話題進行了深入的討論。 總結鏈接…