C語言內存函數超詳細講解

個人主頁:C++忠實粉絲
歡迎 點贊👍 收藏? 留言? 加關注💓本文由 C++忠實粉絲?原創

C語言內存函數超詳細講解

收錄于專欄【C語言學習
本專欄旨在分享學習C語言學習的一點學習筆記,歡迎大家在評論區交流討論💌

目錄

1. memcpy使?和模擬實現

2. memmove使?和模擬實現

3. memset函數的使?

4. memcmp函數的使??


1. memcpy使?和模擬實現

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

?參考:memcpy - C++ Reference (cplusplus.com)

? 函數memcpy從source的位置開始向后復制num個字節的數據到destination指向的內存位置。

? 這個函數在遇到 '\0' 的時候并不會停下來。

? 如果source和destination有任何的重疊,復制的結果都是未定義的。

對于重疊的內存,交給memmove來處理。?

示例:

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;}

?輸出結果:

注意:

函數memcpy從source的位置開始向后復制num個字節的數據到destination指向的內存位置。單位是字節,所以20個字節就是5個整形

memcpy函數的模擬實現:

void* my_memcpy(void* dest, void* src, size_t num)
{void* ret = dest;int i = 0;assert(dest && src);while (num--){*(char*)dest = *(char*)src;((char*)src)++;((char*)dest)++;}return ret;
}

?因為memcpy拷貝的數據類型是不一樣的,這里我們使用void*去接收,使用char*去強轉類型完成一個一個字節的拷貝

這是一個簡單的 my_memcpy 函數,它的功能是將源內存塊 src 的內容復制到目標內存塊 dest。這個函數接受三個參數:目標內存塊的指針 dest,源內存塊的指針 src,以及要復制的字節數 num

函數的主要步驟如下:

  1. 函數首先保存目標內存塊的初始地址 destret,以便在復制完成后返回。

  2. 使用 assert 函數檢查 destsrc 是否為 NULL。如果任一指針為 NULL,則 assert 會終止程序。

  3. 然后,函數進入一個循環,該循環將持續 num 次。在每次迭代中,它都會做以下操作:

    • 使用 *(char*)dest = *(char*)src;src 指向的當前字節復制到 dest 指向的當前字節。

    • 使用 ((char*)src)++;((char*)dest)++;srcdest 的地址分別增加 1,以便在下一次迭代中復制下一個字節。

  4. 最后,函數返回 ret,即目標內存塊的初始地址。

這個函數的實現假設 srcdest 指向的內存區域不會重疊。如果它們重疊,那么這個函數可能會導致未定義的行為。在這種情況下,應該使用 memmove 函數,而不是 memcpy。此外,這個函數也沒有處理可能的內存對齊問題。在某些硬件和操作系統上,如果 srcdest 的地址不是某個特定值(如 4 或 8)的倍數,那么直接復制它們可能會導致性能下降或者錯誤。在這種情況下,應該使用更復雜的算法來處理對齊問題。但是,對于簡單的用途,這個 my_memcpy 函數應該是足夠的。

測試代碼:

int main()
{//strcpy - 字符串的拷貝int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//             0 1 2 3 4int arr2[20] = { 0 };//0 1 2 3 4//memcpy - 針對內存塊進行拷貝my_memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 20; i++){printf("%d ", arr2[i]);}return 0;
}

?這里我們注意一下,strcpy是對字符串的拷貝,而我們的memcpy是對內存塊的拷貝?

測試輸出:

?

2. memmove使?和模擬實現

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

?參考:memmove - C++ 參考 (cplusplus.com)

?和memcpy的差別就是memmove函數處理的源內存塊和?標內存塊是可以重疊的。

? 如果源空間和?標空間出現重疊,就得使?memmove函數處理。

?示例:

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

輸出結果:

?

memmove的模擬實現:

