字符串和字符串函數(2)

前言:

? ? ? ? 在字符串和字符串函數(1)-CSDN博客中,已將將字符串和字符函數的使用了解,并且實現模擬了一些字符串的庫函數。????????

? ? ? ? 接下來將繼續深入學習字符串和字符串函數。并且模擬實現一些較為復雜的函數。

可控制字符長的的函數

介紹并使用strncpy函數

??? ? ?相同點?strncpy函數和strcpy函數的形同點是都可以實現字符串的拷貝,可以將一個字符串中的內容拷貝到另一個字符串中。

? ?? ? 不同點strnpy和strcpy函數的區別在于,strcpy只能將一個字符串中的所有內容全部拷貝到另一個字符串中,但是strnpy可以將一個字符串中的內容,有選擇的拷貝到另一個字符串當中,參數也從2個變成了3個。? ?

例如:我要將arr1[]中的前3個字符拷貝到arr2[]中:

? ? ? ? 可不可以這樣實現,其實問題就在于傳完3個字符之后,有沒有將\0也傳進去?

int main()
{char arr1[] = { "ab cd ef" };char arr2[20];strncpy(arr2, arr1, 3);printf("%s\n", arr2);return 0;
}

通過調試可以看到:

? ? ? ? 在arr1中:

拷貝之后,arr2中是這樣:

發現:并沒有將'\0'考進去!

所以,分兩種情況:

? ? 1、如果我想把一個字符串中幾個字符給拿出來,這時候需要注意我們要手動將拿出來的字符串中的最后一個字符后面的一個字符加上'\0'

? ? ?2、如果我只是想將一個字符串中的前幾個元素做一個替換,此時就不需要手動加上'\0'。

例1:拿出arr1中的3個字符。

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

打印結果:

????????

例2:替換arr2中的前三個字符
????????

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

模擬實現strncpy函數:

? ? ? ? 我們可以在strcpy的基礎上再進行一些修改:

#include<stdio.h>
#include<assert.h>
char* my_strnpy( char* arr2, const char* arr1, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);char* start = arr2;while (num){*arr2++ = *arr1++;num--;}return start;
}int main()
{char arr1[] = {"love you"};char arr2[] = { "like me" };my_strnpy(arr2, arr1,4);printf("%s\n", arr2);return 0;
}

介紹并使用strncat函數:

與strcat相比較:

相同點都可以實現對字符串的追加。

不同點strncat按自我需求調整所追加的字符串的長度。

? ? ? ? ? ? ? ? strcat只能將一個字符串全部內容追加到另一個字符串當中。

追加的時候是從目的地字符數組的'\0'處開始追加。

看一組代碼:

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = {"abcd"};char arr2[20] = { "asdf " };strncat(arr2, arr1, 4);printf("%s\n", arr2);return 0;
}

通過調試來觀測一下:

? ? ? ? 初始化之后:

進入函數之后:

????????

注意:這是后也沒有主動追加'\0',可以最后手動追加

模擬實現strncat函數:

????????

char* my_strncat(char* arr1, const char* arr2, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);char* start = arr1;while (*arr1){arr1++;}while (num){*arr1++ = *arr2++;num--;}return start;
}
int main()
{char arr1[20] = {"love me "};char arr2[] = { "like you" };my_strncat(arr1, arr2, 4);printf("%s\n", arr1);return 0;
}

介紹并使用strncmp函數:

????????

相關介紹和返回值,發現和strcmp函數的返回值是一樣的。

區別:除了多了一個參數num,也就是你要比較幾個字符之外,其他的都是一樣的。

int main()
{char arr1[] = {"abcdef"};char arr2[] = { "abcds" };int a =  strncmp(arr1, arr2,5);if (a == 0){printf("=");}else if (a < 0){printf("<");}else{printf(">");}return 0;
}

模擬實現strncmp函數

????????

int my_strncmp(const char* arr1, const char* arr2, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);while ( *arr1 - *arr2 == 0){arr1++;arr2++;num--;if (num-1 == 0){break;}}return *arr1-*arr2;
}
int main()
{char arr1[] = {"abcd"};char arr2[] = {"abfde"};int a = my_strncmp(arr1,arr2,4);if (a == 0){printf("=");}else if (a < 0){printf("<");}else{printf(">");}return 0;
}

