Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม C

ฟังก์ชัน memmove() ใน C/C++: ย้ายหน่วยความจำ (รองรับ Overlap)

ฟังก์ชัน memmove() คล้าย memcpy() แต่ รองรับ Overlapping Memory Regions ทำงานถูกต้องแม้ Source และ Destination จะทับซ้อนกัน อยู่ใน Header <string.h>

ไวยากรณ์

#include <string.h>
void *memmove(void *dest, const void *src, size_t n);
  • dest - Destination Buffer
  • src - Source Buffer
  • n - จำนวน Bytes
  • คืนค่า: dest

ตัวอย่าง

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Secondstring";
    char dest[] = "Firststring";
    
    // ย้าย 9 bytes จาก src ไป dest (Overlap ไม่ได้ในตัวอย่างนี้ แต่ memmove ทำงานได้)
    memmove(dest, src, 9);
    
    printf("New arrays: %s\t%s\n", dest, src);
    return 0;
}

ผลลัพธ์

New arrays: Secondstrng  Secondstring

ความแตกต่างหลัก: Overlapping Behavior

กรณี Overlap: memmove() ทำงานถูกต้อง

char str[] = "abcdefghijklmnop";

printf("Before: %s\n", str);  // abcdefghijklmnop

// Copy 8 bytes from index 4 to index 0 (Overlap!)
memmove(str, str + 4, 8);

printf("After:  %s\n", str);  // efghijklmnop

memcpy() กับกรณีเดียวกัน: Undefined Behavior

char str[] = "abcdefghijklmnop";
// memcpy(str, str + 4, 8);  // UB! ผลลัพธ์ไม่แน่นอน

วิธีการทำงานของ memmove() (Implementation Strategy)

// Pseudocode
void *memmove(void *dest, const void *src, size_t n) {
    if (dest < src) {
        // Forward Copy: Copy from Beginning
        // Safe: Destination เขียนทับ Source ที่ยังไม่ได้อ่าน
        for (i = 0; i < n; i++) dest[i] = src[i];
    } else if (dest > src) {
        // Backward Copy: Copy from End
        // Safe: Destination เขียนทับ Source ที่อ่านแล้ว
        for (i = n; i > 0; i--) dest[i-1] = src[i-1];
    }
    return dest;
}

ตารางเปรียบเทียบ

คุณสมบัติmemcpy()memmove()
Overlap Safety✗ Undefined Behavior✓ Safe (Handles Both Directions)
Performanceเร็วกว่าเล็กน้อยช้ากว่าเล็กน้อย (Branch Check)
Use CaseNon-overlapping, Performance CriticalOverlapping หรือ Unknown
ImplementationSimple Forward CopyDirection-aware Copy

เมื่อไหร่ควรใช้ memmove()

  • Shift Array Elements (Insert/Delete ใน Array)
  • Buffer Management (Circular Buffers)
  • String Manipulation ที่ Overlap
  • เมื่อไม่แน่ใจว่า Overlap หรือไม่ (Safe Choice)

ตัวอย่าง: Insert Element ใน Array

void insertInt(int *arr, int *size, int capacity, int index, int value) {
    if (*size >= capacity) return;  // Full
    
    // Shift elements right (Overlap: dest = src + 1)
    memmove(&arr[index + 1], &arr[index], (*size - index) * sizeof(int));
    
    arr[index] = value;
    (*size)++;
}

int main() {
    int arr[10] = {1, 2, 3, 4, 5};
    int size = 5;
    
    insertInt(arr, &size, 10, 2, 99);  // Insert 99 at index 2
    // arr = {1, 2, 99, 3, 4, 5}
    return 0;
}

ตัวอย่าง: Delete Element จาก Array

void deleteInt(int *arr, int *size, int index) {
    if (index < 0 || index >= *size) return;
    
    // Shift elements left (Overlap: dest = src - 1)
    memmove(&arr[index], &arr[index + 1], (*size - index - 1) * sizeof(int));
    
    (*size)--;
}

สรุป

memmove() คือ Safe Version ของ memcpy() สำหรับ Overlapping Regions ใช้เมื่อ Source และ Destination อาจทับซ้อนกัน (Shift Arrays, Buffer Operations) ช้ากว่า memcpy เล็กน้อย แต่ปลอดภัยกว่า