//memmove函數拷貝完成后,會返回目標空間的起始地址void* my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;if (dest < src){//前->后while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{//后->前while (num--){*((char*)dest+num) = *((char*)src + num);}}return ret;
}

注意:這里分為前后兩種情況

分析:

這段代碼是?my_memmove?函數的實現,它用于在內存中移動數據塊,并且可以正確處理源和目標內存區域重疊的情況。函數接收三個參數:目標內存地址?dest,源內存地址?src,以及要移動的字節數?num

函數的工作原理如下:

  1. 參數檢查:使用?assert?確保?dest?和?src?都不是空指針。
  2. 保存返回地址:將?dest?的初始地址保存到?ret,以便函數結束時返回。
  3. 前向拷貝:如果?dest?地址小于?src?地址,說明沒有重疊或者?dest?在?src?的前面,可以從前向后拷貝。
    • 在循環中,逐字節拷貝?src?到?dest,然后將兩者的地址都向后移動一位。
  4. 后向拷貝:如果?dest?地址大于或等于?src?地址,說明?dest?在?src?的后面,可能會有重疊,需要從后向前拷貝。
    • 在循環中,從最后一個字節開始拷貝,直到拷貝完所有字節。

這樣,即使?src?和?dest?有重疊,數據也不會被錯誤地覆蓋。函數最后返回?ret,即目標內存塊的起始地址。這個函數是?memcpy?的一個安全替代品,特別是在處理可能重疊的內存區域時。

舉例:

例如,假設我們有一個數組?123456789,并且我們想要將從?3?開始的部分復制到從?1?開始的位置。如果我們從前向后拷貝,那么在拷貝?3?到?1?的位置后,原來?3?的位置就變成了?1,這樣當我們想要拷貝?5?到?3?的位置時,就會出現問題,因為此時?3?的位置已經被改變了。

為了解決這個問題,memmove?會檢查?dest?和?src?的關系。如果?dest?在?src?的后面,那么?memmove?就會選擇從后向前拷貝。這樣,即使?dest?和?src?有重疊,也不會出現數據被提前覆蓋的問題。在上述例子中,memmove?會先拷貝最后一個元素?9,然后是?87,依此類推,直到拷貝到?3。這樣,即使?dest?和?src?有重疊,也能保證數據的正確拷貝。

所以,memmove?函數在處理可能有重疊的內存區域時,比?memcpy?函數更安全。但是,如果確定?dest?和?src?不會重疊,那么?memcpy?的效率通常會更高。因為?memcpy?不需要檢查?dest?和?src?的關系,也不需要決定是從前向后拷貝還是從后向前拷貝,所以它的實現可以更簡單,運行速度也可以更快。但是,如果不能確定?dest?和?src?是否重疊,那么最好使用?memmove這就是為什么標準庫提供了兩個不同的函數來處理內存拷貝的原因。

測試數據:

int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr, arr+2, 5 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

?輸出數據:

3. memset函數的使?

 void * memset ( void * ptr, int value, size_t num );

?參考:?memset - C++ Reference (cplusplus.com)

memset是?來設置內存的,將內存中的值以字節為單位設置成想要的內容。

示例:

#include <stdio.h>
#include <string.h>
int main()
{char str[] = "hello world";memset(str, 'x', 6);printf(str);return 0;
}

?調試分析:

4. memcmp函數的使??

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

? ?較從ptr1和ptr2指針指向的位置開始,向后的num個字節

? 返回值如下:

示例:

#include <stdio.h>
#include <string.h>int main()
{char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0)printf("'%s' is greater than '%s'.\n", buffer1, buffer2);else if (n < 0)printf("'%s' is less than '%s'.\n", buffer1, buffer2);elseprintf("'%s' is the same as '%s'.\n", buffer1, buffer2);return 0;
}

?輸出結果:

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

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

相關文章

C++面向對象程序設計-北京大學-郭煒【課程筆記(十一)】