其他類型庫函數

介紹并使用strstr函數:

????????

返回指向?str1?中首次出現的?str2?的指針,如果?str2?不是?str1?的一部分,則返回空指針.

????????

int main()
{char arr1[] = {"love you best"};char *arr =  strstr(arr1, "you");printf("%s\n", arr);return 0;
}

? ?在arr1中找you,找到第一次出現的地方返回第一次出現的首字符的地址。

打印結果:

如果找不到,就返回NULL;

例如:

int main()
{char arr1[] = {"love you best"};char *arr =  strstr(arr1, "yoo");printf("%s\n", arr);return 0;
}

打印結果:

注:這里找相同的字符串必須完全相同,差一個字符都不行!!

模擬實現strstr函數:

? ? ? ? 首先通過畫圖來講解:

????????

char* my_strstr(const char* arr1, const char* arr2)
{char* cp = (char*)arr1;//表示arr1的紅色指針char* a;//表示arr1的綠色指針char* b;//表示arr2的綠色指針while (*cp){if (*cp == *arr2){a = cp;b = (char*)arr2;while (*cp == *b){cp++;b++;if (*b == '\0')return a;}}cp++;}return NULL;
}
int main()
{char arr1[] = { " welcom next new world" };char arr2[] = {"new"};char *str = my_strstr(arr1, arr2);printf("%s\n", str);return 0;
}

介紹并使用memcpy(內存拷貝函數)函數:

????????

之前探討了strcpy和strncpy,這兩個庫函數是用來拷貝字符串的,其它類型的不能拷貝,那么其他類型的數據該如何拷貝呢?

? ? ? ? 就需要用到memcpy函數,可以拷貝任意類型的數據!

例如:

int main()
{int arr1[] = {1,2,3,4,5};int arr2[20];memcpy(arr2,arr1, 20);return 0;
}

需要三個參數,目的地地址,源頭地址,需要拷貝的字節數,

? ? ? ? 通過調試發現:

拷貝成功!

模擬實現memcpy函數

void* my_memcpy(void* str1, const void *str2, size_t sz)
{void* start = str1;assert(str1 && str2);while (sz){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;sz--;}return start;
}
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[10];my_memcpy(arr2,arr1,20);return 0;
}

拷貝完成!

但是,這回突發奇想,想將arr1中的前4個拷貝到從第二個整形開始。可不可以呢?

void* my_memcpy(void* str1, const void *str2, size_t sz)
{void* start = str1;assert(str1 && str2);while (sz){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;sz--;}return start;
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };my_memcpy(arr1+2,arr1,16);return 0;
}

發現是不可以的,那么如果我要實現重疊部分的拷貝,應該怎么辦,可以使用庫函數中的memmove函數!

? ? ? ? 接下來就來探究一下memmove函數!

介紹并使用memmove函數

和memcopy相比,memmove可以完成重疊部分的拷貝工作!

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };memmove(arr1+2,arr1,16);return 0;
}

發現可以進行重疊部分的拷貝!

模擬實現memmove函數:

? ? ? ? 那么應該怎樣拷貝,才不會出現在memcpy中的情況呢,這里分為三種情況:

1、源頭地址在目的地的左側,源頭低地址,目的地高地址。

此時不會再出現被覆蓋的情況。

2、源頭地址在目的地的左右側,源頭高地址,目的地低地址。

3、源頭和目的地沒有重疊部分

這種情況怎么拷貝都行,只要空間夠用即可。

以上這幾種情況就是memmove函數的思路!

以下是代碼:

void* my_memmove(void* str1, void* str2, size_t num)
{void* start = str1;int sz = num;if (str1 > str2){while (sz){str2 = (char*)str2+1;str1 = (char*)str1 + 1;sz--;}while (sz != num){*(char*)str1 = *(char*)str2;str1 = (char*)str1-1;str2 = (char*)str2 - 1;sz++;}}else {while (sz--){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;}}return start;
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };my_memmove(arr1,arr1+2,12);return 0;
}

????????

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

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

相關文章

【Linux基礎】安裝nginx

