【问题标题】:How could I copy data that contain '\0' character如何复制包含“\0”字符的数据
【发布时间】:2014-11-24 23:06:20
【问题描述】:

我正在尝试复制包含“\0”的数据。我正在使用 C++ 。 当研究结果是否定的时,我决定编写自己的函数来将数据从一个 char* 复制到另一个 char*。但它不会返回想要的结果! 我的尝试如下:

#include <iostream>


char* my_strcpy( char* arr_out,  char* arr_in, int bloc )
{
 char* pc= arr_out;

 for(size_t i=0;i<bloc;++i)     
 {

        *arr_out++ = *arr_in++ ;
 }

 *arr_out = '\0';
 return pc;
}

int main()
{
    char * out= new char[20];
    my_strcpy(out,"12345aa\0aaaaa  AA",20);
    std::cout<<"output data: "<< out << std::endl;
    std::cout<< "the length of my output data: " << strlen(out)<<std::endl;
    system("pause");
    return 0;
}

结果在这里:

我不明白我的代码有什么问题。

提前感谢您的帮助。

【问题讨论】:

  • 您的函数几乎可以正常工作(除了对arr_out 的最后一次访问超出范围)。但是std::coutstrlen 都将\0 解释为字符串终止符。
  • for (blah) { cout &lt;&lt; out[blah]; } 但我不知道你想让\0 出现什么......
  • char out[20]; std::copy_n("12345aa\0aaaaa AA", 20, out);
  • 为什么不使用std::stringstd::vector&lt;char&gt;?这将是 C++ 中常用的处理方式。
  • 我刚刚注意到下面 Chris 的类似回答。他是对的-零字节和 memcpy() 没有问题-但是当您将 char* 传递给“cout

标签: c++ char strcpy


【解决方案1】:

(注意:对于任何不知道\0 是 C 和 C++ 中字符串文字中值为零的单字符字节的读者,不要与导致实际反斜杠的两字节序列后跟字符串中的实际零...我将引导您到Dr. Rebmu's explanation of how to split a string in C 以获取更多错误信息。)


C++ 字符串可以保持其长度独立于任何嵌入的\0。他们根据这个长度复制他们的内容。唯一的问题是,默认构造函数在使用 C 字符串且没有长度进行初始化时,将由空终止符引导至您想要的长度。

要覆盖它,您可以显式传入一个长度。不过,请确保长度准确。您有 17 个字节的数据,如果您希望字符串文字中的空终止符将其作为数据的一部分放入您的字符串中,则为 18 个字节。

#include <iostream>
using namespace std;

int main() {
    string str ("12345aa\0aaaaa  AA", 18);
    string str2 = str;
    cout << str;
    cout << str2;
    return 0;
}

(如果可以避免的话,尽量不要对这样的长度进行硬编码。请注意,你没有算对,当我在这里更正另一个答案时,他们也弄错了。这很容易出错。) em>

在我的终端上输出:

12345aaaaaaa  AA
12345aaaaaaa  AA

但请注意,您在这里所做的实际上是将 0 字节流式传输到标准输出。我不确定不同终端标准的行为是如何正式化的。根据您正在运行的终端类型,可打印范围之外的内容可用于各种目的......将光标定位在屏幕上,更改颜色等。我不会写出嵌入零的字符串除非我知道接收它们的流上的语义是什么。

考虑一下,如果您正在处理的是字节,请不要混淆问题并改用std::vector&lt;char&gt;。许多库提供了替代方案,例如 Qt 的 QByteArray

【讨论】:

  • 感谢您的回答。也许我会尝试使用 std::vector 来保存我的 std::string 。 (我没有使用 Qt)
  • @SADOK 请注意,向量实际上只是托管内存块,您可以从 std::vector (以及长度)中获取 char* ......对于 std: :细绳。 memcpy 等在适当的 C++ 编程中很少使用;它们是低级的且容易出错。
【解决方案2】:
  • 我不明白我的代码有什么问题。

    my_strcpy(out,"12345aa\0aaaaa AA",20);

您的字符串包含被解释为escape sequence 的字符“\”。为防止这种情况,您必须复制反斜杠:

my_strcpy(out,"12345aa\\0aaaaa  AA",20);

Test

output data: 12345aa\0aaaaa  AA
the length of my output data: 18

【讨论】:

  • 你相信我必须浏览成千上万个字符并添加'\'!我必须转换为 char* 的变量是加密 pdf 文件的函数的结果,换句话说就是加密数千个字符的函数 ...
  • @SADOK:这是另一个问题。相应地编辑您的帖子,或发布另一个帖子。
  • 好的,最好再发个帖子;)
  • @SADOK 问题标题是 “我如何复制包含 '\0' 字符的数据”...我们在这里假设您知道它是一个空字节而不是两个字符的反斜杠序列,后跟一个零......正确吗?
  • 你能告诉我空字节和反斜杠后跟零的两个字符序列有什么区别吗?不一样吗?无论如何,您都可以在 [这里] 找到我原来的问题的描述 stackoverflow.com/questions/26121894/…