C面向對象程序設計-北京大學-郭煒【課程筆記&#xff08;十一&#xff09;】 1、string&#xff08;重要知識點&#xff09;1.2、string的賦值和鏈接1.3、比較string1.4、子串1.5、交換string1.6、尋找string中的字符1.7、刪除string中的字符1.8、替換string中的字符1.9、在str…

leetcode119-Pascal‘s Triangle II

題目 給定一個非負索引 rowIndex&#xff0c;返回「楊輝三角」的第 rowIndex 行。 在「楊輝三角」中&#xff0c;每個數是它左上方和右上方的數的和。 示例 1: 輸入: rowIndex 3 輸出: [1,3,3,1] 分析 楊輝三角每位數字就是上一行同一列&#xff0b;上一行前一列的和&#…

結構體;結構成員訪問操作符

結構體&#xff1a; 雖然c語言已經提供了內置類型&#xff0c;比如&#xff1a;char、short、int、long等&#xff0c;但還是不夠用&#xff0c;就好比我描述一個人&#xff0c;我需要描述他的身高&#xff0c;體重&#xff0c;年齡&#xff0c;名字等信息&#xff0c…

微軟密謀超級AI大模型!LangChain帶你輕松玩轉大模型開發

此前&#xff0c;據相關媒體報道&#xff0c;微軟正在研發一款名為MAI-1的最新AI大模型&#xff0c;其參數規模或將達5000億以上&#xff0c;遠超此前微軟推出的相關開源模型&#xff0c;其性能或能與谷歌的Gemini 1.5、Anthropic的Claude 3和OpenAI的GPT-4等知名大模型相匹敵。…

Linux文本處理三劍客(詳解)

一、文本三劍客是什么&#xff1f; 1. 對于接觸過Linux操作系統的人來說&#xff0c;應該都聽過說Linux中的文本三劍客吧&#xff0c;即awk、grep、sed&#xff0c;也是必須要掌握的Linux命令之一&#xff0c;三者都是用來處理文本的&#xff0c;但側重點各不相同&#xff0c;a…

Sam Altman微軟Build 2024最新演講:AI可能是下一個移動互聯網

大家好&#xff0c;我是木易&#xff0c;一個持續關注AI領域的互聯網技術產品經理&#xff0c;國內Top2本科&#xff0c;美國Top10 CS研究生&#xff0c;MBA。我堅信AI是普通人變強的“外掛”&#xff0c;所以創建了“AI信息Gap”這個公眾號&#xff0c;專注于分享AI全維度知識…

【C++11】lambda匿名函數和包裝器

目錄 一&#xff0c;lambda匿名函數 1-1&#xff0c;lambda的引入 1-2&#xff0c;lambda表達式書寫格式 1-3&#xff0c;lambda函數的名稱 1-4&#xff0c;lambda捕獲列表的使用 1-5&#xff0c;函數對象與lambda表達式 二&#xff0c;包裝器 2-1&#xff0c;function…

信息系統管理工程師知識點

信息系統管理工程師知識點 損壞包括自然災害、物理損壞&#xff08;磁盤壞、設備使用壽命&#xff0c;外力破損&#xff09;、設備故障&#xff08;停電、電磁干擾&#xff09;。 泄漏包括電磁輻射&#xff08;偵聽微機損傷過程&#xff09;、乘機而入&#xff08;合法用戶進…

一天了解一個機器學習模型——機器學習基礎知識

人工智能的兩大任務——預測和決策 預測包括對輸入目標的模式識別、標簽分類、回歸、預測未來數據、聚類 決策需要機器產生行動&#xff0c;改變狀態&#xff0c;如下圍棋、自動駕駛 支持人工智能的四大類技術 搜索——結合算法探索分支的好壞&#xff0c;從而做出決策&…

如何使用maven運行SpringBoot程序?

目錄 一、什么是maven 二、什么是SpringBoot 三、如何使用maven運行SpringBoot程序&#xff1f; 一、什么是maven Maven&#xff1a;簡化Java項目構建的自動化工具 在軟件開發的世界里&#xff0c;Maven以其強大的項目管理和構建自動化功能&#xff0c;為Java開發者提供了…

