Accessing C++ Vector as number - c++

So basically I am trying to have a list of games, and give the user the option to delete it. It looks something like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
//setup
vector<string> games;
games.push_back("Team Fortress 2");
games.push_back("Skyrim");
games.push_back("Portal");
vector<string>::iterator myIterator
//main
int delItem;
cin >> delItem; // Consumes a number to represent the game to be deleted
while (iter != games.end()) // Displays all the games
{
cout << j << ") " << *iter << endl;
iter++;
j++;
}
while ((delItem <= games.begin()) || (delItem > games.end())) // can only be 1, 2, or 3
{
cout << "\nThat input is incorrect. Please try again: ";
getline (cin, delItem);
}
myIterator = (games.begin() + (delItem - 1);
games.erase(myIterator); // Deletes the item
cout << "\nThe game has been deleted.";
return 0;
}
So when I display the list, it looks like this:
1) Team Fortress 2
2) Skyrim
3) Portal
A user can type the number preceding the game and that will be selected to delete it. What I am trying to do, is to prevent the user from enter a number higher or lower than those three numbers. I attempt this in the second while loop, but it looks like games.begin() is not a number. I know that this is probably a dumb mistake that I just barely missed, but any help would be great.

There are several problems with your code.
You are reading the user's input before you have even printed out the available options for the user to choose from. You need to reverse those operations.
You are using variables that have not been declared.
When the user enters an invalid number, you are calling std::getline() to get a new number, but std::getline() outputs to a std::string, not to an int.
Try something more like this instead:
#include <iostream>
#include <string>
#include <vector>
#include <limits>
using namespace std;
int main()
{
//setup
vector<string> games;
games.push_back("Team Fortress 2");
games.push_back("Skyrim");
games.push_back("Portal");
vector<string>::iterator myIterator;
//main
int j = 1;
for (myIterator = games.begin(); myIterator != games.end(); ++myIterator) // Displays all the games
{
cout << j << ") " << *myIterator << endl;
++j;
}
cout << "\nPick an item to delete: ";
int delItem;
do
{
if (cin >> delItem) // Consumes a number to represent the game to be deleted
{
if ((delItem >= 1) && (delItem <= games.size())) // can only be 1, 2, or 3
break;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin.clear();
cout << "\nThat input is incorrect. Please try again: ";
}
while (true);
/*
alternatively:
int delItem;
do
{
string line;
if (!getline(cin, line)) {
// error!
return 0;
}
istringstream iss(line);
if (iss >> delItem) // Consumes a number to represent the game to be deleted
{
if ((delItem >= 1) && (delItem <= games.size())) // can only be 1, 2, or 3
break;
}
cout << "\nThat input is incorrect. Please try again: ";
}
while (true);
*/
myIterator = games.begin() + (delItem - 1);
games.erase(myIterator); // Deletes the item
cout << "\nThe game has been deleted.";
return 0;
}

You are right that games.begin() is not a number. It's an iterator. However, you can use games.size() to determine the number of elements in the games vector. You can use this for the maximum number which the user can type. From what I can tell, the minimum number will always be the same. I leave it as an exercise for the reader to determine what it is.

Related

C++ Loop for String

I am struggling to create a loop for getting input from user. The input must push_back() each instance.
#include <iostream>
#include <array>
#include <cstring>
#include <vector>
#include <string>
#include <string.h>
using namespace std;
int main()
{
vector <string> bookQ = { "what","book","is","that","you","are","reading" };
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
string input;
int x = 0;
for (x != '1') { // require a loop to input string and end when user prompts
cout << "Enter 1 to stop" << endl; //
cin >> x; //
getline(cin, input); //
bookQ.push_back(input); //
} //
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}
Your for loop is missing the declaration and (iteration) expression parts:
for (declaration-or-expression; declaration-or-expression; expression)
so it should have looked like this:
for (;x != '1';) {
which is generally written as
while (x != '1') {
That would cause problems though since it would not stop directly when the user entered 1.
You are also comparing an int with a char ('1'), so in order to exit the loop, the user would have had to enter 49 (the ASCII value for 1), not 1.
You are also mixing formatted input (cin >> x) with unformatted input (getline). I suggest that you stick to one only.
Example:
while(cout << "Enter 1 to stop\n", getline(cin, input) && input != "1") {
bookQ.push_back(input);
}
Assuming you meant that input is a string, then you've made a few mistakes with types. First of all, you've used wrong type for variable x, you used int which is integer type, and the type string is required. Secondly, when comparing x with '1' you used single quotes, which define the type of variable as char, not string. To make 1 a string you should use double quotes, like so "1". Besides that, you have used for(condition), which is incorrect syntax. You should use while(condition). Also, when your loop iterates, the x variable is the input book name, and input variable is always an empty string, so I would suggest replace input with x everywhere. The working code is below.
P.S. I am not sure whether you want "1" to be in the final vector, so I haven't changed that
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<string> bookQ = {"what", "book", "is", "that", "you", "are", "reading"};
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
string input;
string x;
while (x != "1") {
cout << "Enter 1 to stop" << endl;
cin >> x;
bookQ.push_back(x);
}
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}
simply check if input is 1 everytime the user enters somthing, and when it does = 1, simply break loop.
string x;
while (true) { // require a loop to input string and end when user prompts
cout << "Enter 1 to stop" << endl;
cin >> x;
if (x == "1"){
break;
}
getline(cin, x);
bookQ.push_back(x);
}
}
First, your for syntax is wrong. You want a while loop instead, or in this case a do..while loop would make more sense. Also, you are pushing the user's input into the vector before validating what the input actually is.
Second, x is an integer, but '1' is a character whose ASCII value is number 49. Your loop will never end, because != will always be true. Since you want the user to enter number 1 to stop the loop, you need to drop the quotes:
Third, what is the point of pre-populating bookQ? Just declare the bookQ without any initial data, and then cout the entire question as a normal string. This way, after the user is done entering input, the vector will contain only the user's input and nothing else.
Try something more like this:
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
using namespace std;
int main()
{
vector <string> bookQ;
string input;
cout << "what book is that you are reading" << endl;
do {
cout << "Enter a book, or 1 to stop" << endl;
getline(cin >> ws, input);
if (input == "1") break;
bookQ.push_back(input);
}
while (true);
for (size_t i = 0; i < bookQ.size(); ++i) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}

Having problem in working with insert, delete and search in an string array at the same time

I was trying to implement insert, delete and linear search in an string type array in the same code. Delete and Linear search works fine here, but insertion is not running perfectly.
Here is the main function of my code.
#include<iostream>
#include <stdlib.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
int main(int argc, char ** argv)
{
int siz;
cout<<"How many elements:";
cin>>siz;
string student[siz];
for(int i=0; i<siz; i++)
{
cin>>student[i];
}
cout<<"Array:";
for(int i=0; i<siz; i++)
cout<<student[i]<<endl;
int choice;
cout <<"Enter your choice :";
cin>>choice;
switch(choice)
{
case 0:
exit(0);
break;
case 1:
st_insert(student,siz);
break;
case 2:
st_delete(student,siz);
break;
case 3:
st_search(student,siz);
break;
case 4:
cout<<"All elements\n:";
for(int i=0; i<siz; i++)
cout<<student[i]<<endl;
break;
default:
cout<<"Wrong choice please try again !!!";
}
return 0;
}
The insert function is
void st_insert(string demo[], int siz)
{
int pos;
cout<<"Enter a position number to insert:";
cin>>pos;
string item;
cout<<"Enter a new Element :";
cin>>item;
cout<<"After Inserting "<<item<<", the updated list is: "<<endl;
for (int i=siz-1; i>=pos; i--)
{
demo[i+1] = demo[i];
}
demo[pos] = item;
for (int i=0; i<siz+1; i++)
cout<<"\t"<<demo[i]<<endl;
}
Sample Output if I want to insert an item
Yes, there is a solution. Don't use non-standard VLAs and don't use Plain-Old Arrays that provide no bounds checking. The solution is to use a vector of strings, e.g. std::vector<std::string>. That way you can add or replace any element you like and the memory is handled automatically.
For example, let's just take a vector of strings initialized with four strings:
std::vector<std::string> student { "my", "dog", "has", "fleas" };
Now student.size() will tell you how many strings are contained in the vector and you can replace (with bounds checking) with student.at(pos) = "new string";
You can list all elements in your vector using a range-based for loop, e.g.
std::cout << "Array:\n\n";
for (const auto& s : student)
std::cout << s << '\n';
Since the vector of strings student contains all the information you will need to either replace an existing element or add a new element at the end, your function (which must be of a type to indicate success/failure of the operation) could be written to take a single parameter -- a reference to your vector of strings, e.g.:
bool st_insert(std::vector<std::string>& demo)
{
size_t pos;
std::string item {};
std::cout << "Enter a position number to insert: ";
if (!(std::cin >> pos))
return false;
std::cout << "Enter a new Element: ";
if (!(std::cin >> item))
return false;
if (pos >= demo.size())
demo.push_back(item);
else
demo.at(pos) = item;
std::cout << "\nAfter Inserting \""<< item <<"\", the updated list is:\n\n";
for (const auto& s : demo)
std::cout << s << '\n';
return true;
}
If you want a compilable example, with 0-exit or 1-st_insert as your menu choices, you could do:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
bool st_insert(std::vector<std::string>& demo)
{
size_t pos;
std::string item {};
std::cout << "Enter a position number to insert: ";
if (!(std::cin >> pos))
return false;
std::cout << "Enter a new Element: ";
if (!(std::cin >> item))
return false;
if (pos >= demo.size())
demo.push_back(item);
else
demo.at(pos) = item;
std::cout << "\nAfter Inserting \""<< item <<"\", the updated list is:\n\n";
for (const auto& s : demo)
std::cout << s << '\n';
return true;
}
int main (void)
{
int choice;
std::string tmp;
std::vector<std::string> student { "my", "dog", "has", "fleas" };
std::cout << "Array:\n\n";
for (const auto& s : student)
std::cout << s << '\n';
std:: cout << "\nEnter menu choice: ";
if (!(std::cin >> choice)) {
std::cerr << "error: invalid integer value - choice.\n";
return 1;
}
switch(choice)
{
case 0:
exit(0);
break;
case 1:
if (!st_insert (student))
std::cerr << "error: unable to insert element.\n";
break;
default:
std::cout << "Wrong choice please try again !!!\n";
}
return 0;
}
Example Use/Output
Replace Exmaple:
$ ./bin/insert_str_item
Array:
my
dog
has
fleas
Enter menu choice: 1
Enter a position number to insert: 1
Enter a new Element: cat
After Inserting "cat", the updated list is:
my
cat
has
fleas
Add Example:
$ ./bin/insert_str_item
Array:
my
dog
has
fleas
Enter menu choice: 1
Enter a position number to insert: 40
Enter a new Element: now
After Inserting "now", the updated list is:
my
dog
has
fleas
now
(note: the st_insert() function was written so if the requested pos for the new string exceeds what the next string in the vector would be, it is simply added as the next string and the invalid position is discarded)
Now when you go to take input for your vector of strings, it is quite simple. just read your input into a temporary string and use the .push_back() member function to add the string to your vector of strings, e.g.
std::string tmp {};
std::cout << "enter a string: ";
if (std::cin >> tmp)
student.push_back(tmp);
(note: you must validate every user input before you use the value)
Adding Taking siz New Elements
From your example, if you did want to specify the number of new strings to enter, you could adjust the program as follows:
int main (void)
{
int choice;
size_t siz;
std::string tmp;
std::vector<std::string> student { "my", "dog", "has", "fleas" };
std::cout << "There are currently " << student.size() << " elements:\n\n";
for (const auto& s : student)
std::cout << s << '\n';
std::cout << "\nHow many elements would you like to add? ";
if (!(std::cin >> siz)) {
std::cerr << "error: invalid size-type input.\n";
return 1;
}
for (size_t i = 0; i < siz; i++) {
std::cout << "student[" << student.size() << "]: ";
if (std::cin >> tmp)
student.push_back(tmp);
}
std::cout << "\nCurrent strings:\n\n";
for (const auto& s : student)
std::cout << s << '\n';
std:: cout << "\nEnter menu choice: ";
if (!(std::cin >> choice)) {
std::cerr << "error: invalid integer value - choice.\n";
return 1;
}
switch(choice)
{
case 0:
exit(0);
break;
case 1:
if (!st_insert (student))
std::cerr << "error: unable to insert element.\n";
break;
default:
std::cout << "Wrong choice please try again !!!\n";
}
return 0;
}
Example Use/Output
$ ./bin/insert_str_item
There are currently 4 elements:
my
dog
has
fleas
How many elements would you like to add? 4
student[4]: my
student[5]: cat
student[6]: has
student[7]: none
Current strings:
my
dog
has
fleas
my
cat
has
none
Enter menu choice: 1
Enter a position number to insert: 5
Enter a new Element: frog
After Inserting "frog", the updated list is:
my
dog
has
fleas
my
frog
has
none
You will want to see std::vector and std::basic::string for full details of the use of std::vector and std::string. Also see: Why is “using namespace std;” considered bad practice? and C++: “std::endl” vs “\n”.
Look things over and let me know if you have further questions.
As rightly said by some authors , what is required by you should not be done by fixed memory allocation , instead dynamic memory allocation (example : vectors in c++) should be used. However since you wanted to try the fixed one still, you can do the following :
Declare a string array of a larger size, instead of the user input (siz). Let's say it to be of predefined size 1000. (You can notify user to have a array of size to be less).
Declare the siz variable as global and not local. Because when you come after doing any insertion / deletion operation your size should be more / less than it previously was.But if you are using it as local then the changes would not be reflected because of call by value.
EDITED code:
#include<iostream>
#include <stdlib.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int siz=0;
void st_insert(string demo[])
{
int pos;
cout<<"Enter a position number to insert:";
cin>>pos;
string item;
cout<<"Enter a new Element :";
cin>>item;
cout<<"After Inserting "<<item<<", the updated list is: "<<endl;
for (int i=siz-1; i>=pos; i--)
{
demo[i+1] = demo[i];
}
demo[pos] = item;
siz++;
for (int i=0; i<siz; i++)
cout<<"\t"<<demo[i]<<endl;
}
int main(int argc, char ** argv)
{
cout<<"How many elements:";
cin>>siz;
string student[1005];
for(int i=0; i<siz; i++)
{
cin>>student[i];
}
cout<<"Array:";
for(int i=0; i<siz; i++)
cout<<student[i]<<endl;
int choice;
cout <<"Enter your choice :";
cin>>choice;
switch(choice)
{
case 0:
exit(0);
break;
case 1:
st_insert(student);
break;
case 4:
cout<<"All elements\n:";
for(int i=0; i<siz; i++)
cout<<student[i]<<endl;
break;
default:
cout<<"Wrong choice please try again !!!";
}
return 0;
}
Rest all seems fine to me.
Hope you got it. :)
In C++, arrays have a fixed sized and when passed as parameters what you are actually getting is a pointer to the first element in the array. In you code, you are trying to access demo[i+1] when size equals size-1; this generates an error because you are trying to access a memory location that isn't part of the array (demo[size]). When inserting an element in an array, you need to first allocate a new chunk of memory with the new size, then you copy each element over(including the new value), and finally delete the old chunk of memory which is now unused.

