【问题标题】:How to memset char array with null terminating character?如何使用空终止字符来memset char数组?
【发布时间】:2012-10-07 19:05:43
【问题描述】:

用空终止字符memset整个字符数组的正确和最安全的方法是什么?我可以列出一些用法:

...
char* buffer = new char [ARRAY_LENGTH];

//Option 1:             memset( buffer, '\0', sizeof(buffer) );
//Option 2 before edit: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );
//Option 2 after edit:  memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );
//Option 3:             memset( buffer, '\0', ARRAY_LENGTH );
...
  • 其中任何一个都比其他的有显着优势吗?
  • 使用 1、2 或 3 会遇到哪些问题?
  • 处理此请求的最佳方式是什么?

【问题讨论】:

  • 选项 2 错误,应为 sizeof(char),始终为 1
  • 您有“c”标签,但“new char[ARRAY_LENGTH]”不是有效的 C 语法。
  • 您的任何选择都不正确!调用 memset 的正确方法是 memset(buffer, '\0', sizeof(char) * ARRAY_LENGTH);。不过 Luchian 指定的语法更好。
  • 抱歉标签错误和错字 - 刚刚编辑了问题
  • @Lundin sizeof(char) 的定义是 1。当我看到它时,我实际上将它用作表示对代码进行特别仔细审查的标志。

标签: c++ arrays c++11 memset null-terminated


【解决方案1】:

惯用的方式是对数组进行值初始化:

char* buffer = new char [ARRAY_LENGTH]();

选项 1 仅将第一个 sizeof(char*) 字节设置为 0,或者在 ARRAY_LENGTH < sizeof(char*) 时运行未定义的行为。这是由于使用了指针的大小而不是类型的大小。

选项 2 遇到未定义的行为,因为您尝试设置的字节数超过 ARRAY_LENGTH 字节。 sizeof(char*) 几乎肯定大于 1。

由于这是 C++(C 中没有 new),我建议您改用 std::string

对于C(假设malloc而不是new[]),你可以使用

memset( buffer, 0, ARRAY_LENGTH );

