Code is meant to work, but I'm getting errors

For the past 8 weeks I have been taking an online C++ course using the community Visual Studio. During these weeks I have been able to code properly and encounter the usual errors that comes from missing one or two semicolons or brackets or mistyping a data type, etc. etc..

However, this past week we were just taught about using Classes for the first time, and I was expected to use an already generated .cpp file that should hold no errors, but requires me to add additional instructions to make it work with other files.

I have seen other users place this assignment in here, but they never encountered the problem I keep seeing on my end. My instructor has no clue why, and isn't looking to investigate further with me on what I may done wrong in my Visual Studio. Here's the .cpp code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "InventoryItem.h"

// Private member function.
void InventoryItem::createDescription(int size, char *value)
{
    // Allocate the default amount of memory for description.
    description = new char [size];

    // Store a value in the memory.
    strcpy(description, value);
}

// Constructor #1
InventoryItem::InventoryItem()
{
    // Store an empty string in the description
    // attribute.
    createDescription(DEFAULT_SIZE, "");

    // Initialize cost and units.
    cost = 0.0;
    units = 0;
}

// Constructor #2
InventoryItem::InventoryItem(char *desc)
{
    // Allocate memory and store the description.
    createDescription(strlen(desc), desc);

    // Initialize cost and units.
    cost = 0.0;
    units = 0;
}

// Constructor #3
InventoryItem::InventoryItem(char *desc, double c, int u)
{
    // Allocate memory and store the description.
    createDescription(strlen(desc), desc);

    // Assign values to cost and units.
    cost = c;
    units = u;
}

// Destructor
InventoryItem::~InventoryItem()
{
    delete [] description;
}

// Mutator functions
void InventoryItem::setDescription(char *d)
{
    strcpy(description, d);
}

void InventoryItem::setCost(double c)
{
    cost = c;
}

void InventoryItem::setUnits(int u)
{
    units = u;
}



// Accessor functions
const char *InventoryItem::getDescription() const
{
    return description;
}

double InventoryItem::getCost() const
{
    return cost;
}

int InventoryItem::getUnits() const
{
    return units;
}


And now, the .h code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef INVENTORYITEM_H
#define INVENTORYITEM_H
#include <cstring>   // Needed for strlen and strcpy

// Constant for the description's default size
const int DEFAULT_SIZE = 51;

class InventoryItem
{
private:
   char *description;  // The item description
   double cost;        // The item cost
   int units;          // Number of units on hand
   int onHand; //added according to project requirements

   // Private member function.
   void createDescription(int size, char *value);

public:
   // Constructor #1
   InventoryItem();

   // Constructor #2
   InventoryItem(char *desc);

   // Constructor #3
   InventoryItem(char *desc, double c, int u);

   // Destructor
   ~InventoryItem();

   // Mutator functions
   void setDescription(char *d);
   void setCost(double c);
   void setUnits(int u);
  // void setOnHand(int intOnHand); //added according to project requirements

   // Accessor functions
   const char *getDescription() const;
   double getCost() const;
   int getUnits() const;
  // int getOnHand() const; //added according to project requirements

};

#endif 


Both of these, at this point, are what I was supposed to do on the assignment, but I get a strange error, among other things, stating:
inventoryitem.cpp(18): error C2664: 'void InventoryItem::createDescription(int,char *)': cannot convert argument 2 from 'const char [1]' to 'char *'


Any idea what this means? Did I install Visual Studios incorrectly?
Last edited on
Your instructor has no clue why? And it's so simple! You need to make the second parameter to createDescription a const char * instead of just a char *.

 
   void createDescription(int size, const char *value);

Change it in the cpp file, too.

The problem is that "" is a constant string, so it is an error to accept it as a char *, which would allow you to modify it, although you probably wouldn't actually be able to modify it since string literals are usually stored in read-only memory.
I figured I had to change it according to the error given, but my instructor insisted that there's no need to change anything. The code is meant to be as is. Though, based on your answer, that isn't true?

So now there's another set of errors that I didn't include. I'd like to show them one at a time so as to not blow up this page with a whole lot of code on the first post.

inventoryitem.cpp(10): error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
inventoryitem.cpp(56): error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.


This I know I'm meant to use strcpy_s. I have used it before and this error goes away, but when I switched them to strcpy_s, this happens:

inventoryitem.cpp(10): error C2660: 'strcpy_s': function does not take 2 arguments
inventoryitem.cpp(56): error C2660: 'strcpy_s': function does not take 2 arguments
Well, since you've used it before you are well aware that it takes three arguments instead of just two. The middle argument is the size of the destination (the first parameter). Passing the size allows the function to ensure that the buffer does not overflow.

The createDescription function is not very well written. And the first comment in it is incorrect since it allocates however much you ask for, not the "default" amount. It only allocates that if you pass DEFAULT_SIZE. Also, it doesn't allocate enough space! It needs to allocate one more than the strlen of the value to have room for the null terminator, i.e., the '\0' that indicates the end of a C-style string. Tell your "instructor" that, too.

So it should be more like:

1
2
3
4
5
6
7
8
void InventoryItem::createDescription(int size, const char *value)
{
    // Allocate the requested amount of memory for description.
    description = new char [size + 1];

    // Store a value in the memory.
    strcpy_s(description, size + 1, value);
}


It would make a lot more sense if it just called strlen itself. That's what we would normally do in such a function.

1
2
3
4
5
6
void InventoryItem::createDescription(const char *value)
{
    size_t size = strlen(value) + 1;
    description = new char [size];
    strcpy_s(description, size, value);
}

Last edited on
I wished I had you and the community here when I was first assigned this last week, because you are able to explain this in a way that makes more sense (and more practical out in the real world) than how I'm being led by my instructor and the textbook that is from Pearson.

So, this is the part where I must include the remaining .cpp and .h files so that I can be 100% sure that nothing is being misunderstood and mistyped so that I can finally understand how these files were meant to talk to each other and run the whole darn thing from the main.cpp. Only then will I be able to actually get going with my final project with better understanding on what that is requiring me to do, but I'm just rambling now so here we go.

Here's main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "cashregister.h"
#include "InventoryItem.h"
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <string>
using namespace std;

int main()
{
	int intItem;
	double dblTax = 0.06;
	double dblCost = 0.0;
	int intUnits = 0;
	int intUnitsAvailable = 0;
    char charRunSwitch;

	const int ITEMS = 5;

    //this added all items to inventory by using constructor 3
	InventoryItem inventory[ITEMS] =
	{
		InventoryItem("Adjustable Wrench", 9.95, 10),
		InventoryItem("Screwdriver", 4.50, 20),
		InventoryItem("Pliers", 3.00, 35),
		InventoryItem("Ratchet", 9.95, 10),
		InventoryItem("Socket Wrench", 5.00, 7)
    };


    do
    {
        cout << "# \t "<<  setw(12) << "Inventory Item \t\tCost \tQty On Hand" << endl;
        cout << "---------------------------------------------------------------------------" << endl;
        for (int count = 0; count < ITEMS; count++)
        {
            cout << count + 1 << " \t";
            cout <<  setw(16) << inventory[count].getDescription() << " \t\t";
            cout << inventory[count].getCost() << " \t";
            cout << inventory[count].getUnits() << endl ;
        }

        cout << endl << "Which item above is being purchased? " << endl;
        cin >> intItem;

        while (intItem < 1 || intItem > 5) //input validation
        {
            cout << "Please enter a number within the range 1 - 5: ";
            cin >> intItem;
        }

        dblCost = inventory[intItem - 1].getCost(); //get cost of unit to be purchased
        intUnitsAvailable = inventory[intItem - 1].getUnits(); //get number of available units

        cout << "How many units? ";
        cin >> intUnits;
        while (intUnits < 0 || intUnits > intUnitsAvailable) //input validation
        {
            cout << "Please enter a valid quantity: ";
            cin >> intUnits;
        }

        inventory[intItem - 1].setUnits(intUnitsAvailable - intUnits); //adjust inventory

      //  cout << "dblcost = " << dblCost << endl; -- used for debugging


        cashregister Register(dblCost, intUnits, dblTax); //add new instance of cashregister class using constructor 2
        cout << fixed << showpoint << setprecision(2);
        cout << "Subtotal (includes 30% fee):   $" << Register.getSubTotal() << endl;
        cout << "Sales Tax:                     $" << Register.getTax() << endl;
        cout << "Total:                         $" << Register.getTotal()  << endl << endl;

		cout << "Do you wish to purchase another item? (Enter Y or N)";
		cin >> charRunSwitch;

        while (charRunSwitch != 'N' && charRunSwitch != 'n' && charRunSwitch != 'Y' && charRunSwitch != 'y') //input validation
        {
            cout << "Please enter a valid answer (Y or N): ";
            cin >> charRunSwitch;
        }

    }
    while(charRunSwitch == 'Y' or charRunSwitch == 'y' ); //check switch

	system("pause");
	return 0;
};