內存泄漏及其解決方法

1. 系統崩潰前的現象 垃圾回收時間延長&#xff1a;從原本的約10ms增長至50ms&#xff0c;Full GC時間也由0.5s增加至4-5s。Full GC頻率增加&#xff1a;最短間隔可縮短至1分鐘內發生一次。年老代內存持續增長&#xff1a;即使經過Full GC&#xff0c;年老代內存未見明顯釋放。…

容器化:ES和Kibana

1 緣起 最近在學習使用ES&#xff0c; 為了找一個功能強大的可視化工具&#xff0c;之前使用了ES-Head&#xff0c;可以滿足學習需求。 閑暇時間又折騰了另一個工具Kibana&#xff0c; 分享如下。 Kibana優點&#xff1a; 用戶友好性&#xff1a;Kibana提供直觀易用的用戶界面…

Strategy設計模式

Strategy設計模式舉例。 看圖&#xff1a; 代碼實現&#xff1a; #include <iostream>using namespace std;class FlyBehavior { public:virtual void fly() 0; };class QuackBehavior { public:virtual void quack() 0; };class FlyWithWings :public FlyBehavior …

數據庫(vb.net+OleDB+Access)簡易學生信息管理系統

在我們日常生活當中&#xff0c;數據庫一詞往往離不開我們的編程界&#xff0c;在學校、倉庫等方面起著存儲數據及數據關系作用的文件。相較于Excel&#xff0c;Access可以存儲無限多的記錄&#xff0c;內容也十分豐富&#xff0c;例如文本、數字、日期、T&F等。而且不需要…

k8s命令式對象管理和配置

kubectl補全: # dnf install -y bash-completion # echo "source <(kubectl completion bash)" >> ~/.bashrc # kubectl completion bash > /etc/bash_completion.d/kubectl 命令式對象管理 kubectl命令 # 查看所有pod kubectl get pod # 查看某個po…

gbk轉utf-8

你們曾經有沒有因為文件的編碼問題而苦惱過&#xff1f;在Windows下開發時&#xff0c;尤其是項目初期&#xff0c;如果沒有特別注意文件的字符編碼問題&#xff0c;等到項目變大后&#xff0c;用Git對比代碼時&#xff0c;很可能會發現一些亂碼。這時才意識到字符編碼的重要性…

LLM——探索大語言模型在心理學方面的應用研究

1. 概述 心理學經歷了多次理論變革&#xff0c;目前人工智能&#xff08;AI&#xff09;和機器學習&#xff0c;特別是大型語言模型&#xff08;LLMs&#xff09;的使用&#xff0c;預示著新研究方向的開啟。本文詳細探討了像ChatGPT這樣的LLMs如何轉變心理學研究。它討論了LL…

docker- 鏡像 導出導入

文章目錄 前言docker- 鏡像 導出導入1. 導出2. 刪除鏡像3. 導入鏡像 前言 如果您覺得有用的話&#xff0c;記得給博主點個贊&#xff0c;評論&#xff0c;收藏一鍵三連啊&#xff0c;寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運氣都不會太差&#xff0c;實在白嫖的話&…

Nginx 從入門到精通-Nginx-Web服務器的瑞士軍刀

在當今互聯網高速發展的時代&#xff0c;作為Web服務器的Nginx可謂是一把"瑞士軍刀"&#xff0c;其強大的功能和出色的性能備受青睞。然而&#xff0c;僅僅停留在"會用"的層面是遠遠不夠的&#xff0c;要充分發揮Nginx的潛力&#xff0c;我們還需要深入了解…

SpringBoot Validation自定義注解之校驗指定最小整數

1&#xff0c;引入核心關鍵依賴 <!--數據校驗--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency> 2&#xff0c;自定義注解 package com.taia.ym…