EXC_BAD_ACCESS error with arrays in C++

sorry if this is a stupid question but I'm trying to write a program that compares 7 numbers that a user inputs to 7 numbers that the computer generates(a kind of lottery simulator). However, when i try to input the 7 numbers that the user inputs the program crashes after the second input. Please help, and thanks in advance!
This is the beginning of my main:
#include <iostream>
#include <iomanip>
#include "Implementation.hpp"
using namespace std;
int main()
{
string name;
cout << "What is your name?\n";
getline(cin, name);
while(1 != 0) //I know this will never be true, I'm just doing it
//because the return statement will
{ //end the program anyways if the user inputs 2
int *userNums = new int[7];
int *winningNums = new int[7];
int cont;
int matches;
cout << "LITTLETON CITY LOTTO MODEL\n";
cout << "--------------------------\n";
cout << "1) Play Lotto\n";
cout << "2) Quit Program\n";
cin >> cont;
if(cont == 2)
return 0;
getLottoPicks(&userNums);
And this is the getLottoPicks function:
void getLottoPicks(int *picks[])
{
int numsAdded = 0, choice;
while(numsAdded <= 7)
{
cout << "Please input a valid number as your lotto decision.\n";
cin >> choice;
if(noDuplicates(*picks, choice) == false)
continue;
*picks[numsAdded] = choice;
numsAdded++;
}
}
I'm fairly certain that it is a problem with the pointers that i'm trying to use, but without them I can't actually change the arrays I don't think, and I couldn't get the function to return an array.
If you're using C++, then you're probably better using a std::vector<int>, and passing in the reference to the vector in getLottoPicks.
However, your code should only be passing the int * to the getLottoPicks, and should process < 7 items - it's the classic off-by one.
call to getLottoPicks:
getLottoPicks(userNums);
and the new getLottoPicks code:
void getLottoPicks(int *picks)
{
int numsAdded = 0, choice;
while(numsAdded < 7)
{
cout << "Please input a valid number as your lotto decision.\n";
cin >> choice;
if(noDuplicates(picks, choice) == false)
continue;
picks[numsAdded] = choice;
numsAdded++;
}
}

How to use a sentinel to trigger end of vector?

I'm new to programming (in general) and C++ (in particular). I'm learning vectors and am trying to write a simple program that:
allows the user to enter a vector of students' test scores
when the user types the sentinel (-1 in this case), the vector terminates
outputs a tally of the student's grades
Here's my code:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
const int SENTINEL = -1;
vector<int> studentGrades = { 0 };
int myInput;
int main()
{
do
{
cout << "Please enter a student's grade: ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades[myInput]++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades[i] << endl;
return 0;
}
Two questions:
1) Can anyone provide guidance on why this code is only allowing me to enter one student's grade?
2) Is the for loop that compute the "tally" correct?
Thanks in advance for taking a look,
Ryan
* REVISED CODE *
# JCx - this is the revised code:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
const int SENTINEL = -1;
vector<int> studentGrades = { 0 };
int myInput;
int main()
{
do
{
cout << "Please enter a student's grade (or -1 to QUIT): ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades.at(myInput)++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades.at(myInput) << endl;
return 0;
}
and, I'm seeing this error:
Unhandled exception at 0x7707C42D
Microsoft C++ exception: std::out_of_range at memory location 0x0035F890
There's more than one problem. The attempt to access studentGrades[-1] when the users enters your sentinel value, and the fact that the default vector only contains an entry for 0 and the use of push_back.
Let's just walk through some of the problems:
User runs program. User enters 100. studentGrades[100] is out of range. Undefined behaviour occurs as the vector only has one element.
User runs program, enters -1 studentGrades[-1] is out of range.
User runs program, enters 0. studentGrades[0] is in range, incremented to 1. studentGrades.push_back(1) adds an element to the vector studentGrades[1] is now also equal to 1.
As a great starting point, if you swap your subscript vector references for the vector at method as I've shown below you will get out-of-range errors which will help (a lot). The code below still needs work but at least you'll have run-time errors instead of odd behaviour.
int main()
{
do
{
cout << "Please enter a student's grade: ";
cin >> myInput;
if (myInput < 1000)
{
studentGrades.at(myInput)++;
}
studentGrades.push_back(myInput);
} while (myInput != SENTINEL);
cout << "\n";
for (int i = 0; i < 1000; i++)
cout << i << " grade(s) of " << studentGrades.at(myInput) << endl;
return 0;
}
I think if I was implementing this I'd be using std::map instead of a vector. It would let you have a studentGrade[1000] without having to allocate memory for studentGrade[0] to [999] first.
However as you are learning about std::vector check out vector::resize to set the vector big enough for the required elements, std::vector::size to find out whether you need to increase the size. You could then ditch the push_back.
References
vector::at http://www.cplusplus.com/reference/vector/vector/at/
vector::size http://www.cplusplus.com/reference/vector/vector/size/

How can a validate input of type int only... in a very simple but effective way? in c++

There is an array with 9 spaces(elements), where those 9 numbers will be stored which are entered by user.
How would you make sure that they enter only those 9 numbers and that they are not the same?
Finally cout(print) them from less to greater?
Here's a solution that ensures numbers in the range [0,9], and ignores duplicates:
#include <algorithm> //if using copy printing
#include <iostream> //for cin and cout
#include <iterator> //if using copy printing
#include <set> //for set
CHOOSE A METHOD BELOW AND ADD THE CORRESPONDING INCLUDE
int main() {
std::set<int> nums; //here's the array
std::cout << "Please enter nine different numbers."
"Duplicates will be ignored.\n";
//ADD THE NEXT PART OF THE METHOD, THE DECLARATION
do {
std::cout << "Enter the next number: ";
//ADD THE FINAL PART, GETTING INPUT AND INSERTING IT INTO THE SET
} while (nums.size() < 9); //do this until you have 9 numbers
std::cout << "The numbers you entered, in order, are:\n";
//C++11 printing
for (const int i : nums)
std::cout << i << ' ';
//C++03 printing using copy
std::copy (nums.begin(), nums.end(),
std::ostream_iterator<int> (std::cout, " "));
//C++03 printing using an iterator loop
for (std::set<int>::const_iterator it = nums.cbegin(); //this was to
it != nums.cend(); //eliminate the
++it) //scrollbar
std::cout << *it << ' ';
}
First Method: (better for a wider range)
#include <limits> //for numeric_limits
...
int temp; //this holds the current entry
...
//works better when you get out of the range 0-9
while (!(std::cin >> temp) || temp < 0 || temp > 9) {
//body executes if input isn't an int between 0 and 9
//clear bad input flag
std::cin.clear();
//discard bad input
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
//prompt for new number (could also add that you're ignoring to beginning)
std::cout << "Invalid number. Please enter a new one: ";
}
//insert the valid number, duplicates ignored, automatically sorted
nums.insert (temp);
Second Method: (better for a 0-9 range)
#include <cctype> //for isdigit
...
char temp; //holds current entry
...
//suitable for 0-9 range
do {
std::cin >> temp;
if (!std::isdigit (temp))
std::cout << "Invalid number. Please enter a new one: ";
while (!std::isdigit (temp));
nums.insert (temp - '0'); //add the integer value of the character processed
The key here is std::set, which only allows unique entries, and automatically sorts the elements.