vector.size() not working

Ok, I am ALMOST finished with this inventory but one last little thing is giving me problems: On line 49 I am attempting to show the number of items in my inventory. Each item consists of a number and a name. Using Names.size() worked just fine until I added i++ to the loadfile() function (line 115). How do I fix Names.size() so that if will output the correct number of elements in the vector Names, and therefore the number of items stored in my inventory? THANK YOU!! :)

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

void menuSelection(int &selection, vector<string> &Names);
void performSelection(int &selection, string &file, string &filename, int &numberInput, string &nameInput, vector<string> &Names, vector<int> &Numbers);
void listitems(vector<string> &Names, vector<int> &Numbers);
void additem(int &numberInput, string &nameInput, vector<string> &Names, vector<int> &Numbers);
void loadfile(string &filename, vector<int> &Numbers, vector<string> &Names);
int searchitems(vector<int> &Numbers, vector<string> &Names);
void saveinventory(string &file, vector<int> &Numbers, vector<string> &Names);


int main(int argc, char *argv[])
{
    int selection;
    int n;
    string file; 
    string filename;
    int numberInput; 
    string nameInput; 
    vector<string> Names; // set to 15???
    vector<int> Numbers;
    int i; 
    
    
    do 
    {
    menuSelection(selection , Names );
    performSelection(selection, file, filename, numberInput, nameInput, Names, Numbers);
    } while (selection !=0);
    
    system("PAUSE");
    return EXIT_SUCCESS;
}
 
 void menuSelection(int &selection, vector<string> &Names)
 {
      cout << "1. Load Inventory" << endl;
      cout << "2. Add Item" << endl; 
      cout << "3. Search for Item" << endl;
      cout << "4. List Items" << endl;
      cout << "5. Save Inventory" << endl;
      cout << "6. End Program" << endl;
      cout << "Number of Items in Inventory: "<< Names.size() << endl;
      cout << endl;
      cout << "Enter the number of the action you would like to do: " << endl;
      cin >> selection;   
 }

void performSelection(int &selection, string &file ,string &filename, int &numberInput, string &nameInput, vector<string> &Names, vector<int> &Numbers)
{ 
     if (selection==1)
     {
        loadfile(filename, Numbers, Names);    
     }
     
     if (selection==2)
     {
        additem(numberInput, nameInput, Names, Numbers);
     }
     
     if (selection == 3)
     {
        searchitems(Numbers, Names);             
     }
        
     if(selection == 4)
     {
        listitems(Names, Numbers);          
     }
     if (selection == 5)
     {
        saveinventory(file, Numbers, Names);              
     }
     if (selection == 6)
     {
        system ("PAUSE");
        exit (1);          
     }
}

void loadfile(string &filename, vector<int> &Numbers, vector<string> &Names)
{
        int i=0 ; 
        int temp;
        string sub;
        ifstream inputFile; 
        string line;
        cout << "Enter the filename where the inventory is stored: " << endl;
        cin >> filename;
        inputFile.open(filename.c_str()); 
          if (inputFile.fail())
        {
           cerr << "File opening failed.\n";
           system ("PAUSE");
           exit (1);    
                         
        }
        else 
        {
           cout << "The file opened" << endl;
        } 
        do
        { 
          inputFile >> temp;
          Numbers.push_back(temp);
          inputFile.ignore();
          getline(inputFile, sub);
          Names.push_back(sub);
          i++;
        } while(!inputFile.eof());
        
           
}

void additem(int &numberInput, string &nameInput, vector<string> &Names, vector<int> &Numbers)
{                  
        int i; 
        int n; 
        cout << "Enter the number of the item: "; 
        cin>> numberInput; 
        Numbers.insert(Numbers.end(), 1,  numberInput);
        cout << "Enter the name of the item: ";
        cin >> nameInput;
        Names.insert(Names.end(), 1, nameInput);


//insertion sort
        int j, val;     
        for(int i = 1; i < Numbers.size(); i++)
        {     
        val = Numbers[i];    
        j = i - 1;         
        while(j >= 0 && Numbers[j] > val)
        {               
       Numbers[j + 1] = Numbers[j];
       std::swap(Names[j], Names[j+1]);  //maintains association between vectors             
        j = j - 1;     
        }
        Numbers[j + 1] = val;  
        }
          
        
         cout << "Your sorted inventory reads: ";
        for(n = 0 ; n < Numbers.size() ; n++ )
        {
              cout << Numbers[n]<< " " << Names[n] << endl;
        }
     
}

void listitems(vector<string> &Names, vector<int> &Numbers)
{
       int k; 
        cout << "The items in the inventory are: " << endl;
        for (k = 0 ; k < Numbers.size() ; k++ )
        {
            cout << Numbers[k] << " " << Names[k] << endl;    
        }      
}

