最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言函數(shù)之memcpy函數(shù)用法實例

 更新時間:2022年08月11日 11:30:18   作者:Nerazzur  
memcpy函數(shù)用于把資源內(nèi)存(src所指向的內(nèi)存區(qū)域)拷貝到目標內(nèi)存(dest所指向的內(nèi)存區(qū)域),下面這篇文章主要給大家介紹了關(guān)于C語言函數(shù)之memcpy函數(shù)用法的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

前言

昨天自己動手實現(xiàn)memcpy這個函數(shù),用一個例程試了一下,結(jié)果正確,滿心歡心,可是有些地方想不明白,于是百度了一下,結(jié)果自己寫的函數(shù)簡直無法直視。

覺得還是寫個總結(jié),以示教訓。

先貼上我自己的函數(shù):

char *mymemcpy(char *dest, const char * src, int n)
{
        char *pdest;
        char *psrc;
        pdest = dest;
        psrc = src;
 
        for(n; n>0; n--)
        {
                *pdest = *psrc;
                pdest++;
                psrc++;
        }
}

我這個程序只能是在非常理想的條件下才能完成復制任務(wù),一旦參數(shù)有誤,那么就會運行出錯;另外沒有返回值,而是直接將dest指針作為了返回型參數(shù)。

另一點需要注意:在函數(shù)體中我另外聲明了兩個指針,分別指向dest和src,我是這樣想的:由于循環(huán)中要移動指針,為了不影響主程序中實參指針的位置,所以我認為需要重新定義兩個指針。后來我發(fā)現(xiàn),我這樣想是錯誤的,指針變量實質(zhì)上也是變量,指針作為形參,那么這個指針也是實實在在存在的,那么在函數(shù)中改變這個形參指針的位置并不會影響主程序中實參指針的位置。所以在這個函數(shù)中,沒必要重新聲明兩個指針,最好是在返回值中返回一個指向dest的指針就夠了。

我會犯上述這個錯誤,應(yīng)該是受了“地址傳參”和“值傳參”的影響。由于地址傳參太過于強調(diào)函數(shù)可以改變主程序中的數(shù)據(jù)內(nèi)容,以至于讓我把形參指針和實參指針等同起來了。實質(zhì)上形參指針變量位置的改變并不會影響實參指針的位置。

重要的內(nèi)容寫前面,

自己總結(jié)該函數(shù)的幾個要點:

1、參數(shù)判斷:對參數(shù)的合法性進行判斷

2、聲明中間變量:由于要返回目的指針,所以需要保留目的首地址;最好是不要破壞形參,設(shè)置臨時變量替換

3、void *類型:要注意dest和src的類型可能不同,進而造成dest++ src++不匹配的問題,先強制類型轉(zhuǎn)換

4、void 類型做右值:void類型變量或是返回值為void類型的函數(shù),一旦做右值編譯出錯

5、指針形參:即上面提到的,指針變量本質(zhì)仍是指針,形參指針位置的改變不會影響實參指針的位置

下面是參考網(wǎng)友的一些總結(jié):

memcpy實現(xiàn)內(nèi)存拷貝,根據(jù)這個問題,我們可以提取出下面幾點:

1.可以拷貝任何數(shù)據(jù),數(shù)據(jù)類型不能受限

2.源數(shù)據(jù)不能被改變

通過上面兩點可以確定函數(shù)原型為void *memcpy(void *dest, const void *src),現(xiàn)在分析一下這些足夠了嗎?這個函數(shù)拷貝什么時候結(jié)束,當時我就用了這個函數(shù)原型,由于是拷貝的任意數(shù)據(jù),所以不能指定一個明確的結(jié)束標志,既然這樣那么只有明確的指定拷貝的大小才可以.所以函數(shù)原型變成這樣void *memcpy(void *dest, void *src, size_t count);好吧,函數(shù)原型既然已經(jīng)確認了,剩下的應(yīng)該就是寫函數(shù)了,先等等,先別急著寫函數(shù),實際上對于C語言的開發(fā)者來說,重要的不是函數(shù)功能的實現(xiàn),重要的是函數(shù)出錯時的處理,如果你用的是Java或者C#大不了拋個異常出來,軟件崩潰一下,不會對其他造成任何影響;C這東西弄不好會把整個系統(tǒng)弄癱瘓,所謂”兵馬未動,糧草先行”,我么還是先考慮考慮出錯的問題吧!我們根據(jù)函數(shù)原型來分析,

