使用 memcpy 复制 n 个字符
Copying n characters using memcpy
我正在尝试使用 memcpy 复制 32 个字符的确切数量,但是我在正确使用它时遇到问题,因为多个在线 g++ 编译器以及我机器上的编译器给出的结果与相同的源代码。
代码:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
char dest[32];
std::memcpy(&dest, source, sizeof(dest));
std::cout << dest << "(" << strlen(dest) << ")";
}
代码编译于 here (G++4.9.2)。
输出不包含 32 个字符(正在添加垃圾值):
Lorem ipsum dolor sit amet, cons †¿(36)
代码编译于 here (G++4.9)。
输出包含所需的结果:
Lorem ipsum dolor sit amet, cons(32)
我机器上的输出类似于第一个输出(36 个字符)。
为什么每个结果都不一样?
memcpy 复制 n 个字符的有效用法应该是什么?
strlen
函数和operator<< (const char *)
函数只适用于C风格的字符串。它们不能用于输出或测量任意数据块的长度。
想一想——他们怎么可能确定长度?他们可能使用什么方法?
Why is each result different?
因为您使用的函数只能用于非 C 风格字符串的 C 风格字符串。这是一个根据平台内存布局的具体情况而表现不同的错误。
What should be the valid usage of memcpy to copy n numbers of characters?
就是这样。你复制了字符。但是现在你只有一堆字符,而不是字符串。如果您使用打印字符束的函数,它们会工作正常。
试试这个:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mat
char dest[32];
std::memcpy(&dest, source, sizeof(dest));
for (int i = 0; i < sizeof(dest); ++i)
std::cout << dest[i];
}
dest
不是空终止的。因此,像 strlen
或 operator <<
这样的函数不知道它们已经到达缓冲区的末尾,并且即使在到达 32 个字符后仍会继续。在 dest[31]
之后的未知内存中遇到 null 时,它们会停止,可以是在 10、1000、1000000 字节甚至根本没有之后。您需要的是:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
char dest[33];
std::memcpy(&dest, source, sizeof(dest)-1);
dest[32] = '[=10=]';
std::cout << dest << "(" << strlen(dest) << ")";
}
memcpy 函数不检查源中的任何终止空字符 - 它总是精确地复制 num 个字节。你应该以 null 结束。
您可以使用 std::string
:
#include <iostream>
#include <string>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
std::string s(source, 32);
std::cout << s << "(" << s.length() << ")";
}
对于memcpy,你通常不想用在c风格的字符串上,因为字符串的长度是内存块的大小减1。
这是因为C++内存分配的奇怪方法
解决方案之一是确定数组的长度。
如果一个数组定义在函数内部,它不会显示为好像它充满了 nuls。更明显的是,strlen() 函数通过找到第一个 nul 字节来计算字符串的长度。在函数内部,变量最初未初始化,并且将包含任意数据。这块内存,是直接从操作系统堆中取出来的。
如果像这样把数组放在外面:
#include <iostream>
#include <cstring>
using namespace std;
char dest[32];
int main(int argc, char** argv) {
....
它将正常运行,因为在函数外部声明的任何变量最初都初始化为零。
解决这个问题的另一种方法是,就像@Lucas 所说的那样,在外面留一个字节为空,即:
char dest[33];
memcpy(dest, source, sizeof(char) * 32);
这不受数组是否位于函数外部的影响。
具体的strlen函数原理类似:
int strlen(char* str)
{
for (int i = 0; ; i++)
if (str[i] == 0)
return i;
return 0;
}
有网友指出我不能保证第33字节是空的。现在我找到了解决方案:
char dest[33];
memset(dest, 0, sizeof(char) * 33);
memcpy(dest, source, sizeof(char) * 32);
或者简单地将最后一个字节设置为nul。
char dest[33];
dest[32] = 0;
一些更安全和更好看的方法包括直接内存分配。然而根据一些统计数据,new 命令和 malloc() 函数会导致性能下降。
char *dest = new char[32];
memcpy(dest, source, sizeof(char) * 32);
如果你使用下面的代码,你会遇到意想不到的结果。
char *dest = new char[32];
memcpy(dest, source, sizeof(char) * 32);
因此,在 C/C++ 中编程时,请始终记住考虑边界。
我正在尝试使用 memcpy 复制 32 个字符的确切数量,但是我在正确使用它时遇到问题,因为多个在线 g++ 编译器以及我机器上的编译器给出的结果与相同的源代码。
代码:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
char dest[32];
std::memcpy(&dest, source, sizeof(dest));
std::cout << dest << "(" << strlen(dest) << ")";
}
代码编译于 here (G++4.9.2)。
输出不包含 32 个字符(正在添加垃圾值):
Lorem ipsum dolor sit amet, cons †¿(36)
代码编译于 here (G++4.9)。
输出包含所需的结果:
Lorem ipsum dolor sit amet, cons(32)
我机器上的输出类似于第一个输出(36 个字符)。
为什么每个结果都不一样?
memcpy 复制 n 个字符的有效用法应该是什么?
strlen
函数和operator<< (const char *)
函数只适用于C风格的字符串。它们不能用于输出或测量任意数据块的长度。
想一想——他们怎么可能确定长度?他们可能使用什么方法?
Why is each result different?
因为您使用的函数只能用于非 C 风格字符串的 C 风格字符串。这是一个根据平台内存布局的具体情况而表现不同的错误。
What should be the valid usage of memcpy to copy n numbers of characters?
就是这样。你复制了字符。但是现在你只有一堆字符,而不是字符串。如果您使用打印字符束的函数,它们会工作正常。
试试这个:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mat
char dest[32];
std::memcpy(&dest, source, sizeof(dest));
for (int i = 0; i < sizeof(dest); ++i)
std::cout << dest[i];
}
dest
不是空终止的。因此,像 strlen
或 operator <<
这样的函数不知道它们已经到达缓冲区的末尾,并且即使在到达 32 个字符后仍会继续。在 dest[31]
之后的未知内存中遇到 null 时,它们会停止,可以是在 10、1000、1000000 字节甚至根本没有之后。您需要的是:
#include <iostream>
#include <cstring>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
char dest[33];
std::memcpy(&dest, source, sizeof(dest)-1);
dest[32] = '[=10=]';
std::cout << dest << "(" << strlen(dest) << ")";
}
memcpy 函数不检查源中的任何终止空字符 - 它总是精确地复制 num 个字节。你应该以 null 结束。
您可以使用 std::string
:
#include <iostream>
#include <string>
int main()
{
const char* source = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu ipsum nec elit mattis consequat. Curabitur sollicitudin ligula et quam bibendum euismod.";
std::string s(source, 32);
std::cout << s << "(" << s.length() << ")";
}
对于memcpy,你通常不想用在c风格的字符串上,因为字符串的长度是内存块的大小减1。
这是因为C++内存分配的奇怪方法
解决方案之一是确定数组的长度。 如果一个数组定义在函数内部,它不会显示为好像它充满了 nuls。更明显的是,strlen() 函数通过找到第一个 nul 字节来计算字符串的长度。在函数内部,变量最初未初始化,并且将包含任意数据。这块内存,是直接从操作系统堆中取出来的。
如果像这样把数组放在外面:
#include <iostream>
#include <cstring>
using namespace std;
char dest[32];
int main(int argc, char** argv) {
....
它将正常运行,因为在函数外部声明的任何变量最初都初始化为零。
解决这个问题的另一种方法是,就像@Lucas 所说的那样,在外面留一个字节为空,即:
char dest[33];
memcpy(dest, source, sizeof(char) * 32);
这不受数组是否位于函数外部的影响。
具体的strlen函数原理类似:
int strlen(char* str)
{
for (int i = 0; ; i++)
if (str[i] == 0)
return i;
return 0;
}
有网友指出我不能保证第33字节是空的。现在我找到了解决方案:
char dest[33];
memset(dest, 0, sizeof(char) * 33);
memcpy(dest, source, sizeof(char) * 32);
或者简单地将最后一个字节设置为nul。
char dest[33];
dest[32] = 0;
一些更安全和更好看的方法包括直接内存分配。然而根据一些统计数据,new 命令和 malloc() 函数会导致性能下降。
char *dest = new char[32];
memcpy(dest, source, sizeof(char) * 32);
如果你使用下面的代码,你会遇到意想不到的结果。
char *dest = new char[32];
memcpy(dest, source, sizeof(char) * 32);
因此,在 C/C++ 中编程时,请始终记住考虑边界。