2

I am reading 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;
  }
Stats Cruncher
  • 155
  • 1
  • 1
  • 6

2 Answers2

6

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

Ari0nhh
  • 5,720
  • 3
  • 28
  • 33
  • Finally, this project works. It spend me a few days. sigh – Stats Cruncher Aug 23 '16 at 11:44
  • I want to add one question that debug assertion window does not inform users which line where (L"Buffer is too small" && 0) happens. – Stats Cruncher Aug 23 '16 at 11:49
  • @user9418 It does. Press `Retry` button when debugger is attached and it will show you the line with error. – Ari0nhh Aug 23 '16 at 11:51
  • So far I read code line by line and enter into "Go to definition" by right click. Should I look up other textbooks for more information on strncpy_s()? – Stats Cruncher Aug 23 '16 at 11:59
  • I did what you say. Click retry button. Then the other small window jumps out. It says something like "stop operating" without showing where the line with error. I am using MVS(English version) but my OS is not of English version, So I am not sure what exact meaning of words in that small window. – Stats Cruncher Aug 23 '16 at 12:07
  • Thanks for your time and having patience. – Stats Cruncher Aug 23 '16 at 15:51
  • Note that the final code here offers no additional "safety" over just calling `strcpy`. You already know that the buffer is big enough, because you created it that way. – Pete Becker Aug 23 '16 at 16:31
  • One weird thing is that the assertion is also thrown in Release builds. Any idea how to disable that? Release build should have a runtime error thrown instead – Paani Nov 30 '22 at 17:34
1
int len = std::strlen(nm);
strncpy_s(name, len, nm, len);

First, the second line should use len + 1 instead of len. And second, it should use strcpy instead of strncpy_s.

Calculating the length of the source (strlen(nm)) doesn't provide any information about the size of the target buffer (name). And since there is no information about the size of the target buffer, restricting the number of characters to copy is meaningless. So don't do all that wheel-spinning. Just copy the string:

strcpy(name, nm);
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Yes, both strcpy() and strncpy() are taught by my textbook. But I am using Visual Studio to write code. Visual Studio says they are unsafe. So I choose strncpy(). Still I would like to say thank you for your time. – Stats Cruncher Aug 23 '16 at 15:47
  • The use of `strncpy_s` in the code example is also "unsafe", in exactly the same way as `strcpy` would be. This is the problem with just about every use of `strncpy` that I've seen on SO: it's used wrong, because whoever wrote the code didn't think enough about the problem that they were trying to solve, and simply chose a function because it was labelled "safe". It's on "safe" if it's used correctly. – Pete Becker Aug 23 '16 at 15:52
  • Thanks you. Actually I am taking baby steps in the direction of C++. Your words encourage me a lot. – Stats Cruncher Aug 23 '16 at 16:26