int searchitems(vector<int> &Numbers, vector<string> &Names)
{
     int searchitem;
     int middle; 
     cout << "Enter the item number you'd like to search for: ";
     cin >> searchitem; 
     //binary search   
     int lo = 0; 
     int hi = (Numbers.size() -1);
     while(lo <= hi)
     {
        middle = (lo + hi) / 2;
        if ( Numbers[middle] == searchitem)
        {
             
           cout << "The item you searched for is: Item #: "
           << Numbers[middle] << " Item Name: " << Names[middle]<< endl;  
           break;   
        }
        
        if (Numbers[middle] < searchitem)
        {
           lo = middle +1;                    
        }
     
        if (Numbers[middle] > searchitem)
        {
           hi = middle -1;                    
        }
        if((Numbers[middle] != searchitem) && (lo>hi))
        {
            cout << "Item not found" << endl;
            cout << endl;    
            break;
        }
     }  
}

void saveinventory(string &file, vector<int> &Numbers, vector<string> &Names)
{
     
    int i; 
    cout << "Enter what you would like the File Name to be: ";
    cin >> file; 
    ofstream outputFile;            
    outputFile.open(file.c_str());  
   
   for (i = 0 ; i < Numbers.size() ; i++)
   { 
       outputFile << Numbers[i] << endl;  
       outputFile << Names[i] << endl;
       
   }
   
    outputFile.close();     
}
Last edited on
What is happening?
I can pretty much guess - but if you actually tell us of the problems you are having - rather than - this is my code - it is not working - please fix it
Using Names.size() worked just fine until I added i++ to the loadfile() function (line 115).


Why did you do that? I don't see i used for any useful purpose in the loadfile function. You are simply incrementing i over and over but you never use it. It has nothing to do with the number of elements in the vector.
I don't know how to answer the original question without more detail but I do see a few things worth noting.

The following functions should receive const references to the vectors in order to avoid changing them accidentally.
saveInventory, searchItems, listItems

performSelection should be coded using if..else if... else pattern. Once a selection has been handled there is no point performing the remaining checks.

I don't see any really obvious problems but I'm sure that the std::vector::size function works fine. You need to debug the program and try different combinations of things until you can figure out how the object is being changed to have more or less elements from what you expect. I would change the listItems function to print the size of both containers. Try running the program and always list the items in between every other command and see if you can pinpoint where the object is being changed unexpectedly.
The problem is the loadInventory function but it has nothing to do with the unused i variable. It is reading the last item twice therefore a duplicate item gets inserted into each vector. I can't say that I understand why that is happening but that is the problem. I noticed that when the file is created by saveInventory you write a final endl which causes the file to have a blank line at the end. When reading the file you are looping until the EOF is reached. Since after the last item is reached there is a blankline, the loop doesn't end when you expect and for some reason the program ends up re-reading the last item again. Perhaps someone who writes these sort of file i/o problems can suggest a solution. I don't have time to fiddle with it any longer to be honest.
It isn't reading the last item twice, but it is failing once. The problem is the way the input loop is designed: it doesn't check for validity before appending items to the vectors... and failed inputs won't change the targeted item -- which still has the previous input value. Hence, the last two items are identical.

There are a number of issues with the code that I'll address in a moment. But first, the modified code:

(continued due to post size)
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
//#include <cstdlib>
#include <limits>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int  /*void*/ menuSelection(/*int &selection, vector<string> &Names*/ int inventory_size );
bool /*void*/ performSelection(int /*&*/selection, /*string &file,*/ /*string &filename,*/ /*int &numberInput, string &nameInput,*/ vector<string> &Names, vector<int> &Numbers);
void listitems(vector<string> &Names, vector<int> &Numbers);
void additem(/*int &numberInput, string &nameInput,*/ vector<string> &Names, vector<int> &Numbers);
bool /*void*/ loadfile(/*string &filename,*/ vector<int> &Numbers, vector<string> &Names);
void /*int*/ searchitems(vector<int> &Numbers, vector<string> &Names);
void saveinventory(/*string &file,*/ vector<int> &Numbers, vector<string> &Names);


int main(int argc, char *argv[])
{
    int selection;
//unused    int n;
//    string file;
//    string filename;
//    int numberInput;
//    string nameInput;
    vector<string> Names; // set to 15???
    vector<int> Numbers;
//unused    int i;

/* This is not efficient. See the following notes...
    do
    {
      menuSelection(selection , Names );
      performSelection(selection, file, filename, numberInput, nameInput, Names, Numbers);
    } while (selection !=0);
*/
    do {
      selection = menuSelection( Names.size() );
      }
    while (performSelection( selection, Names, Numbers));

//    system("PAUSE");
    cout << "Press ENTER to quit." << flush;
    cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
//    return EXIT_SUCCESS;
    return 0;
}

