【问题标题】:What is the best way of clearing a char array in C/C++?在 C/C++ 中清除 char 数组的最佳方法是什么?
【发布时间】:2018-02-09 16:05:22
【问题描述】:

我一直在寻找在 C/C++ 中清空 char 数组的方法。我想出了这个代码:

char testName[20];   

for(int i = 0; i < sizeof(testName); ++i)
{
  testName[i] = (char)0;
}  

它已经工作了一段时间,但是当我尝试strlen时,结果总是比输入的单词多两个。例如,我输入单词dog,输出将是五个。为什么呢?我的 char 数组没有被清除吗?

这是我的代码:

char testName[20];
void loop()
{
  if(Serial.available())
  {
    Serial.println("Waiting for name...");
    index = 0;
    for(int i = 0; i < sizeof(testName); ++i)
    {
        testName[i] = (char)0;
    }
    while(Serial.available())
    {
      char character = Serial.read();
      testName[index] = character;
      index++;
    }
    Serial.print("Name received: ");
    Serial.println(testName);
    Serial.print("The sentence entered is ");
    Serial.print(strlen(testName));
    Serial.println(" long");
    delay(1000);
  } 
  delay(1000);
}

输出截图:

输出为文本:

Name received: dog

The sentence entered is 5 characters long

【问题讨论】:

  • 你确定你没有在输入的最后得到\r\n吗?
  • 最好的办法是根本不使用 char 数组。而是使用 std::string.
  • 阅读memset的文档。
  • @manni66 因为你的建议完全错误。
  • @manni66,没有。字符数组通常比std::string 更合适。另外,你的语言不好。

标签: c++ c arrays


【解决方案1】:

不要在现代 C++ 中使用 C 风格的数组。当您需要一个固定大小的数组时,请改用std::array。从内存存储的角度来看,它们是相同的。

然后您可以使用以下命令清除数组:myarray.fill('\0')

【讨论】:

    【解决方案2】:

    如果您对“清空字符数组”的定义是将数组的所有元素设置为零,则可以使用std::memset。

    这将允许你写这个而不是你的清晰循环:

    const size_t arraySize = 20;  // Avoid magic numbers!
    char testName[arraySize];
    memset(&(testName[0]), 0, arraySize);
    

    至于strlen()的“奇怪”结果:

    strlen(str) 返回"(...) str 指向的字符数组中第一个元素指向的字符数,不包括第一个空字符"。这意味着,它将计数字符,直到找到零为止。

    检查您传递给strlen() 的字符串的内容 - 那里可能有从输入流中读取的白色字符(例如\r 或\n)。

    另外,一个建议 - 考虑使用 std::string 而不是普通的 char 数组。


    小记:memset() 通常针对高性能进行了优化。如果这不是您的要求,您也可以使用std::fill,这是一种更像 C++ 的方式来填充任何数组:

    char testName[arraySize];
    std::fill(std::begin(testName), std::end(testName), '\0');
    

    std::begin()(和std::end)适用于编译时大小的数组。


    另外,为了回答@SergeyA 的评论,我建议阅读this SO post 和this answer。

    【讨论】:

    • @SergeyA 我已经用std::fill 版本更新了我的答案。但是std::memset由于其优化的实现而经常被使用,所以绝对应该提到它。我建议使用std::string,但由于我们这里有一个带有纯char 数组的代码,所以恕我直言,memset 的错误使用是最不值得关注的。
    • std::fill 不能被优化掉; memset 可以。我很确定 memset 也被允许一次写入大于一个字节的块;而 std::fill 不是。
    • @SergeyA 当任务是设置 C 风格 char 数组的内容时,我绝不会责怪提出 memset 的人。
    • @SergeyA 因为允许和“这个编译器做或不做”是不同的;尤其是当它没有
    • @MichaelWalz 和 std::fill 要么专门将 memset 用于 POD 类型,要么优化器在识别模式时动态生成优化代码。
    【解决方案3】:

    另一种用零填充数组的快速方法,仅在初始化时:

    char testName[20] = {};
    

    一样

    char testName[20] = {0};
    

    由于它是 C99 功能,编译器可能会抱怨以下内容

    warning: ISO C forbids empty initializer braces
    

    更多here.

    不管怎样,看 OP 代码,根本不需要初始化/填充数组,最好这样:

    #define MAX_LENGTH 20
    char testName[MAX_LENGTH];
    void loop()
    {
      if(Serial.available())
      {
        Serial.println("Waiting for name...");
        index = 0;
        while(Serial.available())
        {
          if(index < MAX_LENGTH) 
              testName[index++] = Serial.read();
        }
        if(index < MAX_LENGTH)
        {
          testName[index] = 0;
          Serial.print("Name received: ");
          Serial.println(testName);
          Serial.print("The sentence entered is ");
          Serial.print(strlen(testName));
          Serial.println(" long");
        }
        else
          Serial.print("Name too long ...");
    
        delay(1000);
      } 
      delay(1000);
    } 
    

    【讨论】:

    • 只擅长定义。不能在其他地方使用。
    • 您不能以这种方式“清除”现有的零数组。
    • 我会删除这个答案,这真的毫无意义,因为 OP 显然想在他的循环中填充数组。
    • 问题说:emptying a char array in C++,代码明确表明需要对已经存在的数组执行clear,这个答案的第一句话是:"(...) 用零填充数组的快速方法,仅在初始化时"...
    • 我认为我的答案符合 OP 的需要,因为发布的代码,而不是问题。
    猜你喜欢
    • 2010-12-16
    • 2010-10-17
    • 2010-09-08
    • 1970-01-01
    • 2010-10-12
    • 2010-09-22
    • 1970-01-01
    • 2020-08-11
    • 2010-09-05
    相关资源
    最近更新 更多