Basically I'm trying to use an array to store inventory data, and I'm a little (lot) lost with vectors and such. I feel a little guilty asking for help three times in a day, but alas the semester is winding down and I'm in a crunch.

My class (or should I use struct?) :?::

class Inventory {
    string ItemName;
    int ItemQty;
    float ItemPrice;
};

Function to simply add an item, it's a mess because I'm trying everything I can think of:

void AddItem(vector <Inventory> *MyInventory, unsigned &key, int &i) {
    // i = number of elements in the item
    MyInventory->ItemName = "Blah";
    MyInventory[i].ItemQty = 3;
    MyInventory[i].ItemPrice = 3.50;
    i++;
    
    ClearScreen();
    UpdateScreen(key);
}

Here are my errors:

In function `void AddItem(std::vector<Inventory, std::allocator<Inventory> >*, unsigned int&, int&)': 
99 'class std::vector<Inventory, std::allocator<Inventory> >' has no member named 'ItemName' 
100 'class std::vector<Inventory, std::allocator<Inventory> >' has no member named 'ItemQty' 
101 'class std::vector<Inventory, std::allocator<Inventory> >' has no member named 'ItemPrice'
In function `void PerformFunction(unsigned int&, std::vector<Inventory, std::allocator<Inventory> >*, int&)': 
132 cannot convert `std::vector<Inventory, std::allocator<Inventory> >**' to `std::vector<Inventory, std::allocator<Inventory> >*' for argument `1' to `void AddItem(std::vector<Inventory, std::allocator<Inventory> >*, unsigned int&, int&)'

I want to add item to the next index.
So how do I accomplish this?

Lastly, I want the screen to update when an item is added - I know I'm doing it wrong, and should probably use some kind of loop, but I'm not sure of pseudocode that would work. Right now it just goes to a function, flushes the screen, and re-displays the menu but that doesn't seem correct.

Thank you for assistance with my frustrations and newbieness :icon_redface:

Full code:

#include <iostream>
#include <conio.h> // for menu selection input
#include <vector> // arrays

using namespace std;

class Inventory {
    string ItemName;
    int ItemQty;
    float ItemPrice;
};

int main() {
    vector <Inventory> MyInventory;
    int i=0;
    unsigned key;
    
    // function declarations
    void InventoryOverview();
    void MenuOptions(unsigned &key);
    void PerformFunction(unsigned &key, vector <Inventory> *, int &i);
    void ProgramTitle();
    void AddItem(vector <Inventory> *, unsigned &key, int &i);
    void ClearScreen();
    void UpdateScreen(unsigned &key);
    //
    
    i = MyInventory.size();
    ProgramTitle();
    InventoryOverview();
    MenuOptions(key);
    PerformFunction(key, &MyInventory, i);
}

// function operations
void ClearScreen() {
    system("CLS"); // using system is not good programming practice, but for the sake of this program it's needed
}

void ProgramTitle() {
    // just for prettiness
    cout << "                         [Inventory Management System]" << endl << endl;
}

void MenuOptions(unsigned &key) {
    cout << "Select an option:" << endl;
    cout << "[1] Load new inventory from file" << endl;
    cout << "[2] Load additional inventory from file" << endl;
    cout << "[3] Add item to inventory" << endl;
    cout << "[4] Save inventory" << endl;
    cout << "[5] Search inventory" << endl;
    cout << "[6] List inventory" << endl;
    cout << "[0] Exit";
    
    // loop until correct key is inputted
    do {
        key = getch();
    } while(key < 48 || key > 54);
}

void InventoryOverview() {
    cout << "Inventory items: 0" << endl;
    cout << "Inventory value: $0.00" << endl << endl;
}

void UpdateScreen(unsigned &key) {
    ProgramTitle();
    InventoryOverview();
    MenuOptions(key);
}

void NewInventoryFromFile() {
}

void AddInventoryFromFile() {
}

void AddItem(vector <Inventory> *MyInventory, unsigned &key, int &i) {
    // i = number of elements in the item
    MyInventory->ItemName = "Blah";
    MyInventory[i].ItemQty = 3;
    MyInventory[i].ItemPrice = 3.50;
    i++;
    
    ClearScreen();
    UpdateScreen(key);
}

void SaveInventory() {
}

void SearchInventory() {
}

void ListInventory() {
}

void PerformFunction(unsigned &key, vector <Inventory> *MyInventory, int &i) {
    if(key == 48) { // 0
        //cout << "Exit";
        exit(1);
    }
    else if(key == 49) { // 1
        //cout << "New inventory from file";
        NewInventoryFromFile();
    }
    else if(key == 50) { // 2
        //cout << "Load additional inventory from file";
        AddInventoryFromFile();
    }
    else if(key == 51) { // 3
        //cout << "Add item to inventory";
        AddItem(&MyInventory, key, &i);
    }
    else if(key == 52) { // 4
        //cout << "Save inventory";
        SaveInventory();
    }
    else if(key == 53) { // 5
        //cout << "Search inventory";
        SearchInventory();
    }
    else if(key == 54) { // 6
        //cout << "List inventory";
        ListInventory();
    }
}

This is what I noticed when quickly going through your code.

void AddItem(vector <Inventory> &MyInventory, unsigned &key, int &i) { //change it to &MyInventory instead of *MyInventory since you are going to be changing it like the variable i
//this means just pass it in normally and not by reference
// i = number of elements in the item
	MyInventory[i].ItemName = "Blah";
	MyInventory[i].ItemQty = 3;
	MyInventory[i].ItemPrice = 3.50;
	i++;

	ClearScreen();
	UpdateScreen(key);
}

Edited 6 Years Ago by sfuo: Didnt test before posting but went back and changed it so it should work

This is what I noticed when quickly going through your code.

void AddItem(vector <Inventory> &MyInventory, unsigned &key, int &i) { //change it to &MyInventory instead of *MyInventory since you are going to be changing it like the variable i
//this means just pass it in normally and not by reference
// i = number of elements in the item
	MyInventory[i].ItemName = "Blah";
	MyInventory[i].ItemQty = 3;
	MyInventory[i].ItemPrice = 3.50;
	i++;

	ClearScreen();
	UpdateScreen(key);
}

*cough* You're still passing by reference ;)

** Here's a bit of an explanation **

In the OP's code, they are passing a pointer to the object.
Pretend that the numbers below are memory blocks.

|1|2|3|4|5|6|

I create a new Object (denoted by Obj)

|Obj|Obj|Obj|4|5|6|

Obj's start address is "1". So if I do Obj.Add(someVal); the program knows to go to address "1" to find the object data.

When I create a pointer to the Obj object (denoted by ptr) I'm doing the following:

|Obj|Obj|Obj|ptr|5|6|
  ^-----------|

So ptr at address "4" now contains the value "address 1".

So when I go ptr->Add(someVal); the program goes to memory address 4 (where my pointer is stored) to find out where my "Obj" object is. The program see's it contains "address 1" and looks at address "1" for the object data.

When you pass by Pointer: MyMethod(MyObject *ptrObj) you're passing it a pointer address. If I ran the code as follows:

{
   MyObject Obj;
   MyObject* ptr = &Obj;
   MyMethod(ptr);
}

What I've actually done is given it the value in address "4". This is good when you want to save on passing large data structures around in memory. It also allows you to change what is being pointed at (although arguably this is almost always bad).

When you pass by reference you're actually passing the address location of the object.

To pass by reference you use ampersand and not star. MyMethod(MyObject &tempObj) When you use a reference, the program automatically de-references it when you use it in your methods.
So...

{
   int x = 10;
   int& refX = x; // I have just set refX to the address of x

   refX = 20;
   cout << x;
}

The above code will print out 20.

If we did the same using pointers...

{
   int x = 10;
   int* ptrX = &x; // Set the pointer refX to the address of x

   ptrX = 20;
   cout << x;
}

This would print out 10. However! The important part to note here is that ptrX now points to the memory address 20 and NOT to the address of our x variable.

In order to directly access the x variable, we would need to "de-reference" it. Which is done as follows:

{
   int x = 10;
   int* ptrX = &x;

   (*ptrX) = 20;
   cout << x;
}

Would print out 20.

That's pretty much the main difference between pointers and references.

I hope this has been educational for you :)

Edited 6 Years Ago by Ketsuekiame: Added tutorial on pointers and references

>>My class (or should I use struct?)
Well classes and structs are essentially the same in C++, the only difference really is that by default all data members declared in a class are private, while the default for struct is public. So in your code, you won't be able to access the members of Inventory, you need to do either one of these options:

class Inventory {
  public: //make data members public.
    string ItemName;
    int ItemQty;
    float ItemPrice;
};

struct Inventory { //change to struct, and data members will be public by default.
    string ItemName;
    int ItemQty;
    float ItemPrice;
};

Then as sfuo said, pass the vector by reference and not by pointer, that should get you going further towards solving your problems with this code.

Edited 6 Years Ago by mike_2000_17: n/a

class Item  {
    std::string ItemName;
    int ItemQty;
    float ItemPrice;
  public:
    Item (std::string Itnm,int Itqt,float Itpr) :
       ItemName(Itnm), ItemQty(Itqt), ItemPrice(Itpr)  {}
    Item () {}
    void Display()  {
            std::cout << ItemName << "\t" << ItemQty << "\t" << ItemPrice << "\n";
         }
    std::string Name() { return ItemName;}

    Item& Stash(Item duplicate)  {
        (*this).ItemQty+=duplicate.ItemQty;
        return *this;
      }
   };

class Inventory  {
    std::vector<Item> inventory;
    std::vector<Item>::iterator i;
  public:
    void AddItem (Item I)  {
        bool exist=false;
        for (i=inventory.begin();i!=inventory.end();++i)  {
           if ((*i).Name()==I.Name()) {
               (*i).Stash(I);
               exist=true;
             }
          }        
        if (!exist) inventory.push_back(I);
        if (!inventory.size()) inventory.push_back(I);
                
      }
    void Enum()  {
        for (Item* p=inventory.begin();p!=inventory.end();++p)
           (*p).Display();
         }
    Item LocateItem(std::string it)  {
        for (i=inventory.begin();i!=inventory.end();++i)  {
                if ((*i).Name()==it) break;
              }
           return (inventory.size()) ? *i : Item();
      }
    int Size() { return inventory.size();}
    operator std::vector<Item> () {return inventory;}
   };

Thank you mike and Ketsuekiame(that was the best pointer/reference explanation ever) and caut baia.

The scope of the example provided by caut baia is beyond me and I wasn't sure how to accurately implement it?
I tried a simple example but couldn't get it to go, any help would be appreciated:

Error generated:

In member function `void Inventory::Enum()': 
46 cannot convert `__gnu_cxx::__normal_iterator<Item*, std::vector<Item, std::allocator<Item> > >' to `Item*' in initialization 
46 no match for 'operator!=' in 'p != ((std::vector<Item, std::allocator<Item> >*)this)->std::vector<_Tp, _Alloc>::end [with _Tp = Item, _Alloc = std::allocator<Item>]()'
#include <iostream>
#include <vector>

