記憶體重疊是指在記憶體中存在兩個或多個區域,它們的地址范圍有交叉部分,在 C++ 中,記憶體重疊可能會導致程式出現不可預期的行為,因此我們需要了解它的原因和如何避免,
記憶體重疊的原因
記憶體重疊的主要原因是指標的使用,當我們使用指標訪問記憶體時,如果指標指向的記憶體區域與另一個區域有交叉部分,就會產生記憶體重疊,
如下圖,記憶體拷貝的兩種情況:

第一種情況下,拷貝重疊的區域不會出現問題,內容均可以正確地被拷貝,
第二種情況下,問題出現在右邊的兩個位元組,這兩個位元組的原來的內容首先就被覆寫了,而且沒有保存,所以接下來拷貝的時候,拷貝的是已經被覆寫的內容,顯然這是有問題的,
舉個代碼例子,下面的代碼片段就會導致記憶體重疊:
char str[] = "Hello World";
char* p = str + 1;
memcpy(p, str, 11);
在上面的代碼中,我們定義了一個字符陣列 str,并使用指標 p 指向 str 中的第二個字符,接著,我們使用 memcpy 函式將 str 中的 11 個字符復制到了 p 指向的區域,由于 p 指向的區域與 str 有交叉部分,因此就產生了記憶體重疊,因為 memcpy 是直接按位復制拷貝,代碼如下,所以會遇到情況二,拷貝的是已經被覆寫的內容,
void *memcpy(void *dest, const void *src, size_t count)
{
char *tmp = dest;
const char *s = src;
while (count--)
*tmp++ = *s++;
return dest;
}
如何避免記憶體重疊
為了避免記憶體重疊,我們需要注意以下幾點:
- 盡量避免使用指標,尤其是指標運算和型別轉換;
- 在使用指標時,確保指標指向的記憶體區域與其他區域沒有交叉部分;
- 使用安全的記憶體操作函式,如
memcpy_s、memmove等,這些函式可以確保在復制記憶體時不會產生記憶體重疊,
那 memmove 是怎么避免記憶體重疊的影響呢,我們看看 memmove 的代碼:
void *memmove(void *dest, const void *src, size_t n)
{
char *d = dest;
const char *s = src;
if (d < s) {
while (n--)
*d++ = *s++;
} else {
// 采用倒序拷貝
char *lasts = (char *)s + (n - 1);
char *lastd = d + (n - 1);
while (n--)
*lastd-- = *lasts--;
}
return dest;
}
memmove 判斷如果 dest ≥src 的時候(也就是前面圖片的情況2),采用倒序拷貝,避免了內容被覆寫導致拷貝不完整的問題,
其原理圖如下:

memcpy 與 strcpy 都沒有記憶體重疊的問題,實際可以根據需要使用 memmove ,
總結
本文介紹了 C++ 中的記憶體重疊問題,指出了指標的使用是記憶體重疊的主要原因,并提供了避免記憶體重疊的方法,如盡量避免使用指標,確保指標指向的記憶體區域與其他區域沒有交叉部分,使用安全的記憶體操作函式等,此外,還介紹了 memmove 函式如何避免記憶體重疊的影響,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/547881.html
標籤:其他
上一篇:堆疊的實作:括號的決議