And here's the other .cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "cashregister.h"

cashregister::cashregister() //default constructor
{
    subTotal = 0;
    total = 0;
    tax = 0.06;
}

cashregister::cashregister(double dblCost, int intUnits, double dblTax) //constructor that accepts value during implementation
{
    subTotal =  (1.3*dblCost)*intUnits,
    tax = subTotal*dblTax;
    total = tax + subTotal;

}

//mutator functions begin
void cashregister::setSubTotal(double dblSubTotal)
{
    subTotal = dblSubTotal;
}

void cashregister::setTotal(double dblTotal)
{
    total = dblTotal;
}

void cashregister::setTax(double dblTax)
{
    tax = dblTax;
}
//mutator functions end


//begin accessor functions
double cashregister::getSubTotal() const
{
    return subTotal;
}

double cashregister::getTotal() const
{
    return total;
}

double cashregister::getTax() const
{
    return tax;
}
//end accessor functions 

And it's .h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using namespace std;

class cashregister //: public InventoryItem
{
private:
	double subTotal;
	double total;
	double tax;

public:
	cashregister();
	cashregister(double dblCost, int intUnits, double dblTax);

	void setSubTotal(double dblSubtotal);
	void setTotal(double dblTotal);
	void setTax(double dblTax);

	double getSubTotal() const;
	double getTotal() const;
	double getTax() const;
};


So, now that we have all five files here, in main, there's a problem when it's trying to create the five constructors within the object array with the following error:
main.cpp(26-30): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'InventoryItem'

Based on what you have told me so far, are they still valid enough to be kept, and now this just needs to be solved with more code changes? Again, according to my instructor, these .cpp and .h answer files are supposed to work as they are. He can compile them fine and apparently can run them without changing the createDescription function, as per your corrected suggestion. And supposedly these files have been used for several years, which quite frankly, does not give me confidence because languages and digital technology have been rapidly changing. Shutting up now so I can see what can be done.
I don't know what to say about your instructor. The char* parameter in createDescription and all the char* parameters in the InventoryItem constructors should be const char *. When you pass a C-style string to a function that doesn't modify the string, it should be declared as const char *. He is simply wrong to say they shouldn't be const. In the past compilers were more lenient and didn't complain about it. But the modern approach is to do things properly.

If they compile for your instructor then you need to ask EXACTLY how he is compiling them. Is he using a different compiler than you? What flags is he passing the compiler? Does he not realize that people may be using a different compiler?

But he is TOTALLY WRONG to suggest that the code is correct. All those char*'s should be const. If he says otherwise than he simply doesn't know what he's talking about, which our experience here shows to be VERY COMMON with "instructors" out in the wild.

BTW, there shouldn't be a semicolon after the closing brace of main (functions don't end in a semicolon).

This include in the inventory header file shouldn't be there:
#include <cstring> // Needed for strlen and strcpy
It is incorrect (or at a minimum, hidiously bad style) to include headers in a header file that are not used in that file itself. The <cstring> header should be included in the cpp file instead.

And you shouldn't say "using namespace std" in a header file (as in the cashregister header). And why is cashregister not called CashRegister? And I have no idea what the commented-out : public InventoryItem is doing there since it makes no sense for cashregister to inherit from InventoryItem makes no sense. A cach register is not an inventory item!
Wow, just wow. tpb, you have been extremely helpful. In the end, it just makes sense to use a constant at all times when the value isn't meant to change whatsoever. That's like, basic C++ 101! I feel like I've been cheated at a lot of things just for trying to understand his code.

You're also correct about the #include needed to be in the cpp file, instead of the header file. And I just read that in the book! Ugh, it's terrible to see the truth, yet believe in the lie.

I'll be honest that I've used [using namespace std] in all the prior assignments that deal with cpp and h files, just to make sure the compiler doesn't yell at me that something went wrong in my coded instructions. I should definitely stop that habit and actually use it when it's needed like a normal C++ coder such as yourself, haha.

Thank you, tpb. You're definitely the right person to answer my distress call, haha!
Topic archived. No new replies allowed.