void *memcpy(void *dest, const void *src, size_t count);

1.空指針的問題,如果dest、src兩者或者兩者之一為NULL,那么自然能沒得完了;

2.拷貝大小count為小于等于0的值,自然也是不正確的;

3.目標有沒有足夠的大小容納源數(shù)據(jù),這個我們在函數(shù)內(nèi)部似乎也無法進行保證,但是我們自己也要想到

4.內(nèi)存地址有沒有重疊,這個我們暫時不考慮了。

有了上面的提示寫起來自然比較簡單了

#include <stdio.h>
void *memcpy(void *dest, const void *src, size_t count)
{
<span style="white-space:pre">	</span>if (NULL == dest || NULL == src || count <= 0)
<span style="white-space:pre">		</span>return NULL;
<span style="white-space:pre">	</span>while (count--)
<span style="white-space:pre">		</span>*dest++ = *src++;
<span style="white-space:pre">	</span>return dest;
}

上面這段代碼在Linux中使用gcc編譯是沒錯的,但是會有警告,所以改成這樣:

(注意,上述代碼我在測試時,不僅有警告還有一個錯誤:error: invalid use of void expression,這是因為void型的變量或者是函數(shù)返回值被使用了。使用下面這段代碼是可以通過編譯的:)

#include <stdio.h>
void *memcpy(void *dest, const void *src, size_t count)
{
	if (NULL == dest || NULL == src || count <= 0)
		return NULL;
	while (count--)
		*(char *)dest++ = *(char *)src++;
	return dest;
}

OK,也就這樣了,要是面試官再問起內(nèi)存重疊的問題,你再和他侃侃.我的面試算是泡湯了.

總結(jié):不要著急慢慢來,根據(jù)需求推出原型,根據(jù)原型推斷問題,這算是個教訓吧!!!

補充:

在這里非常感謝博客園的求道于盲  這位好心的網(wǎng)友指出了我程序中的兩個錯誤,再次感謝.

1.返回了一個++過的指針

2.size_t是無符號類型的,size_t的定義為:typedef unsigned int size_t;

所以count<=0,只會判斷==0的情況,如果傳入-1,會產(chǎn)生一個很大的無符號整型.

希望別人注意,改過的程序如下:

void *memcpy(void *dest, const void *src, int count)
{
void *ptr = dest;
if (NULL == dest || NULL == src || count <= 0)
return NULL;
 
while (count--)
*(char *)dest++ = *(char *)src++;
 
return ptr;
}

本文通過匯總一些網(wǎng)上搜集到的資料,總結(jié)c語言中的memcpy實現(xiàn)

背景

想必大多數(shù)人在面試時被要求寫 memcpy的實現(xiàn),很不幸,我也吃過這個虧(這種題要是寫的一塌糊涂后面完全沒戲),所以還是得提前準備一下,不然就只能呵呵了。先來看看一段錯誤的示范: 找茬:)

void * memcpy(void *dest, const void *src, unsigned int count);  
{  
    if ((src == NULL) || (dest == NULL))  
        return;  
      
    while (count--)  
        *dest++ = *src++;  
          
    return dest;  
}  

dest都指到哪里去了?怎么著也得備份一下dest的值,好讓函數(shù)返回的指針是從頭開始的

考慮一下指針類型,如果dest和src的指針類型不一樣,不能直接++賦值. 例如: int* p和 char*q, p++指針的值是4個4個加(0,4,8),q++是1個1個加(0,1,2,3,4)

第二版 - 定義兩個臨時變量,不要直接++ dest和src,并且指明指針類型char *

void *memcpy(void *dest, const void *src, size_t count)  
{  
 char *tmp = dest;  
 const char *s = src;  
   
 while (count--)  
  *tmp++ = *s++ ;  
    
 return dest;  
}  

