Segmentation Fault while accepting input - c++

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.

Related

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

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);
}
}

Elegant solution to take input to a vector<int>

I am trying to create an vector <int> whose size is not pre-defined. It should take in numbers as long as there are numbers in the input terminal and should stop reading when I hit Enter. I tried many solutions including the ones given here and here. In the second case, I can enter a non-integer to terminate the input to the vector. If I use the first solution (code added below), it listens to the input indefinitely.
Code:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
//cout << "Enter the elements of the array: \n";
//vector <int> arr ( std::istream_iterator<int>( std::cin ), std::istream_iterator<int>() );
vector <int> arr;
string buf;
cout << "Enter the elements of the array: \n";
while(getline(cin, buf))
{
istringstream ssin(buf);
int input;
while(ssin >> input)
{
arr.push_back(input);
}
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}
1) I don't feel that typing in a character or a very large number to end listening to input is very elegant. However, the solution with istringstream seems to be the way to go. I am not sure why it doesn't work.
2) Is there any way to detect the Enter from keyboard to terminate listening to input? I tried using cin.get(), but it changed the numbers in the vector.
3) Any other methods or suggestions?
Let's take things one step at a time.
We want to read up until enter is pressed. That means you probably want to use std:getline to read a line.
Then you want to parse it, so you want to put the line into an istringstream.
Then you want to read numbers. While you're reading them, you apparently want to ignore anything other than digits, and you want to keep reading even if you get to a group of digits that can't be converted to a number.
That leaves a few things that aren't entirely clear, such as what to do with that input that's too large to convert? Do you want to just skip to the next? Do you want to read some digits as a number, then read remaining digits as another number?
Likewise, what do you want to do if you get something like "123a456"? Should it be skipped completely, read as "123" (and the "a456" ignored)? Should it be read as "123" and "456", and just the "a" ignored?
For the moment let's assume that we're going to read space-separated groups of characters, and convert all those to numbers that we can. If something is too big to convert to a number, we'll ignore it (in its entirety). If we have a group like "123a456", we'll read the "123" as a number, and ignore the "a456".
To achieve this, we can do something like this:
std::string line;
std::getline(infile, line);
std::istringstream input(line);
std::string word;
std::vector<int> output;
while (input >> word) {
try {
int i = std::stoi(word);
output.push_back(i);
}
catch (...) {}
}
For example, given input like: "123a456 321 1111233423432434342343223344 9", this will read in [123, 321, 9].
Of course, I'm just taking a guess about your requirements, and I haven't worked at making this particularly clean or elegant--just a straightforward implementation of one possible set of requirements.
Please see the comments from #LearningC and #M.M.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
vector <int> arr;
string buf;
int input;
cout << "Enter the elements of the array: \n";
getline(cin, buf);
istringstream ssin(buf);
while(ssin >> input)
{
arr.push_back(input);
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}

c++ word count(as words we take every possible variable name)

I was asked to make a program that reads a cin could be text and then counts the words in it(i need to count as a word every name that can be accepted as a variable name ex _a,a1) my problem is that my code works for only one byte. if its more than one the sum is always 0.The only thing i think i can have wrong is that i didn't put the string into an array but a friend of mine told me i don't need to do so.below is my code:
#include<iostream>
#include<string>
#include<stdio.h>
using namespace std;
int main(){
int sum=0;
bool z= false; //z is just a switch to see if we are inside a word\n
string s;
cout<<"Insert text: ";
getline(cin,s); //here we get the string\n
int n=s.length()-1; //for some reason i==(s.length-1) put a warning$
for(int i=0;i==n;i++){ //here we check each byte to see what it contai$
cout<<s[i];
if(isalpha(s[i]) || s[i]=='_'){ //to enter a word we need a let$
z=true;
sum++;}
if(z==true){ // if we are in a word we can have numbers as w$
if(!isalnum(s[i]) && s[i]!='_'){
z=false;}} // exit the current word and go$
if(s[i]==EOF){ // the end\n
break;}}
cout<<"Number of words is: "<<sum<<endl; // the real end\n
return 0;
}
This is so much easier than the code you have provided. We can do this with the STL using an istream iterator. If you choose to use C++ and not C, then you should take advantage of the standard library.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;
int main(){
vector<string> words((istream_iterator<string>(cin)), istream_iterator<string>());
for(int i = 0; i < words.size(); i++)
cout << words[i] << '\n';
return 0;
}
Check your for loop.. it runs as long as the second statement is true.. when is it true that i==n? only at the very last byte.. change this to i<=n instead.
First of all you don't need dont use getline because it is insecure, use cin instead. Also you do not need the and use cin instead of getline. Also if getline is used with an array it could pose a serious problem and could be exploited via stack overflow. Sorry I cant help much what you were asking but I just wanted to give you a heads up.

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

std::getline does not work inside a for-loop

I'm trying to collect user's input in a string variable that accepts whitespaces for a specified amount of time.
Since the usual cin >> str doesn't accept whitespaces, so I'd go with std::getline from <string>
Here is my code:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local); // This simply does not work. Just skipped without a reason.
//............................
}
//............................
return 0;
}
Any idea?
You can see why this is failing if you output what you stored in local (which is a poor variable name, by the way :P):
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local);
std::cout << "> " << local << std::endl;
}
//............................
return 0;
}
You will see it prints a newline after > immediately after inputting your number. It then moves on to inputting the rest.
This is because getline is giving you the empty line left over from inputting your number. (It reads the number, but apparently doesn't remove the \n, so you're left with a blank line.) You need to get rid of any remaining whitespace first:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
cin >> ws; // stream out any whitespace
for(int i = 0; i < n; i++)
{
string local;
getline(cin, local);
std::cout << "> " << local << std::endl;
}
//............................
return 0;
}
This the works as expected.
Off topic, perhaps it was only for the snippet at hand, but code tends to be more readable if you don't have using namespace std;. It defeats the purpose of namespaces. I suspect it was only for posting here, though.
Declare a character to get in the carriage return after you have typed in the number.char ws;int n;cin>>n;ws=cin.get();
This will solve the problem.
Using cin>>ws instead of ws=cin.get(),will make first character of your string to be in variable ws,instead of just clearing '\n'.
It's quite simple.
U jst need to put a cin.get() at the end of the loop.
Are you hitting enter? If not get line will return nothing, as it is waiting for end of line...
My guess is that you're not reading n correctly, so it's converting as zero. Since 0 is not less that 0, the loop never executes.
I'd add a bit of instrumentation:
int n;
cin >> n;
std::cerr << "n was read as: " << n << "\n"; // <- added instrumentation
for // ...
why this happens :
This happens because you have mixed cin and cin.getline.
when you enter a value using cin, cin not only captures the value, it also captures the newline. So when we enter 2, cin actually gets the string ā€œ2\nā€. It then extracts the 2 to variable, leaving the newline stuck in the input stream. Then, when getline() goes to read the input, it sees ā€œ\nā€ is already in the stream, and figures we must have entered an empty string! Definitely not what was intended.
old solution :
A good rule of thumb is that after reading a value with cin, remove the newline from the stream. This can be done using the following :
std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed
A better solution :
use this whenever you use std::getline() to read strings
std::getline(std::cin >> std::ws, input); // ignore any leading whitespace characters
std::ws is a input manipulator which tell std::getline() to ignore any leading whitespace characters
source : learncpp website
goto section (Use std::getline() to input text)
hope this is helpful
Is n properly initialized from input?
You don't appear to be doing anything with getline. Is this what you want?
getline returns an istream reference. Does the fact that you're dropping it on the ground matter?
On which compiler did you try this? I tried on VC2008 and worked fine. If I compiled the same code on g++ (GCC) 3.4.2. It did not work properly. Below is the versions worked in both compilers. I dont't have the latest g++ compiler in my environment.
int n;
cin >> n;
string local;
getline(cin, local); // don't need this on VC2008. But need it on g++ 3.4.2.
for (int i = 0; i < n; i++)
{
getline(cin, local);
cout << local;
}
The important question is "what are you doing with the string that gives you the idea that the input was skipped?" Or, more accurately, "why do you think the input was skipped?"
If you're stepping through the debugger, did you compile with optimization (which is allowed to reorder instructions)? I don't think this is your problem, but it is a possibility.
I think it's more likely that the string is populated but it's not being handled correctly. For instance, if you want to pass the input to old C functions (eg., atoi()), you will need to extract the C style string (local.c_str()).
You can directly use getline function in string using delimiter as follows:
#include <iostream>
using namespace std;
int main()
{
string str;
getline(cin,str,'#');
getline(cin,str,'#');
}
you can input str as many times as you want but one condition applies here is you need to pass '#'(3rd argument) as delimiter i.e. string will accept input till '#' has been pressed regardless of newline character.
Before getline(cin, local), just add if(i == 0) { cin.ignore(); }. This will remove the last character (\n) from the string, which is causing this problem and its only needed for the first loop. Otherwise, it will remove last character from the string on every iteration. For example,
i = 0 -> string
i = 1 -> strin
i = 2 -> stri
and so on.
just use cin.sync() before the loop.
just add cin.ignore() before getline and it will do the work
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string local;
cin.ignore();
getline(cin, local);
}
return 0;
}