using namespace std;


// class
class Item  {
    std::string ItemName;
    int ItemQty;
    float ItemPrice;
  public:
    Item (std::string Itnm,int Itqt,float Itpr) :
       ItemName(Itnm), ItemQty(Itqt), ItemPrice(Itpr)  {}
    Item () {}
    void Display()  {
            std::cout << ItemName << "\t" << ItemQty << "\t" << ItemPrice << "\n";
         }
    std::string Name() { return ItemName;}

    Item& Stash(Item duplicate)  {
        (*this).ItemQty+=duplicate.ItemQty;
        return *this;
      }
   };

class Inventory  {
    std::vector<Item> inventory;
    std::vector<Item>::iterator i;
  public:
    void AddItem (Item I)  {
        bool exist=false;
        for (i=inventory.begin();i!=inventory.end();++i)  {
           if ((*i).Name()==I.Name()) {
               (*i).Stash(I);
               exist=true;
             }
          }        
        if (!exist) inventory.push_back(I);
        if (!inventory.size()) inventory.push_back(I);
                
      }
    void Enum()  {
        for (Item* p=inventory.begin();p!=inventory.end();++p)
           (*p).Display();
         }
    Item LocateItem(std::string it)  {
        for (i=inventory.begin();i!=inventory.end();++i)  {
                if ((*i).Name()==it) break;
              }
           return (inventory.size()) ? *i : Item();
      }
    int Size() { return inventory.size();}
    operator std::vector<Item> () {return inventory;}
   };