int readInteger()
{
  int result;

  do {
    cout << "> " << flush;

    // Read a line (terminated by ENTER) from the user
    string s;
    getline( cin, s );

    // Get rid of any trailing whitespace
    s.erase( s.find_last_not_of( " \f\n\r\t\v" ) + 1 );

    // Turn it into an integer
    istringstream ss( s );
    ss >> result;

    // Check to see that all is well
    if (ss.eof()) break;

    // Otherwise, instruct the user again
    cout << "Please enter an INTEGER number";
  } while (true);

  return result;
}

int menuSelection( int inventory_size )
{
      cout << endl;
      cout << "1. Load Inventory" << endl;
      cout << "2. Add Item" << endl;
      cout << "3. Search for Item" << endl;
      cout << "4. List Items" << endl;
      cout << "5. Save Inventory" << endl;
      cout << "6. End Program" << endl;
      cout << "Number of Items in Inventory: " << inventory_size << endl;
      cout << endl;
      cout << "Enter the number of the action you would like to do: " << endl;
//      cin >> selection;
//      cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
      return readInteger();
}

bool /*void*/ performSelection(int /*&*/selection, /*string &file,*/ /*string &filename,*/ /*int &numberInput, string &nameInput,*/ vector<string> &Names, vector<int> &Numbers)
{
     switch (selection)
     {
         case 1:
             return loadfile(/*filename,*/ Numbers, Names);

         case 2:
             additem(/*numberInput, nameInput,*/ Names, Numbers);
             break;

         case 3:
             searchitems(Numbers, Names);
             break;

         case 4:
             listitems(Names, Numbers);
             break;

         case 5:
             saveinventory(/*file,*/ Numbers, Names);
             break;

         case 6:
//             system ("PAUSE");
//             exit (1);
             return false;
     }
     return true;          
}

bool /*void*/ loadfile(/*string &filename,*/ vector<int> &Numbers, vector<string> &Names)
{
        string filename;
//not needed        int i=0 ;
//moved & renamed        int temp;
//moved & renamed        string sub;
        ifstream inputFile;
        string line;
        cout << "Enter the filename where the inventory is stored: " << endl;
//        cin >> filename;
        getline( cin, filename );  
        inputFile.open(filename.c_str());
          if (inputFile.fail())
        {
           cerr << "File opening failed.\n";
//           system ("PAUSE");
//           exit (1);
           return false;

        }
        else
        {
           cout << "The file opened" << endl;
        }

        while (inputFile)
          {
          int item_number;
          inputFile >> item_number;
          inputFile.ignore( numeric_limits <streamsize> ::max(), '\n' );
          if (!inputFile) break;

          string item_name;
          getline(inputFile, item_name);
          if (!inputFile) break;

          Numbers.push_back(item_number);
          Names.push_back(item_name);
//not needed          i++;
          }

        return true;
}

void additem(/*int &numberInput, string &nameInput,*/ vector<string> &Names, vector<int> &Numbers)
{
        int    numberInput;
        string nameInput;
//unused        int i;
//moved        int n;
        cout << "Enter the number of the item: ";
//        cin >> numberInput;
//        cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
        numberInput = readInteger();
        Numbers/*.insert(Numbers.end(), 1,  numberInput);*/.push_back(numberInput);  // use the simplest method
        cout << "Enter the name of the item: ";
//        cin >> nameInput;
        getline( cin, nameInput );
        Names/*.insert(Names.end(), 1, nameInput);*/.push_back(nameInput);


//insertion sort
        int j, val;
        for(unsigned int i = 1; i < Numbers.size(); i++)
        {
        val = Numbers[i];
        j = i - 1;
        while(j >= 0 && Numbers[j] > val)
        {
       Numbers[j + 1] = Numbers[j];
       std::swap(Names[j], Names[j+1]);  //maintains association between vectors
        j = j - 1;
        }
        Numbers[j + 1] = val;
        }


         cout << "Your sorted inventory reads: ";
        for(unsigned n = 0 ; n < Numbers.size() ; n++ )
        {
              cout << Numbers[n]<< " " << Names[n] << endl;
        }
     
}

void listitems(vector<string> &Names, vector<int> &Numbers)
{
//moved       int k;
        cout << "The items in the inventory are: " << endl;
        for (unsigned k = 0 ; k < Numbers.size() ; k++ )
        {
            cout << Numbers[k] << " " << Names[k] << endl;    
        }      
}