【讨论】:

    【解决方案2】:

    如果您绝对必须在 C++ 中使用原始数组(这是一个非常糟糕的主意),请这样做:

    char* buffer = new char [ARRAY_LENGTH]();
    

    对于 C++,memset 通常是无能者的最后避难所,尽管我在过去几个月中了解到,为了获得可接受的性能,使用当前工具,当一个人实现自己的字符串类时,有必要降低到那个水平。

    代替这些看起来需要memset的原始数组等,使用例如std::string(针对上述情况)、std::vectorstd::array

    【讨论】:

    • “这是一个非常糟糕的主意”。是的?那么如何编写代码来处理一组 8 位硬件寄存器值呢?
    • @Lundin - 你可能不应该问这些人 - 他们会对 std::vector 元数据进行一些令人讨厌的调整,以便它指向内存映射硬件
    • 从 C++ 11 开始,我应该使用:std::unique_ptr<char[]> buffer(new char[ARRAY_LENGTH]());,从 C++ 14 开始,我会使用:std::unique_pointer<char[]> buffer = std::make_unique<char[]>(ARRAY_LENGTH);,或者如果需要,可以使用共享指针。
    • @AmitG.:嗯。如果我不得不有一个new-allocated 原始数组,我更喜欢auto buffer = make_unique<char[]>(array_length);
    【解决方案3】:

    选项一和二是错误的。第一个使用指针的大小而不是数组的大小,因此它可能不会写入整个数组。第二个使用sizeof(char*) 而不是sizeof(char),所以它会写到数组的末尾。选项3没问题。你也可以用这个

    memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );
    

    sizeof(char) 保证为1。

    【讨论】:

    • 第二个选项是使用sizeof(char) 而不是sizeof(char*) 或者我错过了什么?
    • @PiotrNycz:从问题下的hmjd评论来看,问题最初在选项2中说sizeof(char*),但在编辑窗口中被更改,因此没有编辑历史记录。
    • @LuchianGrigore:这只会让其他人的答案看起来不对——三个人说选项 2 没问题。
    • 不是那么重要,但是传递 0 而不是 '\0' 也可以。
    • 假设数组是char a[200][200];memset(a, 0, sizeof(a)); 工作正常吗?
    【解决方案4】:

    Option 3: memset( buffer, '\0', ARRAY_LENGTH ): 只会给你数组的长度,但实际上这个参数是总共有多少字节的内存。

    Option 1: memset( buffer, '\0', sizeof(buffer) ): 会给你错误的答案,因为bufferchar*sizeof(buffer) 不会给你整个数组的大小,只有指针变量的大小。

    选项2是对的。

    【讨论】:

      【解决方案5】:

      由于问题不断变化,我定义:

      1:memset( buffer, '\0', sizeof(buffer) );

      2a:memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );

      2b:memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );

      3:memset( buffer, '\0', ARRAY_LENGTH );

      如果问题仅仅是“调用memset 的正确方法是什么”而不是“将此数组归零的最佳方法是什么”,那么 2b 或 3 都是正确的。 1 和 2a 是错误的。

      您可以在 2b 与 3 上进行风格大战:是否包含 sizeof(char) - 有些人因为它是多余的而将其省略(我通常这样做),其他人将其放入以创造一种一致性使用相同的代码设置int 的数组。也就是说,他们总是将一个大小乘以多个元素,即使他们知道大小是 1。一个可能的结论是,对buffer 指向的数组进行 m​​emset 的“最安全”方法是:

      std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);
      

      如果缓冲区的类型发生变化,此代码仍然正确,当然前提是它继续具有 ARRAY_LENGTH 任何类型的元素,并且所有位为零仍然是正确的初始值。

      “C++ 不是 C”程序员钟爱的另一个选择是:

      /* never mind how buffer is allocated */
      std::fill(buffer, buffer + ARRAY_LENGTH, 0);
      

      如果您关心的话,您可以自行检查您的编译器是否将其优化为与优化对 std::memset 的等效调用的代码相同的代码。

      char *buffer = new char [ARRAY_LENGTH](); 很漂亮,但实际上在 C++ 中几乎毫无用处,因为您几乎从一开始就从未使用 new 分配数组。

      std::string buffer(ARRAY_LENGTH, 0); 介绍了一种管理缓冲区的特殊方式,这可能是也可能不是您想要的,但通常是。在某些情况下,char buffer[ARRAY_LENGTH] = {0}; 有很多话要说。

      【讨论】:

        【解决方案6】:
        • 其中任何一个都比其他的有显着优势吗?
        • 使用 1、2 或 3 会遇到哪些问题?

        第一个是错误的,因为sizeof(buffer) == sizeof(char*)

        第 2 次和第 3 次都可以。

        • 处理此请求的最佳方式是什么?

        为什么不只是:

        buffer[0] = '\0';
        

        如果这是一个char 数组,为什么还要麻烦其他字符呢?将第一个字节设置为零,您的buffer 中就有"" 的等价物。

        当然,如果您真的坚持将所有buffer 归零,请使用std::fill 的答案 - 这是正确的方法。我的意思是std::fill(buffer, buffer + ARRAY_LENGTH, 0);

        【讨论】:

          【解决方案7】:

          嗯,我个人喜欢选项 3:

          memset( buffer, '\0', ARRAY_LENGTH )
          

          ARRAY_LENGTH正是我想填入内存的东西。

          【讨论】:

            【解决方案8】:

            从 C++ 11 开始,我会选择:

            #include <array>
            
            std::array<char, ARRAY_LENGTH> buffer{ '\0' };
            
            buffer.fill('\0');
            

            【讨论】:

            • 您能详细说明原因吗?我发现它的可读性甚至比 memset() 还要低,而且您将无法使用旧编译器对其进行编译。它是否在运行时提供了一些优势?
            猜你喜欢
            • 1970-01-01
            • 2012-10-27
            • 2012-04-20
            • 1970-01-01
            • 2012-03-06
            • 2012-08-14
            • 1970-01-01
            • 1970-01-01
            • 2016-03-22
            相关资源
            最近更新 更多