【Linux基礎】安裝nginx 文章目錄 【Linux基礎】安裝nginx1、下載nginx2、安裝nginx3、使用nginx4、配置nginx環境變量 1、下載nginx 在Nginx的官網的下載頁面中(http://nginx.org/en/download.html)&#xff0c;就展示了當前Nginx版本&#xff0c;并提供了下載的連接。 如下&a…

圖像處理之基于標記的分水嶺算法(C++)

圖像處理之基于標記的分水嶺算法&#xff08;C&#xff09; 文章目錄 圖像處理之基于標記的分水嶺算法&#xff08;C&#xff09;前言一、基于標記點的分水嶺算法應用1.實現步驟&#xff1a;2.代碼實現 總結 前言 傳統分水嶺算法存在過分割的不足&#xff0c;OpenCV提供了一種…

【C語言進階】動態內存管理及柔性數組

動態內存的開辟在C語言中相當重要的知識 1、為什么會存在動態內存分配 內存的開辟方式&#xff1a; int a20;//在棧空間上開辟4個字節 int arr[10];//在棧空間上開辟40個字節的連續空間 這種開辟空間的方式有兩個特點&#xff1a; 1、開辟的空間大小是固定的 2、數組在聲明的…

二叉樹創建和遍歷

個人主頁 &#xff1a;敲上癮-CSDN博客二叉樹介紹&#xff1a;二叉樹(詳解)-CSDN博客 目錄 一、二叉樹的創建 二、二叉樹的遍歷 1.前序遍歷 2.中序遍歷 3.后序遍歷 4.層序遍歷 三、相關計算 1.總節點個數計算 2.葉子節點個數計算 3.深度計算 一、二叉樹的創建 關于…

如何在路由器上安裝代理服務:詳細教程

如何在路由器上安裝代理服務&#xff1a;詳細教程 步驟一&#xff1a;通過漏洞進入路由器系統開啟Telnet服務使用Telnet登錄路由器系統查看系統信息和CPU信息步驟二&#xff1a;交叉編譯MIPS程序 Go對MIPS的支持 安裝TFTP Server使用BusyBox tftp傳輸文件在路由器系統中下載編譯…

?機器學習正則化算法的總結。耗時10個小時完成。?

?純 干 貨~? 目錄 純干貨 1、L1 正則化&#xff08;Lasso 正則化&#xff09; 2、L2 正則化&#xff08;嶺正則化&#xff09; 3、彈性網絡正則化&#xff08;Elastic Net 正則化&#xff09; 4、Dropout 正則化&#xff08;用于神經網絡&#xff09; 5、貝葉斯Rid…

海外盲盒小程序:跨文化營銷的利器

在全球化的浪潮下&#xff0c;跨境電商正迎來前所未有的發展機遇。作為這一領域中的新興力量&#xff0c;海外盲盒小程序憑借其獨特的魅力和優勢&#xff0c;正逐漸嶄露頭角&#xff0c;成為跨文化營銷的利器。本文將探討海外盲盒小程序在跨文化營銷中的應用及其帶來的價值。 一…

【30天精通Prometheus:一站式監控實戰指南】第16天:snmp_exporter從入門到實戰:安裝、配置詳解與生產環境搭建指南,超詳細

親愛的讀者們&#x1f44b; ??歡迎加入【30天精通Prometheus】專欄&#xff01;&#x1f4da; 在這里&#xff0c;我們將探索Prometheus的強大功能&#xff0c;并將其應用于實際監控中。這個專欄都將為你提供寶貴的實戰經驗。&#x1f680; ??Prometheus是云原生和DevOps的…

【java11】java11新特性之增強String的API

Java11在String類上引入了一系列新的API增強&#xff0c;這些改進顯著提升了開發者在處理字符串時的便捷性和效率。 以下是Java11中增強String API的主要新特性&#xff1a; String.repeat()&#xff1a;重復給定次數的字符串。返回連接的字符串。String.isBlank()&#xff1…

ldap協議(常用于統一身份認證)與dict協議(在線詞典)

文章目錄 LDAPDICT LDAP LDAP&#xff08;Light Directory Access Portocol&#xff09;&#xff0c;輕量目錄訪問協議。 目錄是一個為查詢、瀏覽和搜索而優化的數據庫&#xff0c;它成樹狀結構組織數據&#xff0c;類似文件目錄一樣。 目錄數據庫和關系數據庫不同&#xff0c…

spring security 使用記錄

spring security 使用記錄 Bad credentials配置類密碼匹配 Bad credentials org.springframework.security.authentication.BadCredentialsException: Bad credentialsat org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticatio…

Docker安裝極簡版(三分鐘搞定)

什么是Docker? Docker是一個開源的應用容器引擎&#xff0c;它允許開發者打包他們的應用以及依賴包到一個可移植的容器中&#xff0c;然后發布到任何流行的Linux機器上&#xff0c;也可以實現虛擬化。容器是完全使用沙箱機制&#xff0c;相互之間不會有任何接口。 化。容器是…

日志脫敏功能

前言 數據安全尤為重要&#xff0c;最為簡單的防線就是防止重要信息&#xff08;身份證、手機號、姓名等&#xff09;明文顯示&#xff0c;對此需要在數據庫層、日志層等做好數據加解密。 思路 1、編寫需加密的正則模板、加密字段 2、重寫ch.qos.logback.classic.pattern.Me…

簡易圖像處理器的設計

1 概述 Python是一種高級、通用、解釋型的編程語言&#xff0c;由Guido van Rossum于1991年創造。它被設計為易讀易寫的語言&#xff0c;具有簡潔而清晰的語法&#xff0c;使得它成為許多領域的首選語言&#xff0c;如Web開發、科學計算、人工智能、數據分析等。結合本科階段以…

三維地圖校內導航系統解決方案

在如今的數字化時代&#xff0c;越來越多的學校開始實施智慧校園計劃&#xff0c;旨在為學生和教師提供更高效、便捷的學習和教學環境。智慧校園運用互聯網、大數據、人工智能等技術&#xff0c;對校園內各信息進行收集、整合、分析和應用&#xff0c;實現教學、管理、服務等多…

【matlab】繪圖插入并放大/縮小子圖

參考鏈接 代碼分為兩個&#xff1a;繪圖代碼與magnify.m 繪圖代碼就是普通的繪圖代碼&#xff0c;以下為例 %https://zhuanlan.zhihu.com/p/655767542 clc clear close all x 0:pi/100:2*pi; y1 sin(x); plot(x,y1,r-o); hold on y2sin(x)-0.05; y3sin(x)0.05; xlim([0 2*…

C#關鍵字概覽

C#是一種面向對象的編程語言&#xff0c;由微軟開發并作為.NET框架的一部分。它具有豐富的關鍵字&#xff0c;用于定義程序的結構和行為。本文將詳細介紹C#中的關鍵字&#xff0c;包括基本關鍵字、上下文關鍵字以及它們在C#編程中的使用方式。 訪問修飾符 訪問修飾符控制成員…

Python變量age:深入探索其內涵與運用

Python變量age&#xff1a;深入探索其內涵與運用 在Python的世界里&#xff0c;變量age不僅是一個簡單的標識符&#xff0c;它更是一個承載著豐富信息和功能的實體。今天&#xff0c;我們就來深入探索這個看似簡單的age變量&#xff0c;揭示其背后的奧秘和魅力。 四個方面&am…

供應SKYA21001思佳訊芯片現貨

長期供應各進口品牌芯片現貨&#xff1a; SKYA21001 QM11024TR13 QM12113TR13 QM42391 QM45392 QM28005 RF8020TR13 QM77033DTR13 QM56021TR13-5K 885171 QM77043 QM78207 QM77038TR13 SKY58081-11 QPF5752QTR13-5K RF7198TR13-5K SKY58255-11 SKY85720-11 …

Ubuntu中安裝和配置SSH的完全指南

目錄 前言 第1步&#xff1a;安裝SSH服務器 第2步&#xff1a;檢查防火墻設置 第3步&#xff1a;連接到SSH服務器 第4步&#xff1a;配置SSH服務器&#xff08;可選&#xff09; 更改SSH端口 禁用root登錄 第5步&#xff1a;公鑰認證&#xff08;建議&#xff09; 結論…