內存函數詳解,包含部分字符串函數

目錄

?????????一,memcpy內存函數的介紹

二memmove函數的介紹

三,memset的函數使用

四,memcmp的介紹

五,內存函數的模擬實現,以及一個字符串函數strstr的模擬實現

????????5.1memcpy函數的實現

????????5.2memmove的模擬實現

????????5.3memcmp的模擬實現

????????5.4 strstrg函數的模擬實現(暴力實現以及KMP算法實現)


內存操作函數

memcpy的使用以及模擬實現

memmove的使用以及模擬實現

memcmp的使用以及模擬實現

memset的使用

strstr的模擬實現

一,memcpy內存函數的介紹

void* memcpy(void* destination, const void* source, size_t num);
這里我們可以看到,他是有三個參數的,其中有倆個無符號指針,還有一個是無符號的num
這倆個指針,一個指向目標要改變的數據的地址,另一個是源地址,要拷貝到我們目標中
當然這里使用無符號類型的指針,是為了我們能拷貝任何類型的數據,就不僅限于拷貝字符

解釋如下

函數 memcpy source 的位置開始向后復制 num 個字節的數據到 destination 的內存位置。
這個函數在遇到 '\0' 的時候并不會停下來,因為我們給了需要拷貝的字節大小,所以拷貝停止是由我們自己來控制的
如果 source destination 有任何的重疊,復制的結果都是未定義的。
這個意思是所不能在自己的后面拷貝自己,因為可能會導致越界的風險,當然在VS下是可以自己拷貝自己的內容的,但是在不同的編譯器中,可能效果不同,有些編譯器是不允許這樣使用的

這便是在自己后面進行拷貝,然后出現越界的情況,例如在字符串中,他在拷貝的過程中,可以會將'\0'修改,導致字符串沒有結尾標志。

可以看到,我們將arr2中的數據拷貝到了arr1中去,而arr1和arr2中存放的都是int類型的變量,這就是和字符串拷貝的區別,當然我們也可以拷貝其他類型的變量,例如結構體

memmove函數的介紹

void* memmove(void* destination, const void* source, size_t num);

這里我們可以看到,他是有三個參數的,其中有倆個無符號指針,還有一個是無符號的num
這倆個指針,一個指向目標要改變的數據的地址,另一個是源地址,要拷貝到我們目標中
當然這里使用無符號類型的指針,是為了我們能拷貝任何類型的數據,就不僅限于拷貝字符
memcpy 的差別就是 memmove 函數處理的源內存塊和目標內存塊是可以重疊的。
如果源空間和目標空間出現重疊,就得使用 memmove 函數處理。
當然他也能在字符串后面去追加自己的部分
我們可以看到,他是能在他自己的后面追加內容的。

三,memset的函數使用

void *memset( void *dest, int c, size_t count );

memset函數,有三個參數,一個是無符號的指針,一個是你要設置的符號是什么,最后一個參數是無符號的整形,返回類型是無符號的指針類型,指向的是 *dest的首元素地址

memset函數的功能是,在dest里面設置count字節的符號C,并返回dest的地址

我們使用memset就能使我們想要的字節個數的內容變成我們需要的值。

四,memcmp的介紹

int memcmp(const void* ptr1, const void* ptr2, size_t num);

我們可以看到,他有三個參數,前倆個是我們要比較內容的地址,最后一個是我們要比較的個數,返回類型是int類型,如果ptr1 > ptr2 則返回 > 0 的數,如果ptr1 < ptr2 則返回 0? <?的數,如果 ptr1 == ptr2 則返回 0

五,內存函數的模擬實現,以及一個字符串函數strstr的模擬實現

5.1memcpy函數的實現

void* my_memcpy(void* dest, const void* cur, size_t num)
{//保留dest的地址void* ret = dest;while (num){*(char*)dest = *(char*)cur;dest = (char*)dest + 1;cur = (char*)cur + 1;num--;}//返回dest的地址return ret;
}
int main()
{char str1[] = "hello world .............";char str2[] = ".............";//將str2的前5個字節的內容拷貝到str1中my_memcpy(str1,str2,5sizeof(str2[0]));printf(str1);return 0;
}

5.2memmove的模擬實現

圖,一

圖,二