//

int main() {
    Inventory MyInventory;
}

I can't believe I made it this far along in my semester (this is one of the final projects), but I had to do it all without a book and only Google/Daniweb so forgive me for shortcomings.
Thanks a ton!

Edited 6 Years Ago by rObOtcOmpute: n/a

int main ()  {
   Inventory Inv;
   Item whiskey("Red Label",15,20);
   Inv.AddItem(whiskey);
   Inv.Enum();
 }

When I run the compiler I still get these errors:

In member function `void Inventory::Enum()': 
46 cannot convert `__gnu_cxx::__normal_iterator<Item*, std::vector<Item, std::allocator<Item> > >' to `Item*' in initialization 
46 no match for 'operator!=' in 'p != ((std::vector<Item, std::allocator<Item> >*)this)->std::vector<_Tp, _Alloc>::end [with _Tp = Item, _Alloc = std::allocator<Item>]()'

and points to this line:

for (Item* p=inventory.begin();p!=inventory.end();++p)

Is it my compiler? I'm using Dev C++.

Change that line to

for (std::vector<Item>::iterator p=inventory.begin();p!=inventory.end();++p)

What i did is not really portable but using a stl iterator is.

As caut_baia pointed out you need to use an iterator which he's shown you how to do.

Notice in the code you've already declared an iterator as "i". Which is why the other methods aren't throwing errors.

Personally I wouldn't use class wide iterators, but there's no reason in this code that you can't. Simply change your "p"'s to "i"'s and it will run.

This article has been dead for over six months. Start a new discussion instead.