能否改進? src和dest都強制轉(zhuǎn)換成char*類型的指針,那么copy一定是一個字節(jié)一個字節(jié)的完成?那么第三版來了

void * memcpy(void *dst,const void *src,size_t num)  
{  
    int nchunks = num/sizeof(dst);   /*按CPU位寬拷貝*/  
    int slice =   num%sizeof(dst);   /*剩余的按字節(jié)拷貝*/  
      
    unsigned long * s = (unsigned long *)src;  
    unsigned long * d = (unsigned long *)dst;  
      
    while(nchunks--)  
        *d++ = *s++;  
          
    while (slice--)  
        *((char *)d++) =*((char *)s++);  
          
    return dst;  
}  

看著沒什么問題了,可是如果dst和src地址不對齊,copy效率豈不降低? 是否需要先處理一下地址不對齊的情況?

再來看看dest和src地址有重疊的情況

內(nèi)存重疊問題是指目的地址的內(nèi)存空間的首地址,包含在源內(nèi)存空間中,這兩段內(nèi)存空間有了交集,因而在使用memcpy進行內(nèi)存復制操作時,這段重疊的內(nèi)存空間會被破壞.這種情況在應(yīng)用程序級代碼中一般不會出現(xiàn)的,而在驅(qū)動或內(nèi)核級代碼中要十分小心,盡量使用memmove函數(shù).

memcpy對內(nèi)存空間有要求的,dest和src所指向的內(nèi)存空間不能重疊,否則復制的數(shù)據(jù)是錯誤的.下面具體講解一下這個錯誤是如何產(chǎn)生的.

如果內(nèi)存空間布局入下圖所示:

src所指向的內(nèi)存空間后面部分數(shù)據(jù)被新拷貝的數(shù)據(jù)給覆蓋了(也就是dest<=src+size).所以拷貝到最后,原來的數(shù)據(jù)肯定不是原來的數(shù)據(jù),拷貝的數(shù)據(jù)也不是想要的數(shù)據(jù),使用memcpy函數(shù)可以得到錯誤的結(jié)果.

再者,如果內(nèi)存空間布局入下圖所示:

雖然原來的數(shù)據(jù)不再是原來的數(shù)據(jù)(dest+size>=src),但拷貝的數(shù)據(jù)是原來的數(shù)據(jù),使用memcpy函數(shù)可以得到正確的結(jié)果.因此,在使用memcpy這個函數(shù)之前,還需要做一個判斷,如果dest<=src你才能使用這個函數(shù)不過完全沒有必要, 解決辦法,從高地址向地地址copy

實例

void *memcpy(void *dest, const void *src, size_t count)  
{  
 char *d;  
 const char *s;  
   
 if (dest > (src+size)) || (dest < src))  
    {  
    d = dest;  
    s = src;  
    while (count--)  
        *d++ = *s++;          
    }  
 else /* overlap */  
    {  
    d = (char *)(dest + count - 1); /* offset of pointer is from 0 */  
    s = (char *)(src + count -1);  
    while (count --)  
        *d-- = *s--;  
    }  
    
 return dest;  
}  

•memcpy是把src指向的對象中的size個字符拷貝到dest所指向的對象中,返回指向結(jié)果對象的指針. 

•memmove也是把src指向的對象中的size個字符拷貝到dest所指向的對象中,返回指向結(jié)果對象的指針,但這兩個函數(shù)在處理內(nèi)存區(qū)域重疊的方式不同.

注意memmove這個函數(shù)名稱中有"move"這個單詞,而實際上src處的數(shù)據(jù)仍然還在,并沒有真的被"移動"了!這個函數(shù)名稱有它的歷史原因,是因為有了memcpy函數(shù)后,發(fā)現(xiàn)這個函數(shù)有問題,又發(fā)明了另一個沒有問題的memcpy函數(shù),但為了保證兼容性依然保留了memcpy函數(shù),而將新版本的memcpy函數(shù)改名為memmove函數(shù).

總結(jié)

1. 不要破壞傳進來的形參,定義新的臨時變量來操作