當然在拷貝自己時會出現上述倆種情況,如果我們一直只選一直拷貝方式,例如,從前向后拷貝因為cur和dest都是來自同一部分,那么會出現什么情況呢,我們在dest?> cur時,在拷貝的時候就已經將存儲在a ,b ,c 之后的數據d,e,f修改為 a,b,c 因為dest和cur指向的是同一塊內容,那么cur里面的數據 d,e,f也被修改了,那么就達不到我們需要的拷貝效果。這時我們就要進行一定的判斷,當dest > cur時,我們從后向前拷貝,當 cur > dest時我們從前向后拷貝。當然,如果不是相同地址塊的內容,如何拷貝不會影響他們的結果,這個判斷只對拷貝同一塊地址內容進行區分。

代碼如下

void* my_memmove(void* dest, const void* cur, size_t num)
{void* ret = dest;//為了防止自己拷貝自己導致的內容覆蓋//如果dest < curif (dest < cur){while (num){*(char*)dest = *(char*)cur;dest = (char*)dest + 1;cur = (char*)cur + 1;num--;}}else{dest = (char*)dest + num;cur = (char*)cur + num;while (num){*(char*)dest = *(char*)cur;dest = (char*)dest - 1;cur = (char*)cur - 1;num--;}}
}
int main()
{char str1[] = "hello world .............";char str2[] = ".............";my_memmove(str1,str1+5,6);printf(str1);return 0;
}

5.3memcmp的模擬實現

