What is wrong with strncpy_s() here?

Stats Cruncher picture Stats Cruncher · Aug 23, 2016 · Viewed 10.3k times · Source

I am reading my a textbook and trying to solve the question given to readers.

The fallowing code is function definition from my source file of my answer.

I want to copy content of character strings to another ones.

I chose functions strncpy_s().

But it does not work.

Microsoft Visual Studio says Debug Assertion Failed!

I have no idea how to fix it.

cow.h

// class declarations

#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

// class methods

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;
  }

Answer

Ari0nhh picture Ari0nhh · Aug 23, 2016

From strncpy_s documentation:

These functions try to copy the first D characters of strSource to strDest, where D is the lesser of count and the length of strSource. If those D characters will fit within strDest (whose size is given as numberOfElements) and still leave room for a null terminator, then those characters are copied and a terminating null is appended; otherwise, strDest[0] is set to the null character and the invalid parameter handler is invoked, as described in Parameter Validation.

Lets consider your code:

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

Second argument of strcpy_s is a size of buffer in characters. Fourth - number of characters copied. Since you are passing the same len variable, strcpy_s detects, that buffer has insufficient size (because there should be a space for the trailing \0) and invokes invalid parameters handler. This works correctly:

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

Check other places where you are using strncpy_s for this error. Also it is a good idea to actually read text in the debug assertion windows. In this case error source is pretty straightforward:

debug assertion failed