使用memcpy函數時要注意拷貝數據的長度


本文轉載於https://www.cnblogs.com/xia-weiwen/p/11255927.html

memcpy函數簡介

memcpy函數是C/C++語言中的一個用於內存復制的函數,聲明在 string.h 中(C++是 cstring)。其原型是:

void *memcpy(void *destin, void *source, unsigned n); 

作用是:以source指向的地址為起點,將連續的n個字節數據,復制到以destin指向的地址為起點的內存中。
函數有三個參數,第一個是目標地址,第二個是源地址,第三個是數據長度。
使用memcpy函數時,需要注意:

  • 數據長度(第三個參數)的單位是字節(1byte = 8bit)。
  • 注意該函數有一個返回值,類型是void*,是一個指向destin的指針。

memcpy函數復制的數據長度

使用memcpy函數時,特別要注意數據長度。
如果復制的數據類型是char,那么數據長度就等於元素的個數。而如果數據類型是其他(如int, double, 自定義結構體等),就要特別注意數據長度的值。
好的習慣是,無論拷貝何種數據類型,都用 n * sizeof(type_name)的寫法。
先以最簡單的情況說明:

    char a[10] = "abcdefgh"; unsigned n = 2; void * p = memcpy(a+3, a, n); 

以上代碼將從a開始的兩個字節的數據(即'a'和'b'),復制到從a+3開始的內存('d'所在的地址)。這樣,'d'和'e'被替換。
執行結束之后,字符數組(字符串)a的內容變為"abcabfgh",返回值p即為a的地址(p == a)。

再以int類型為例說明:

    int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; unsigned n = 5; void * p = memcpy(a+3, a, n); 

int類型的長度是4個字節。以上代碼將從a開始的5個字節的數據復制。5個字節的數據是什么呢?前四個字節組成了一個完整的int(即第一個元素0)。第五個字節,只能取到第二個元素的第1個字節。這里又會涉及到big-endian和little-endian的問題。假設是小端方式儲存(更常見),那么讀到的是元素1的低8位,寫成十六進制即0x1
目標地址是a+3。由於指針加減常數,單位是與類型保持一致的,也就是在a的基礎上,增加3倍int長度,對應的是元素3的地址。元素3被替換為0。元素4寫成十六進制是0x0004,低8位被替換為0x1,變為0x0001
所以執行結束之后,數組a的內容變為 { 0, 1, 2, 0, 1, 5, 6, 7, 8, 9 },返回值p即為a的地址(p == a)。
根據上面的解釋,如果把程序里的n改為6、7、8,那么結果都是一樣的。因為數字1和4的二進制表示除了低8位不同,高位都是0。

倘若高位不相同,那么結果就沒那么簡單了。還是以int數組為例:

    int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 }; unsigned n = 5; memcpy(a+3, a, n); 

復制5個字節的數據,前4個字節組成了一個int,即第一個元素0。那么元素3被替換為0。第5個字節從-1中取。-1的十六進制表示為0xFFFF,第5個字節的數據是0xF。元素4變為0x000F,即15。數組a變為 { 0, -1, 2, 0, 15, 5, 6, 7, 8, 9 }。
如果 n = 6,那么4變為```0x00FF``,即255。數組a變為 { 0, -1, 2, 0, 255, 5, 6, 7, 8, 9 }。

可以看出,如果你想用memcpy復制元素,那么一定要寫對數據長度。如果要完整地復制 n 個 int 類型元素,那么寫法如下:

    int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 }; unsigned n = 5 * sizeof(int); memcpy(a+3, a, n); 

數組a變為 { 0, -1, 2, 0, -1, 2, 0, -1, 8, 9 }。
如果是其他類型,用法也是一樣的。

好的習慣是,如果拷貝何種數據類型,都用 n * sizeof(type_name)的寫法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM