Input (as a condition) terminates when the value is entered - c++

Goals:
Write a program where you first enter a set of name-and-value pairs, such as Joe 17 and Barbara 22.
For each pair, add the name to a vector called names and the number to a vector called scores (in corresponding positions, so that if names[7]=="Joe" then scores[7]==18).
Problems:
Input (as a condition) terminates when the values are entered.
Questions:
Is there a way to avoid it?
Why does it terminate?
Is there a more effective approach?
#include <iostream>
#include <vector>
std::vector<std::string> names;
std::vector<int> values;
std::string name;
int value;
int main(){
for (int i = 0; std::cin >> name >> value; i++){
names[i] = name;
values[i] = value;
}
}

Your vectors are empty. You cannot use operator[] to access any element, because there is none. The "termination" is most likely a segmentation fault (your OS stops your program, because it tries to access memory that doesn't belong to it).
You can append to your vectors using push_back() method:
int main(){
//you don't need any counter, so it's easier to use while loop:
while (std::cin >> name >> value) {
names.push_back(name);
values.push_back(value);
}
}

Related

how can i use (!(cin>>a)) twice times?

enter image description here
i have used code ( if (!(cin >> arr[i])) ) to check if input from user is different with type int (like string, char) to stop reading into array (arr1), and then i can't use it twice with the second array (arr2), it didn't read input and go straight to cin.clear and return... Can you help me? Thank you very much from it^^
enter image description here
It seems you mean the following
#include <limits>
//...
if ( not ( std::cin >> arr[i] ) )
{
//...
std::cin.clear();
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
Below is the complete working example in 2 ways. The program given read as many integers as the user enters on the console. For example the user can enter 30 or 300 inputs some which may be integer types and other may be of some other types like string. The array/vector will add only integer type input inside itself as you require.
Solution 1: Using built in array
#include <iostream>
#include <sstream>
#include <string>
int main()
{
std::string line;
//in case of using array, size must be fixed and predetermined
int arr[4] = {0}; //all elements are initialzed to zero. Also you can choose array size according to your needs
int i = 0;//this variable will be used to add element into the array
int count = 0;
getline(std::cin, line);
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof()) {
//check if either failbit or badbit is set
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
arr[count] = i;
++count;
if(count>=4)
{
break;//break the loop so that you don't go beyond array size
}
}
}
//print out the elements of the array
for(int i: arr)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
Solution 1 can be checked here.
Solution 2: Using std::vector
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
int main()
{
std::string line;
std::vector<int> vec;
int i = 0;//this variable will be used to add element into the array
getline(std::cin, line);
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof())
{
//check if either failbit or badbit is set
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
vec.push_back(i);
}
}
//print out the elements of the array
for(int i: vec)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
Solution 2 can be checked here.
Important Note
The advantage of using std::vector over built in array(in this case) is that you don't have know the size of the vector beforehand. That is std::vector's size is not fixed as opposed to built in arrays. So it is preferable because you don't know how many input the user is going to enter. std::vector can handle this accordingly and add only valid(integer type) input. But when using built in arrays you must know/specify the size of the array beforehand. This in turn means you must know beforehand how many integers the user is going to enter, which is not practical.

Segmentation Fault while accepting input

I am trying to accept the input from user
where first line will be Integer to indicate number of testcases
if number is 3
Input will be like
3
Hello world
hey there, I am John
have a nice day
I am using getline to read the input
My code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
vector<string> arr;
for(int i=0; i<n; i++){
string s;
getline(cin, s);
arr[i] = s;
}
}
Error:
3
Segmentation fault(core dumped)
arr is an empty vector, so arr[i] = s; is going to access out of bounds. The [] operator does not grow the vector. It can only be used to access already existing elements.
You can't create an element of a vector using the [] indexing operator; your line arr[i] = s; is trying to assign a string to an element that doesn't (yet) exist.
There are several ways around this: first, you could use the push_back function to add a new element to the end of the vector, in each loop; second, you could use the resize member to pre-allocate a specified number of elements (which you can then use in the arr[i] = s; line); third - and perhaps simplest - you can 'pre-allocate' the elements of the vector by specifying the number of elements in the declaration (constructor), like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string> // Need this for the "getline()" function definition
using namespace std;
int main()
{
size_t n; // Indexes and operations on std::vector use "size_t" rather than "int"
cin >> n;
cin.ignore(1); // Without this, there will be a leftover newline in the "cin" stream
// std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // More precise, actually!
vector<string> arr(n);
// arr.resize(n); // Alternative to using 'n' in constructor
for (size_t i = 0; i < n; i++) {
string s;
getline(cin, s);
arr[i] = s;
}
for (auto s : arr) cout << s << endl; // Just to confirm the input values
return 0;
}
There are also a few other issues in your code that I have 'fixed' and commented on in the code I posted. Feel free to ask for further clarification and/or explanation.
EDIT: On the use of the cin.ignore(1); line I added, see Why does std::getline() skip input after a formatted extraction? (and the excellent answers given there) for more details.

How can I get limitless inputs in a line seperated with spaces?

What I am trying to do is overloading the >> operator of my Book class to take an unknown number of integers from the user in one line. After that, I need to create an array of them.
I tried this:
istream& operator>>( istream& in, Book& b )
{
int x;
delete[] b.editionYears;
b.editionNo = 0;
b.editionYears = new int[0];
cin>>x;
b.addEdition(x);
return in;
}
And I call this with
cout << A << endl;
in the test class where A is a Book object.
I tried this but in here, when the user enters something like "1 2 3 4", it only deletes the array and adds 1 to it, in the second call it deletes 1 again and adds 2.
What I expect is, if the user enters "1 2 3 4", it should delete editionYears array, create again and add 1,2,3,4 to it.
So how can I do this? Thanks for any help.
Your problem is in the use of cin. Try using std::getline.
This other answer may help https://stackoverflow.com/a/5838803/5355195
Consider using std::vector instead of dynamically allocated arrays. There are multiple ways to do this. You may ask users to enter the number of integers they are going to enter, you may ask them to enter something like -1 when they are done, or you may ask them to enter all the integers in a single line, then read it into stringstream then convert to ints and push_back to a vector. The first two approaches are trivial to implement, so here's an example implementation for the third way:
#include <iostream>
#include <vector>
#include <sstream>
int main()
{
std::vector<int> vec;
std::cout << "please enter numbers in a line" << std::endl;
std::string line;
std::getline(std::cin, line);
std::istringstream ss(line);
int i;
while (ss >> i)
{
vec.push_back(i);
}
return 0;
}

Reading a row until newline in the console

I need to make a program that reads n numbers in a row. For example, the user first puts in a list of 2 numbers like this:
P n
I managed to read those with scanf but now I need to read the n following numbers, these numbers are given in a row as follows.
1 6 3 99 ... n times
These numbers must be read all at once (or give the impression of).
I already tried using
while(getline(cin,str)){
// do something with str
}
As explained in this thread but I need the actions inside the while loop to stop when I hit the intro key. With my current implementation they don't stop, it just keeps waiting for more lines to read.
In summary:
First, user must be able to input two numbers (P and n)(done!) then hit enter and start typing a list of n numbers (not done!).
Here is my code.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main(void){
int P,n;
scanf("%d %d",&P,&n);
string val;
int score[P];
int i;
for(i=0;i<P;i++){
score[i]=0;
}
while(getline(cin,val)){
printf("Val=%s\n",val.c_str());
stringstream stream(val);
int local;
while(stream >> local){
score[local]=score[local]+1;
printf("%d-%d\n",local,score[local]);
}
}
for(i=0;i<P;i++){
printf("%d-%d\n",i,score[i]);
}
return 0;
}
Use scanf() inside the n times loop instead of getline().
for(int i = 0; i < n; i ++){
scanf("%d",&variable);
}
Not sure I understood your question, but this code will read 2 numbers, then a line and then finish.
using namespace std;
int main(){
int P,n;
cin >> P;
cin >> n;
int *score = new int[P];
for(int i=0;i<P;i++){
score[i]=0;
}
int num;
string val;
cin.ignore();
getline(cin, val);
istringstream stream(val);
while (stream >> num) {
printf("Val = %d\n", num);
score[num]=score[num]+1; // potential segmentation fault here in your code
printf("%d-%d\n",num,score[num]);
}
delete [] score;
return 0;
}
The fault would occur because you are assuming that the number on the line is smaller than P, which is the size of the array. However, the following input would cause error:
1 2
5
This question is almost a classic. The classic question has this code:
cin >> n;
getline(cin, s);
and then the author is puzzled why s is empty. Your variation does the same, although it also uses C stdio function to make matters more confusing. The problem is that the first call is a field-based input, which will read a single value n and leave any other input in the buffer! If the user entered 42 and hit enter, the remaining input is the newline. The second getline() call then reads an empty string and discards the newline.
For interaction with the user, only use getline() and then try to parse each line. Using stringstreams or sscanf(), since you seem familiar with it, are both valid options. However, if you only want to read the input an not really interact, David Weston's suggestion is also a good one and probably the easiest one, too. However, since you're using C++, I'd suggest using cin >> variable instead.

For loop to input strings in vector using getline

So I have an assignment for school, I need to declare a vector of strings
then use a for loop to input names into the vector using get line. This code is what I have so far, I was trying to make a variable for a location in my vector, then input a string into the vector based on the value of my variable. Im using C++.
What Im wondering is: whats the flaw in my logic?
#include "stdafx.h"
#include <iostream>;
#include <vector>;
#include <string>;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
vector<string> name_list(10);
int n;
for (name_list[n]; cin.getline >> name_list[n]; ++n)
cin >> name_list[n];
cout << name_list[n];
int stop; cin >> stop;
return 0;
}
EDIT:::
So I figured it out! Thank you 0x499602D2, You kinda set me on the right way. the code I came up with is this::
int _tmain(int argc, _TCHAR* argv[])
{
vector<string> name_list(11);
int n = 0;
for (int n = 0; n < 11; ++n);
getline(cin, name_list[n]);
cout << name_list[n];
int stop; cin >> stop;
return 0;
}
Not only is n uninitialized, you're also doing cin.getline >> name_list[n] which shouldn't even compile as far as I know. getline is a member function of std::cin that reads a line from input into a character array. It's not needed here as we are trying to read into a vector.
Moreover, since you want to get names from the user input into each slot in the vector, attempting to retrieve a line with getline also wouldn't make sense.
n needs to be initialized to an integer that when access with name_list[n], will give us the start of the vector (that would be 0), and instead of getline, we use the operator >> to get each whitespace separated input. Like this:
for (int n = 0; std::cin >> name_list[n]; ++n)
; // empty
A statement isn't needed within the for loop body as its already been done in the loop parameters.
Another thing you need to look out for is overrunning the size of the vector. You initialized name_list with a size of 10, and if the user enters in, say, 11 names, accessing an index with name_list[n] will cause Undefined Behavior in your program, which is a special way of saying your program will be invalid.
It's better to use the at() member function as it will throw an exception if you try to access an out-of-bounds address:
for (int n = 0; std::cin >> name_list.at(n); ++n)
// ^^^^^^
;
You need to initialize n=0 and in the second for parameter you might wanna move the cin into the loop and replace it with i < 10 because otherwise the loop would not know when to stop