2.考慮指針的類型,不同類型的指針不能直接++賦值

3.overlap情況下需要從高地址處向前copy

到此這篇關(guān)于C語言函數(shù)之memcpy函數(shù)用法的文章就介紹到這了,更多相關(guān)C語言memcpy函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++使用curl庫的完成流程

    C++使用curl庫的完成流程

    curl 是一個利用URL語法在命令行方式下工作的文件傳輸工具,curl不但提供了一個可執(zhí)行的工具庫,還提供了供程序開發(fā)的libcurl庫,該庫使用c語言編寫,支持跨平臺,本文給大家介紹了C++使用curl庫的完成流程,需要的朋友可以參考下
    2024-09-09
  • C語言創(chuàng)建數(shù)組實現(xiàn)函數(shù)init,empty,reverse

    C語言創(chuàng)建數(shù)組實現(xiàn)函數(shù)init,empty,reverse

    這篇文章主要介紹了C語言創(chuàng)建數(shù)組實現(xiàn)函數(shù)init,empty,reverse,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07
  • 探討:C++實現(xiàn)鏈式二叉樹(用非遞歸方式先序,中序,后序遍歷二叉樹)

    探討:C++實現(xiàn)鏈式二叉樹(用非遞歸方式先序,中序,后序遍歷二叉樹)

    本篇文章是對用C++實現(xiàn)鏈式二叉樹(用非遞歸方式先序,中序,后序遍歷二叉樹)的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    這篇文章主要介紹了C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Qt中常用對話框使用技巧及注意事項

    Qt中常用對話框使用技巧及注意事項

    Qt?為應(yīng)用程序設(shè)計提供了一些常用的標準對話框,如打開文件對話框、選擇顏色對話框、信息提示和確認選擇對話框、標準輸入對話框等,這篇文章主要給大家介紹了關(guān)于Qt中常用對話框使用技巧及注意事項的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • C++在同一對象中存儲左值或右值的方法

    C++在同一對象中存儲左值或右值的方法

    C++ 代碼似乎經(jīng)常出現(xiàn)一個問題:如果該值可以來自左值或右值,則對象如何跟蹤該值?即如果保留該值作為引用,那么就無法綁定到臨時對象,本文給大家介紹了C++在同一對象中存儲左值或右值的幾種方法,需要的朋友可以參考下
    2025-03-03
  • C語言實現(xiàn)倒置字符串的兩種方法分享

    C語言實現(xiàn)倒置字符串的兩種方法分享

    這篇文章主要和大家詳細介紹了利用C語言實現(xiàn)倒置字符串的兩種方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起動手嘗試一下
    2022-08-08
  • 總結(jié)IOS中nil、Nil、NULL和NSNull區(qū)別

    總結(jié)IOS中nil、Nil、NULL和NSNull區(qū)別

    相信有不少朋友想知道,在 Objective-C 中 nil 和 Nil 以及 NULL 的區(qū)別。最重要的是,在面試中還有不少朋友常會被問到?,F(xiàn)在小編在這里統(tǒng)一詳細說明。
    2016-08-08
  • C語言實現(xiàn)高精度加法

    C語言實現(xiàn)高精度加法

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)高精度加法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • Linux UDP服務(wù)端和客戶端程序的實現(xiàn)

    Linux UDP服務(wù)端和客戶端程序的實現(xiàn)

    這篇文章主要介紹了Linux UDP服務(wù)端和客戶端程序的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05

最新評論

襄汾县| 丹寨县| 洛宁县| 龙泉市| 衢州市| 洪泽县| 普定县| 荔浦县| 枣阳市| 蓝山县| 杭锦旗| 榕江县| 堆龙德庆县| 建平县| 临夏市| 满洲里市| 阳新县| 峨边| 长阳| 和龙市| 崇左市| 海口市| 宣恩县| 万源市| 大埔区| 萝北县| 临潭县| 黄石市| 藁城市| 酉阳| 宣汉县| 白玉县| 闸北区| 玛曲县| 博爱县| 酒泉市| 铁力市| 宝坻区| 泰来县| 澳门| 林州市|