【问题标题】:Explanation on how does the memcpy function behaves? [duplicate]解释 memcpy 函数的行为方式? [复制]
【发布时间】:2017-10-28 17:38:53
【问题描述】:
#include <stdio.h>
#include <string.h>

char lists[10][25];
char name[10];

void main()
{
    scanf("%s" , lists[0]);
    memcpy(name , lists[0], 25);

    printf("%s\n" , name);
}

在上面的代码中,我将字符数组“name”的大小预定义为 10。 现在,当我将输入输入为:

输入 - abcdefghijklmnopqrstuvwxy

我得到的输出是相同的字符串:abcdefghijklmnopqrstuvwxy

我应该得到输出为:abcdefghij ???

即使数组的大小限制为 10,这如何成为可能?

【问题讨论】:

  • 这是一个未定义行为的例子,这意味着任何事情都可能发生。包括正常运行的程序。
  • 您的代码在线条之外着色,非常基本的 UB。如果你想让它炸毁并重新格式化磁盘,那么你需要更多的颜色。交换两个变量声明值得一试。
  • 大多数语言都阻止程序员写超出数组的末尾。 C 没有。你有责任防止这种情况发生。
  • 您可能会在 memcpy 中遇到分段错误,因为您的副本超出范围

标签: c memcpy string.h


【解决方案1】:

因为它不知道它正在写入的分配内存的大小,所以你逃脱了额外数据的写入位置。您可能不在其他平台上,或使用不同的编译器,或不同的优化设置。

size 参数传递给memcpy () 时,最好考虑目标内存的大小。

在使用 char 数组时,如果您想更安全地避免内存溢出,可以使用strncpy ()。它会负责在正确的位置插入尾随 NULL

【讨论】:

  • 所以你的意思是说如果我可用的内存块是 10 那么这不会发生?
  • 不,如果内存是 25,那么你就没有问题了。 C 确实依赖于程序员小心内存分配和写入等
  • 我的意思是说可用的物理内存只有 10 块,那么我将无法找到一些额外的内存,然后它就会引发错误或什么的!对吧??
  • 是的,如果复制越界,您可能会遇到分段错误
  • 不,再次,因为memcpy 不知道它在哪里复制并且无法保护您。如果您只有 10 个字节,请将 10 作为大小传入,它将确保它只复制 10 个字节。但是你的字符串不会正确地以 NULL 结尾,所以你会有其他问题。
【解决方案2】:

首先,数组是指针。在 C 中,没有像 Java 那样的长度检查。

当您编写 char a[2]; 时,操作系统会为您提供 2 个字符的内存空间。 比如让内存是

|1|2|3|4|5|6|7|8|9|10|11|12|
 a

a是指向地址1的指针。a[0] = 0;等于*(a+0) = 0,意思是write 0 to the address a + offset 0

因此,如果您尝试写入尚未分配的地址,可能会发生意想不到的事情。

例如,假设我们有char a[2];char b[2];,内存映射是

|1|2|3|4|5|6|7|8|9|10|11|12|
 a   b

那么a[2] = 0 等于b[0] = 0。但是如果这个地址是其他程序的地址,则会引发分段错误。

试试这个程序(它可能在没有编译器优化的情况下工作):

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

char a[4];
char b[4];

void main()
{
    scanf("%s" , a);    // input "12345678"
    printf("%s\n" , b); // print     "5678"
}

memcpy 只是从一个地址复制到另一个你所说的数据大小。

在您的示例中,您很幸运,因为您访问的所有地址都分配给了您的程序(在您的内存页面内)。

在 C/C++ 中,您有责任正确处理内存。另外,请记住,字符串以字符 \0 结尾,因此在数组 char str[10]; 中,我们通常有前 9 个字符和 \0

【讨论】:

  • 我认为你这里有一个错字:“a[0] = 0; 等于 *(a+1) = 0,意味着将 0 写入地址 a + 偏移量 0。”
  • 是的,当然。谢谢你。 (现在是正确的)
  • "|1|2|3|4|5|6|7|8|9|10|11|12| a b 那么 a[2] = 0 等于 b[0] = 0。”如果你依赖这种行为,你就会陷入一个受伤的世界。不知道编译器/优化器会做什么。
  • 在第一个例子中,这是假设。在代码上,希望编译器会按顺序分配变量。无论如何,正如我提到的“如果您尝试写入尚未分配的地址,可能会发生意想不到的事情”,a[2] 就是这样一个地址。
  • 知道了。我首先以为您是在暗示分配将必然以这种顺序方式布置。我看到你在说假设变量以这种方式布局......那么行为将如下......
猜你喜欢
  • 2014-09-06
  • 2015-10-18
  • 2016-06-09
  • 2019-09-09
  • 2020-04-22
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
相关资源
最近更新 更多