【问题标题】:What is wrong with strncpy_s() here?strncpy_s() 这里有什么问题?
【发布时间】:2016-08-23 05:04:36
【问题描述】:

我正在阅读我的教科书并试图解决给读者的问题。

下面的代码是我的答案源文件中的函数定义。

我想将字符串的内容复制到另一个字符串。

我选择了函数 strncpy_s()。

但它不起作用。

Microsoft Visual Studio 说调试断言失败!

我不知道如何解决它。

牛.h

// 类声明

#include <iostream>
#ifndef COW_H_
#define COW_H_

class Cow {
char name[20];
char * hobby;
double weight;
public:
Cow();
Cow(const char * nm, const char * ho, double wt);
Cow(const Cow & c);
~Cow();
Cow & operator=(const Cow & c);
void ShowCow() const;  // display all cow data   
}; 
#endif

cow.cpp

// 类方法

Cow::Cow(const char * nm, const char * ho, double wt)
{
    int len = std::strlen(nm);
    strncpy_s(name, len, nm, len);
    name[19] = '\0';

    len = std::strlen(ho);
    hobby = new char[len + 1];
    strncpy_s(hobby, len, ho, len);
    hobby[len] = '\0';

    weight = wt;
}

Cow::Cow()
{
    strncpy_s(name, 19, "no name", 19);
    name[19] = '\0';

    int len = std::strlen("no hobby");
    hobby = new char[len + 1];
    strncpy_s(hobby, len, "no hobby", len);
    hobby[len] = '\0';

    weight = 0.0;
}

Cow::Cow(const Cow & c)
{
    int len = std::strlen(c.name);
    strncpy_s(name, len, c.name, len);
    name[19] = '\0';

    len = std::strlen(c.hobby);
    hobby = new char[len + 1];
    strncpy_s(hobby, len, c.hobby, len);
    hobby[len] = '\0';

    weight = c.weight;
}

Cow::~Cow()
{
    delete [] hobby;
}

Cow & Cow::operator=(const Cow & c)
{
    if (this == &c)
        return * this;

    delete [] hobby;

    int len = std::strlen(c.name);
    strncpy_s(name, len, c.name, len);
    name[19] = '\0';

    len = std::strlen(c.hobby);
    hobby = new char[len + 1];
    strncpy_s(hobby, len, c.hobby, len);
    hobby[len] = '\0';

    weight = c.weight;
    return * this;
}

void Cow::ShowCow() const
{
    cout << name << ", " << hobby << ", " << weight << endl;  
}

usecow.cpp

  #include <iostream>
  #include "cow.h"


  int main()
  {
      Cow Japan;
      Japan.ShowCow();

      Cow America("Aspen", "Swim", 307.45);
      America.ShowCow();

      return 0;
  }

【问题讨论】:

  • 请在您使用Cow 类的地方添加代码。
  • 您是否检查了您传递的参数与手册所说的需要什么?在一个地方您只传递3 参数,但在另一个地方您将4 参数传递给strncpy_s
  • @Ari0nhh 是的,我刚刚添加了usecow.cpp。
  • @Galik 我认为 strncpy_s() 在这些方面是一个重载函数。

标签: c++ strncpy


【解决方案1】:

来自strncpy_sdocumentation

这些函数尝试将 strSource 的前 D 个字符复制到 strDest,其中 D 是计数和 strSource 长度中的较小值。 如果这些 D 字符适合 strDest (其大小为 numberOfElements) 并且仍然为空终止符留出空间,然后 这些字符被复制并附加一个终止的空值; 否则,strDest[0] 设置为空字符并且无效 调用参数处理程序,如参数验证中所述。

让我们考虑一下您的代码:

int len = std::strlen("no hobby");
hobby = new char[len + 1];
strncpy_s(hobby, len, "no hobby", len);

strcpy_s 的第二个参数是以字符为单位的缓冲区大小。第四 - 复制的字符数。由于您传递了相同的len 变量,strcpy_s 检测到该缓冲区的大小不足(因为尾随\0 应该有空间)并调用无效参数处理程序。这可以正常工作:

int len = std::strlen("no hobby");
hobby = new char[len + 1];
strncpy_s(hobby, len+1, "no hobby", len);

检查您使用strncpy_s 的其他地方是否存在此错误。 在调试断言窗口中实际读取文本也是一个好主意。在这种情况下,错误来源非常简单:

【讨论】:

  • 终于,这个项目成功了。我花了几天时间。叹息
  • 我想补充一个问题,调试断言窗口不会通知用户 (L"Buffer is too small" && 0) 发生在哪一行。
  • @user9418 确实如此。附加调试器后按Retry按钮,它将显示错误行。
  • 到目前为止,我逐行阅读代码并通过右键单击进入“转到定义”。我应该查找其他教科书以获取有关 strncpy_s() 的更多信息吗?
  • 我照你说的做了。单击重试按钮。然后另一个小窗口跳了出来。它说诸如“停止操作”之类的内容,但没有显示错误所在的行。我正在使用 MVS(英文版),但我的操作系统不是英文版,所以我不确定那个小窗口中单词的确切含义。
【解决方案2】:
int len = std::strlen(nm);
strncpy_s(name, len, nm, len);

首先,第二行应该使用len + 1 而不是len。其次,它应该使用strcpy 而不是strncpy_s

计算源 (strlen(nm)) 的长度不会提供有关目标缓冲区 (name) 大小的任何信息。而且由于没有关于目标缓冲区大小的信息,限制要复制的字符数是没有意义的。所以不要做所有的车轮旋转。只需复制字符串:

strcpy(name, nm);

【讨论】:

  • 是的,strcpy() 和 strncpy() 都是由我的教科书教授的。但我正在使用 Visual Studio 编写代码。 Visual Studio 说它们不安全。所以我选择strncpy()。不过,我还是要感谢您的宝贵时间。
  • 在代码示例中使用strncpy_s 也是“不安全的”,与strcpy 的使用方式完全相同。这就是我在 SO 上看到的几乎每次使用 strncpy 的问题:使用错误,因为编写代码的人没有充分考虑他们试图解决的问题,只是选择了一个函数因为它被标记为“安全”。如果使用正确,它就处于“安全”状态。
  • 谢谢。实际上,我正在朝着 C++ 的方向迈出一小步。你的话给了我很多鼓励。
猜你喜欢
  • 1970-01-01
  • 2021-10-03
  • 2011-01-22
  • 2016-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多