int my_memcmp(void* pstr1, char* pstr2, size_t num)
{while (num){//如果某個字節的值不相等,則中斷循環if (*(char*)pstr1 != *(char*)pstr2){break;}//相等這繼續向下走pstr1 = (char*)pstr1 + 1;pstr2 = (char*)pstr2 + 1;num--;}//直接返回pstr1 和 pstr2對應的差值即可return (*(char*)pstr1 - *(char*)pstr2);
}int main()
{char str1[] = "hello world .............";char str2[] = "hello word";int ret = my_memcmp(str1,str2,5);printf("ret = %d",ret);return 0;
}

可以看到,直接返回了不相等部分的差值,大于0 說明前num個字節 str1大于str2

可以看到,直接返回了相等部分的差值,等于0 說明前num個字節 str1等于str2

5.4 strstrg函數的模擬實現(暴力實現以及KMP算法實現)

暴力實現:

char* my_strstr(const char* ps1, const char* ps2)
{char* p1 = ps1;char* p2 = ps2;char* p3 = ps1;while (*p3 != '\0'){//每次循環一次,將p3指向的下一個內容給p1,p2回到子集的起點p1 = p3;p2 = ps2;while (*p2 != '\0'){if (*p2 == *p1){//相等就p1和p2向后走,一直比較到 p2指向'\0'為止p2++;p1++;}else{//如果在p2到'\0'之前不相等,這直接跳出循環break;}}//如果*p2 == '\0' 那么說明以及在ps1中的子集里找到了與ps2相等的部分,那么就可以返回p3所指向的內容,if (*p2 == '\0'){return p3;}//如果不相等,p3向后走一位p3++;}//如果一直到最后都沒有找到那么將返回空return NULL;
}int main()
{char str1[] = "abcdeffghjkln";char str2[] = "ffg";char* ret = my_strstr(str1,str2);printf(ret);return 0;
}

KMP算法:
next數組:
由上圖next數組我們可以知道
如果我們只知道i之前的next數組下標,那么他之后的應該按照 next[i+1]?= k+1,去計算
而圖中我們要求的是 i 位置的next數據,那么如果字符串第 i - 1 位置的字符與 k 位置的字符相等,那么next[i] 位置的值就等于 next [i] = next[i-1] + 1,當然,如果 i 的前一個位置的字符串不等于 k 位置的字符串,那么next數組回退到 k 指向的位置,如果一直不相等,直到 k 會退到 -1位置處,在出現進行比較
void GetNext(char* ps2,int* next,int len2)
{next[0] = -1;next[1] = 0;int i = 2;int k = 0;//一直插入數據到next的最后一個位置while(i < len2){// 如果 k 等于 -1 那么說明已經回退到原點,或者 第 i 的前一項與k位置的字符相等 if (k == -1 ||ps2[i - 1] == ps2[k]){next[i] = k + 1;i++;k++;}//不相等這 k 回退到next[k]對應的值else{k = next[k];}}
}
char* KMP( char* ps1,  char* ps2,int pos)
{int len1 = strlen(ps1);int len2 = strlen(ps2);//我們要找的子串,和需要的主串不能為空if (len1 == 0 || len2 == 0){return NULL;}//我們希望開始比較的位置不能大于主串的長度,也不能小于零if (pos<0 || pos > len1){return NULL;}//數組這里我們選擇動態開辟在堆上建next數組int* next = (int*)malloc(sizeof(int) * len2);//如果malloc失敗這直接返回if (next == NULL){return;}//函數得到我們的next數組GetNext(ps2, next,len2);int i = pos;//遍歷主串int j = 0;//遍歷子串//在主串中尋找子串while (i < len1 && j < len2){//如果 j = -1;這說明需要比較下一個,相等這比較下一個if (j == -1||ps1[i] == ps2[j]){i++;j++;}//不相等將 j 更新為next[k] 對應的值在重新去比較else{j = next[j];}}//釋放我們在堆上申請的空間free(next);// 如果j >= len2的長度則說明已經找到主串中的子串,返回對應位置的地址if (j >= len2){return &ps1[i - j];}//沒有找到返回空return NULL;
}

KMP整體代碼如下

#include<stdio.h>
#include<stdlib.h>
void GetNext(char* ps2,int* next,int len2)
{next[0] = -1;next[1] = 0;int i = 2;int k = 0;while(i < len2){if (k == -1 ||ps2[i - 1] == ps2[k]){next[i] = k + 1;i++;k++;}else{k = next[k];}}
}
char* KMP( char* ps1,  char* ps2,int pos)
{int len1 = strlen(ps1);int len2 = strlen(ps2);if (len1 == 0 || len2 == 0){return NULL;}if (pos<0 || pos > len1){return NULL;}int* next = (int*)malloc(sizeof(int) * len2);if (next == NULL){return;}GetNext(ps2, next,len2);int i = pos;//遍歷主串int j = 0;//遍歷子串while (i < len1 && j < len2){if (j == -1||ps1[i] == ps2[j]){i++;j++;}else{j = next[j];}}if (j >= len2){free(next);return &ps1[i - j];}free(next);return NULL;
}int main()
{char str1[] = "abcdeffghjkln";char str2[] = "ffghjk";char* ret = KMP(str1,str2,0);printf(ret);return 0;
}

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

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

相關文章

Shell環境變量深入:自定義系統環境變量

Shell環境變量深入&#xff1a;自定義系統環境變量 目標 能夠自定義系統級環境變量 全局配置文件/etc/profile應用場景 當前用戶進入Shell環境初始化的時候會加載全局配置文件/etc/profile里面的環境變量, 供給所有Shell程序使用 以后只要是所有Shell程序或命令使用的變量…

H.機房【藍橋杯】/數組鏈式前向星建圖+堆優化版dijkstra

機房 數組鏈式前向星建圖堆優化版dijkstra #include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; typedef pair<int,int> pii; //無向圖開兩倍 int e[200005],ne[200005],v[200005],h[200005],du[1000…

STL---unordered set和unordered multiset【無序集合】

1.1 定義及初始化&#x1f357; 下面列出常用的初始化方式 #include <unordered_set> #include <iostream> using namespace std; //輸出s中的所有元素 template<typename T> void Show(const T& s) {for (auto& x : s) …

Python的pip配置、程序運行、生成exe文件

一、安裝Python 通過官網下載對應的版本&#xff0c;安裝即可。 下載地址&#xff1a;Download Python | Python.org Python標準庫查看&#xff08;Python自帶庫&#xff09; Python 標準庫文檔 安裝Python的時候&#xff0c;如果選第二個自定義安裝要記得勾選安裝pip 二、…

2024/05/25學習記錄

1、面經復習&#xff1a;前端廣度 2、代碼隨想錄刷題&#xff1a;動態規劃 3、rosebush 完成input組件基礎

閑置商標轉讓出現這些狀態時注意!

近日以前做轉讓的一個朋友的商標轉讓證明下來&#xff0c;正好是2個半月&#xff0c;普推知產老楊發現這個時間也太快&#xff0c;以前差不多四個月左右&#xff0c;有些朋友需要購買閑置商標&#xff0c;3個月內所有權就變成自己的。 在購買閑置商標時要注意有一些細節&#x…

Python限制輸入的數范圍

在Python中&#xff0c;我們可以使用多種方法來限制用戶輸入的數值范圍。 1.使用while循環和try-except語句的方法 以下是一個使用while循環和try-except語句的示例&#xff0c;該示例將要求用戶輸入一個在指定范圍內的整數。 假設我們要限制用戶輸入的數在1到100之間&#…

MySQL的索引, 到底怎么創建?

目錄 前言 MySQL的數據結構 索引是一把雙刃劍 索引創建原則 如何給一個列挑選索引? 索引列的基數, 要盡量小 索引列的類型盡量小 索引長字符串的前綴 不要對索引列進行計算操作或者函數計算. 不要老想著查詢, 想想插入該怎么辦? 避免索引冗余和重復 前言 今天在…

TOTP 算法實現:雙因素認證的基石(C/C++代碼實現)

雙因素認證&#xff08;Two-Factor Authentication, 2FA&#xff09;扮演著至關重要的角色。它像是一道額外的防線&#xff0c;確保即便密碼被竊取&#xff0c;不法分子也難以輕易突破。在眾多雙因素認證技術中&#xff0c;基于時間的一次性密碼&#xff08;Time-Based One-Tim…

ubuntu/部分docker容器無法訪問https站點

ubuntu/部分docker容器無法訪問https站點 解決方案 解決方案 默認的系統內可能沒有安裝根證書&#xff0c;需要安裝一下 apt install ca-certificates如果官方源比較慢&#xff0c;可以換為國內源&#xff0c;但是不要使用https

【fastapi+mongodb】使用motor操作mongodb

上一篇文章&#xff0c;我們在電腦上安裝了mongodb數據庫。這篇文章&#xff0c;我們在fastapi后端使用motor操作mongodb 如果你還沒看過上一篇文章&#xff0c;鏈接在這里&#xff1a;【MongoDB】安裝與使用 安裝 motor motor 是一個用于操作 mongodb 數據庫的 python 庫&a…

計算機網絡 1

兩臺主機想通信&#xff0c;其實本質就是兩個文件的資源交換&#xff0c;但是長距離的通信&#xff0c;面臨的是很多的問題。這個時候需要通過一些方式來保證可靠性 什么是協議 這樣一個例子&#xff0c;我是住在農村&#xff0c;我讀高中了我需要去縣里面讀書。這個時候呢&…

VL15 優先編碼器Ⅰ

兩種思路 module encoder_83(input [7:0] I ,input EI ,output wire [2:0] Y ,output wire GS ,output wire EO );reg [4:0] temp1 ; always (*) begincasex({EI,I}) 9b0_xxxx_xxxx:begin temp1 5b000_0_0;…

冒泡排序和遞歸排序

目錄 一.冒泡排序 1.1概念&#xff1a; 1.2原理&#xff1a; 1.3簡單示例講解&#xff1a; 二.遞歸排序 1.1概念&#xff1a; 1.2原理&#xff1a; 1.3簡單示例講解&#xff1a; 一.冒泡排序 1.1概念&#xff1a; 冒泡排序是一種最基礎的交換排序。 通過反復交換相鄰…

Jupyter Lab 軟件安裝與使用

軟件簡介 Jupyter Lab 軟件是一個基于web 的交互式開發環境&#xff0c;集成了代碼編輯器、終端、文件管理器等功能&#xff0c;使得開發者可以在一個界面中完成各種任務。JupyterLab是Jupyter Notebook的全面升級&#xff0c;是一個集文本編輯器、終端以及各種個性化組件于一…

Java進階學習筆記29——Math、System、Runtime

Math&#xff1a; 代表的是數學&#xff0c;是一個工具類&#xff0c;里面提供的都是對數據進行操作的一些靜態方法。 示例代碼&#xff1a; package cn.ensourced1_math;public class MathTest {public static void main(String[] args) {// 目標&#xff1a;了解Math類提供…

那智不二越機器人維修案例分享

那智不二越工業機器人在工業范圍內廣泛應用于各種生產領域。其示教器作為人機交互的重要設備&#xff0c;常常需要定期維護和Nachi不二越機械手示教盒修理。 【Nachi不二越機器人示教器維修步驟】 1. 關閉電源 在進行任何那智不二越機器人維修操作之前&#xff0c;務必確保機器…

<商務世界>《75 微課堂<茶葉(1)-質量分級>》

1 中國茶葉分級 中國的10級標準是按照茶葉的外觀、香氣、滋味、湯色、葉底五個方面進行評分&#xff0c;分別用10分制進行評分&#xff0c;總分為50分&#xff0c;得分越高&#xff0c;茶葉的品質就越高。具體的分數和等級如下表所示&#xff1a; 2 每級的特點 茶葉的質量等級…

OceanBase SQL 診斷和調優實踐——【DBA從入門到實踐】第七期

數據庫作為絕大多數應用系統儲存數據的核心系統&#xff0c;在用戶系統需要訪問數據時&#xff0c;有著至關重要的作用。在這些交互中&#xff0c;SQL 語言是應用與數據庫系統之間“溝通”的橋梁&#xff0c;它負責將應用的指令傳達給數據庫。因此&#xff0c;SQL 的性能好壞直…