void /*int*/ searchitems(vector<int> &Numbers, vector<string> &Names)
{
     int searchitem;
     int middle; 
     cout << "Enter the item number you'd like to search for: ";
//     cin >> searchitem;
//     cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
     searchitem = readInteger();  
     //binary search
     int lo = 0; 
     int hi = (Numbers.size() -1);
     while(lo <= hi)
     {
        middle = (lo + hi) / 2;
        if ( Numbers[middle] == searchitem)
        {
             
           cout << "The item you searched for is: Item #: "
           << Numbers[middle] << " Item Name: " << Names[middle]<< endl;  
           break;   
        }
        
        if (Numbers[middle] < searchitem)
        {
           lo = middle +1;                    
        }
     
        if (Numbers[middle] > searchitem)
        {
           hi = middle -1;                    
        }
        if((Numbers[middle] != searchitem) && (lo>hi))
        {
            cout << "Item not found" << endl;
            cout << endl;    
            break;
        }
     }  
}

void saveinventory(/*string &file,*/ vector<int> &Numbers, vector<string> &Names)
{
    string file;  // I would have named it 'filename'
//moved    int i;
    cout << "Enter what you would like the File Name to be: ";
//    cin >> file;
    getline( cin, file );  
    ofstream outputFile;
    outputFile.open(file.c_str());

   for (unsigned i = 0 ; i < Numbers.size() ; i++)
   { 
       outputFile << Numbers[i] << endl;  
       outputFile << Names[i] << endl;
       
   }
   
    outputFile.close();     
}
First off, starting at line 1: the <cstdlib> file is only needed for three things: system(), which is evil; exit() which is also not recommended; and EXIT_SUCCESS, which I personally like but is not worth including a whole file where return 0 (lines 47-48) suffices.

As pertains to the use of system(), see lines 45-46 for the 'corrected' method. This requires the <limits> header. This correction also exposes an input design failure: don't use formatted input functions (which in C++ are the >> operator functions) when dealing with the user. Remember, the user always expects to press ENTER after every input. Your input methods should match. You'll notice that the first thing I did was go through the code and add a cin.ignore( numeric_limits <streamsize> ::max(), '\n' ); after every cin >> someinteger;. Likewise, all cin >> somestring; have been changed to getline( cin, somestring );, which is more appropriate.

However, I have added a suggested input function for reading integers from the user: see lines 51-77. Again, user input is always line-oriented. After reading the entire line, a temporary istringstream is used to read the integer, check that it worked, and complain if it didn't. Ultimately, the user must input an integer value to continue.


Next I'll touch on the changes to the function prototypes I made on lines 11-17. This all has to do with scope and visibility. As it was, many of the arguments to the functions were simply used as local variables inside the function. For example, the loadfile() function took as argument a reference to a string to use when asking the user what filename to open. Since the loadfile() function does all necessary I/O with the user and the name of the file opened is not needed elsewhere, there is no need to have the filename variable visible anywhere outside the loadfile() function. Hence, I made it a local variable and removed it from all places elsewhere. Similar changes were made with other functions. Notice also how this unclutters the main() function with unused variables: see lines 24-27.


The menuSelection() function's obvious purpose is to return the number of the user's selection. This is a good example of making things look like what they do:
y = foo();
Hence, I modified the function to work the same way.

The change to the performSelection() is similar, considering lines 39-42: it returns whether or not to stop the program. Notice also how loadfile() returns success or failure instead of simply exit()ing on failure.

This is also an important point. Before, you had three distinct exit points for the program. Don't do that. Unless there is a catastrophic failure, exit points should be consolidated as much as possible, and kept as close to main() as possible. (This is my opinion.)

The problem with multiple exit points is that duplicate code is spread around. Keep things simple and in one spot as much as is reasonable. The changes I made always return an OK code to the OS, but you can add in a failure exit if you wish.


performSelection(), lines 96-125: If you are selecting on constant integer values, avoid if..else... constructs and use a switch instead.

A change I did not make, that you should consider, is using an enumeration to name the values returned by menuSelection() and listed in the switch statement of performSelection(). This makes it easier to make changes to the menu -- you no longer have to care what the exact number is, just change the enum name and use it to your advantage in the switch.


loadfile(), lines 152-166: Here is the corrected file input. Notice how if there is any input failure at all neither the 'Numbers' nor the 'Names' vectors are modified.


All other changes should be fairly obvious. There are other things I would have done differently, but you must work through them yourself. Hopefully this is enough to get you started. (The program works correctly now, at least.)

Hope this helps.
Topic archived. No new replies allowed.