编程后端C开发者

如何在C语言中安全地在数组之间复制内存?应该使用哪些标准库函数,它们有什么区别?

用 Hintsage AI 助手通过面试

答案

问题历史

安全的内存复制是C语言中最常见且最关键的任务之一。最初,程序使用循环进行逐字节复制。后来的标准函数包括:memcpymemmove,以及像strncpy这样的更安全的字符串替代品。不正确的复制会导致缓冲区溢出和安全漏洞。

问题

使用不合适的函数或错误的大小进行复制可能会破坏数据,甚至可能被安全感兴趣的第三方利用。区分在何种情况下使用memmove,何时可以使用memcpy,对于避免内存重叠错误是至关重要的。

解决方案

对于安全地复制非字符串内存,请使用:

memcpy(dest, src, n);
  • memcpy快速地将n字节从src复制到dest,如果它们的内存区域不重叠。
  • 如果区域可能重叠,请使用memmove
memmove(dest, src, n);

对于字符串的复制,最好使用strncpy,或者更好的是,如果可用,现代且安全的替代品strlcpy

关键特点:

  • memcpy仅在src和dest不重叠时安全。
  • memmove即使在内存区域重叠时也能正确工作。
  • 对于字符串,最好使用专门的函数,考虑到空终止符。

具有陷阱的问题。

1. memcpy和memmove有何区别,何时需要使用哪种函数?

memcpy非常快速,但不适用于重叠的内存区域——结果会变得不可预测。memmove保证无论重叠情况如何,都会正确复制:

int arr[] = {1,2,3,4,5}; // memmove:安全地复制重叠 memmove(arr+1, arr, 4 * sizeof(int));

2. 使用strcpy将字符串复制到较小的缓冲区是否安全?

不,strcpy函数不会检查目标缓冲区的大小。这通常会导致缓冲区溢出。最好使用strncpy,或者strlcpy(如果可用),或者显式地控制大小:

char dest[5]; strncpy(dest, src, sizeof(dest)-1); // src应少于5个字符

3. 可以使用memcpy复制包含指针的结构体吗?

可以,但这只会复制指针本身,而不是那些地址上的数据。这可能导致内存操作错误和双重释放。

常见错误和反模式

  • 在内存区域重叠时使用memcpy。
  • 忽视目标缓冲区的大小。
  • 对包含指针的结构体简单使用memcpy(浅拷贝)。

生活中的例子

负面案例

使用strcpy将长字符串复制到小缓冲区而不检查源长度。导致缓冲区溢出,造成安全漏洞。

优点:

  • 最小的代码,快速执行。

缺点:

  • 安全漏洞,可能出现崩溃,内存损坏。

正面案例

使用strncpy或memmove,并精确控制大小,手动确保字符串以零字符结束。

优点:

  • 可预测的行为,防止缓冲区溢出。

缺点:

  • 需要额外控制长度,可能由于额外的检查而略微降低速度。