【解决方案3】:

你的函数很好(除了你应该传递给它17而不是20)。如果需要输出空字符,一种方法是将数据转换为std::string

std::string outStr(out, out + 17);
std::cout<< "output data: "<< outStr << std::endl;
std::cout<< "the length of my output data: " << outStr.length() <<std::endl;

【讨论】:

  • 您没有计算字节数。未定义的行为。 (我数了 18。)
  • 我在这里被阻止了,因为我必须返回 char* 而不是 std::string。如果没有,这对我来说将是个大问题,因为我将不得不更改自编码两周以来开发的所有功能
  • @SADOK 你最好描述你原来的问题。如果你得到一个包含零字节的char*,你必须从某个地方知道它的长度。所以你可以而且应该把它传递下去。
  • @Anton Savin:我对stackoverflow 中的规则有疑问。我必须做些什么来描述我原来的问题?删除这篇文章并替换它,或者我问另一个相同主题的问题! (因为这里不容易描述我原来的问题)
  • @SADOK 您在此处提出的问题已在原始限制范围内得到几个人的正确回答。我认为现在改变问题为时已晚,最好问一个新问题。但我不知道您的具体情况,例如您的新问题可能与 SO 无关。
【解决方案4】:

如果您知道“字符串”的长度,请使用 memcpy。当遇到字符串终止符 \0 时,Strcpy 将停止其复制。 Memcpy 不会,它会复制 \0 和后面的任何内容。

【讨论】:

  • 我试图用 memcpy() 来做这个,但我遇到了同样的问题
  • 如果你做了 memcpy (dst, src, 20) 那么字符串肯定被复制了。字符串的显示将在 \0 处停止。也许您正在寻找一种将字符串分解以显示单独部分的方法?
  • 如果 cout 和 strlen 在 '\0' 处停止,我如何确定我的字符串被复制了。我正在寻找将 std::string 转换为 char*。
  • 您实际上有两个以空字符结尾的字符串背靠背。你可以有三个或更多。所以你需要一个循环的 cout 来显示每个字符串。
  • 阅读另一个问题,但它存在被阻止的外部站点 JS。您的输出字符串不起作用,还有其他转义序列可以操纵输出、删除一行等。做你想做的事情的唯一安全方法是十六进制转储它。为了证明这一点,您不能物理打印 \0,因此在结果字符串中,您将如何确定 \0 的位置?
【解决方案5】:

您的my_strcpy 工作正常,当您将char* 写入cout 或使用strlen 计算其长度时,它们停止在\0,按照C 字符串行为。顺便说一句,不管\0如何,你都可以使用memcpy复制char的一个块。

【讨论】:

  • 但 memcpy 也停在 \0。请测试它以确保
  • @SADOK 不,它没有,阅读this
  • memcpy 不会在空字节上停止。在任何情况下,您都应该使用 std::copystd::copy_n 在 C++ 中执行此类操作。
【解决方案6】:

你的字符串已经中途终止了。

my_strcpy(out,"12345aa\0aaaaa  AA",20);

你为什么打算在中间有 \0 呢?如果您愿意,可以使用其他分隔符 否则,由于 std::cout 和 strlen 将 \0 解释为字符串终止符,您会感到惊讶。 我的意思是遵循约定,即 '\0' 作为字符串终止符

【讨论】:

  • std::cout 不会将 \0 解释为字符串终止符。它将字符串保存的字节数发送到标准输出和您的终端,或者它对它所做的任何事情。您的终端可能会以其他方式解释大量代码(定位光标、更改文本颜色等),因此最好保持在可打印范围内,除非您知道自己在做什么。
  • @Debasish Jana:我正在尝试复制密文,不幸的是,我的密文包含相邻的符号“\”和“0”——
  • @SADOK,那么您的字符串复制功能是绝对正确的,您可以在文本缓冲区的最开始保留一个标题来保存字符串的预期长度,这将满足您的目的,任何支持请问?
  • upVote 没问题。完成。我已经有一个标题。它包含我要转换为 char* 的字符串的长度。
  • @SADOK,所以你的字符串应该包含“17:12345aa\0aaaaaa AA”而不是“12345aa\0aaaaaa AA”,假设 17 是后面的实际字符串的长度:delemeter
猜你喜欢
  • 2015-05-20
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
  • 2017-09-03
  • 2020-09-20
  • 1970-01-01
相关资源
最近更新 更多