I'm making a program which is getting inputs from the user, while each input contains ints delimited with spaces. e.g "2 3 4 5".
I implemented the atoi function well, but, whenever I try to run on the string and "skip" on the spaces I get a runtime error:
for(int i=0, num=INIT; i<4; i++)
{
if(input[i]==' ')
continue;
string tmp;
for(int j=i; input[j]!=' '; j++)
{
//add every char to the temp string
tmp+=input[j];
//means we are at the end of the number. convert to int
if(input[i+1]==' ' || input[i+1]==NULL)
{
num=m_atoi(tmp);
i=j;
}
}
}
In the line 'if(input[i+1]==' '.....' I get an exception.
Basically, I'm trying to insert just "2 2 2 2".
I realized that whenever I try to compare a real space in the string and ' ', the exception raises.
I tried to compare with the ASCII value of space which is 32 but that failed too.
Any ideas?
The problem is that you don't check for the end of the string in your main loop:
for(int j=i; input[j]!=' '; j++)
should be:
for(int j=i; input[j]!=0 && input[j]!=' '; j++)
Also, don't use NULL for the NUL char. You should use '\0' or simply 0. The macro NULL should be used only for pointers.
That said, it may be easier in your case to just use strtol or istringstream or something similar.
Not an answer to the question.
but two big for a comment.
You should note the C++ stream library automatically reads and decodes int from a space separated stream:
int main()
{
int value;
std::cin >> value; // Reads and ignores space then stores the next int into `value`
}
Thus to read multiple ints just put it in a loop:
while(std::cin >> value) // Loop will break if user hits ctrl-D or ctrl-Z
{ // Or a normal file is piped to the stdin and it is finished.
// Use value
}
To read a single line. That contains space separated values just read the line into a string (convert this to a stream then read the values.
std::string line;
std::getline(std::cin, line); // Read a line into a string
std::stringstream linestream(line); // Convert string into a stream
int value;
while(linestream >> value) // Loop as above.
{
// Use Value
}
Related
everyone, here is a function I wrote to read a user input which is a vector of double of unknown size, the input must terminate when 'enter' is pressed:
vector<double> read_array()
{
vector<double> array_in;
double el;
while (!cin.get())
{
cin >> el;
array_in.push_back(el);
}
return array_in;
}
To illustrate it consider the following code:
void init() // the function that calls the read_array function
{
cout << "Enter array X: " << endl;
vector<double> X = read_array();
int l = X.size();
cout << l << endl;
}
A typical input when promted is:
1(space)2(space)3(space)4(enter)
When enter is pressed, the input terminates, and the variable 'l' is initialised but is equal to 0
However, when the enter key is pressed, the array size is 0. Debugging it makes it look like it never makes it into the loop like that.
The same routine works well if the input value is not an array.
Thanks to everyone in advance!
I don't know what you hope std::cin.get() does but based on your comment it seems you hope that it somehow deals with end of lines: it doesn't. It simply reads the next character which is unlikely to do you much good. In particular, if the character is anything but '\0' negating it will result in the boolean value false. That said, the loop should in principle work unless you only input a single digit numeric value followed (possibly after space) by a non-digit or the end of the input.
The easiest approach to deal with line-based input is to read the line into a std::string using std::getline() and then to parse the line using std::istringstream:
std::vector<double> read_array() {
std::vector<double> result;
if (std::string line; std::getline(std::cin, line)) {
std::istringstream lin(line);
for (double tmp; std::cin >> tmp; ) {
result.push_back(tmp);
}
}
return result;
}
As std::cin is only involved while reading lines, std::cin.fail() won't be set when parsing doubles fails. That is, you can read multiple lines with arrays of doubles, each of which can also be empty.
If you don't want to read an auxiliary line, you'll need to understand a bit more about how formatted input in C++ works: it starts off skipping whitespace. As newlines are whitespace you need to rather read the whitespace yourself and stop if it happens to be a newline or non-whitespace. I'd use a function doing this skipping which returns false if it reached a newline (which is still extracted):
bool skip_non_nl_ws(std::istream& in) {
for (int c; std::isspace(c = in.peek()); std::cin.ignore()) {
if (c == '\n') {
return false;
}
}
return true;
}
std::vector<double> read_array() {
std::vector<double> result;
for (double tmp; skip_non_nl_ws(std::cin) && std::cin >> result); ) {
result.push_back(tmp);
}
return result;
}
This approach has a similar property that std::ios_base::failbit won't be set. However, if any of the characters on a line can't be parsed as double the bit will set. That way you can detect input errors. The approach using std::getline() will just go on to the next line.
I am quite new in c++ and programming so sorry in advance in my question repeats. I have a text file of 3 lines:
7
00000000000000000000000*0000
0 0 0 R 0
What I need to do is read 2nd line and write it into an array as char. But I must not include 3rd line because it will go to a completely different matrix. My code so far :
ifstream input;
input.open("input1.txt");
input >> start;
char a=0;
string line;
while (getline(input, line))
{
a=0;
istringstream iss(line);
int length = line.size();
for (int i=0; i<length; i++)
{
iss >> a;
A[i] = a;
cout << A[i] << " " << i << endl;
}
}
input.close();
However, with this code it always starts new array for 3rd line. What am I doing wrong? What is the easiest way to fix it? Thank you.
-----------------------------Update--------------------------------------
I have modified the code but it still does not work properly. I am getting this kind of result : 5)-└ instead of correct one. My current code:
void Read(int &numLines, int &start, vector<char>&A, char B[][5])
{
ifstream input;
input.open("input.txt");
input >> start;
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
string line;
if(getline(input, line))
{
for(char temp: line)
{
A.push_back(temp);
}
}
input.close();
}
A here is a vector I want to write 2nd line to, char by char
Start is just an integer in which I am storing 1st line (7)
Thank you very much for advices
Mixing >> and std::getline is non-trivial. For example, after input >> start; the end of line marker is left in the stream in case it's still needed. In your case it isn't, and it is picked off by the subsequent call to getline, resulting in a read of an empty line.
This is what's complicating your read of line and forcing the while loop and test for empty lines.
Step through your program with your development environment's debugger and you'll see what I'm talking about. Get used to using the debugger. It's possibly the best programming productivity tool you'll ever encounter.
The easiest way to fix it is to place
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
after
input >> start;
to eat up the end of the line (and anything else that might be on that line. This needs the addition of #include<limits> to get std::numeric_limits<std::streamsize>::max.
Then you can remove the while loop and replace it with
if (getline(input, line))
No loop, not chance of consuming multiple lines from the file. And the logic for reading and processing the third line can follow.
Side note: instead of that for loop, consider
int i = 0;
while (iss >> a)
{
A[i] = a;
cout << A[i] << " " << i << endl;
i++;
}
This will march through iss until it hits the end of the line. You can also throw iss out entirely and just read the characters directly out of line.
int i = 0;
for(char temp: line)
{
A[i] = temp;
}
And A should probably be a vector if it isn't already to reduce the chances of buffer overruns.
for(char temp: line)
{
A.push_back(temp);
}
I would go with something like this:
std::string start;
std::string Astring;
ifstream input;
input.open("input.txt");
input >> start;
input >> Astring;
// If you really want a char array
char * A = new char[Astring.size()];
for (unsigned int i = 0; i < Astring.size(); i++) {
A[i] = Astring[i];
}
// Don't forget to delete after use
delete[] A;
Moreover, if you just need the char array as an input to something else later, you can call Astring.c_str() instead of that for loop, which returns a C-style char array.
When I enter "111 111" and then press enter, the output shows nothing. Then when I press enter twice, the expected output appears. Why is that?
#include<iostream>
using namespace std;
int main()
{
char seq[10];
//initialize the sequence
for (int i = 0; i<10; i++)
{
seq[i] = ' ';
}
//read characters from the keyboard
for (int i = 0; i<10; i++)
{
cin.get(seq[i]);
if (seq[i] == '\0')
{
break;
}
}
//the output should be the sequence of characters
//users typed before
cout << seq;
system("pause");
return 0;
}
You can use header file string instead, which provides more flexibility like below:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string seq;
//initialize the sequence
//read characters from the keyboard
getline(cin,seq);
//the output should be the sequence of characters
//users typed before
cout << seq;
system("pause");
return 0;
}
In response to OP's question update:
In the described case, You never inputting \0 from standard input, right? Rather you are pressing enter key.
if (seq[i] == '\0'){
Instead, you can replace this checking line with:
if (seq[i] == '\n'){
You can provide std::getline() with an additional char parameter, that defines the line-delimiter. In your case, simply let it read to the next '\0'.
auto seq = std::string{};
std::getline(cin, seq, '\0');
BTW.: are you really sure, you want to read to the next '\0'? It is not too easy to enter a zero character with the keyboard. If you actually are interested in a complete line from the input, just drop the delimiter parameter: std::getline(cin, seq).
This code:
for (int i = 0; i<10; i++){
seq[i] = ' ';
}
initializes all elements in seq to spaces, not '\0'. I don't think your break statement will trigger therefore.
Your program reads 10 characters before it does anything else. So you need to provide 10 characters.
The break check never triggers. why would it.
Finally, cout << seq is not safe, as it may read memory past the end of seq.
I am struck on getting this to work. What I am trying to do is:
Read a complete line from cin and scans it as an integer (using the string streams). If the scan succeeds, the integer value is returned. If the argument is not a legal integer or if extraneous characters (other than whitespace) appear in the string, the user is given a chance to reenter the value. Both the prompt and reprompt arguments are optional.
If supplied, the optional prompt string is printed before reading the value. If the prompt does not end with a space, a space is added when printing it.
If supplied the optional reprompt string is used as an error message when the input is not acceptable. If no reprompt string is supplied, then the string "Invalid integer format. Try again: " is used.
Prototype is:
int getInt(const string& prompt,
const string& reprompt){
int n;
bool pass = true;
while (pass != false){
string line = getLine(prompt);
istringstream s(prompt);
s >> n >> ws;
for (size_t i = 0; i < line.length(); i++){
if (i == ': '){
return isdigit(n);
}
else if (i != ': '){
i++;
line = i + ' ';
}
}
if (s.fail() || !s.eof()){
cerr << reprompt;
pass = false;
}
}
return n;
}
The results:
3. Make sure getInt returns values correctly
Invalid integer format. Try again: X Calling getInt("123")->123:
expected [123] but found [-858993460]
Comments don't handle code very well, so I write this as an answer instead.
What you seem to want to do is to write a function that reads a line from some input stream, and then parse it as an integer while verifying that an actual integer var input?
Then you start okay, but then in the parsing/validation you kind of mess up.
All you have to do is e.g.
std::string line = getLine(prompt);
for (;;)
{
std::istringstream iss(line);
int n;
if (iss >> n) // This does both parsing and validation
return n;
// If we reach here, input was not an integer
line = getLine(reprompt);
}
When I load less than 5 chars, it is ok. But if i load more than five chars my program crash.
How can i protect before that?
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
char tab[5];
int tab2[5];
char *wsk = tab;
int i = 0;
cin >> tab;
while (true) {
cin >> tab2[i];
if (tab2[i] == 0) break;
i++;
}
i = 0;
while (true) {
if (tab2[i] ==0) break;
wsk += tab2[i];
cout << *wsk;
i++;
}
return 0;
}
You don;t want to limit it to 5.
What you really want is to make sure the read works and never crashes.
The reason you don't want to stop reading at 5 characters is that if the user enters more than 5 characters you have stopped reading in the middle of their input and you now have to write code to find the end of this input and then continue. Writting code to fix the input stream is hard. Rather take input validate (the user may have typed crap and you can generate an error message) but you will be in the correct place to continue reading for the next input operation.
char tab[5];
cin >> tab; // Fails if you read more than 4 input characters
// (because it will add '\0' on the end)
Why not use a self expanding destination structure.
std::string tab;
std::cin >> tab; // Read one word whatever the size.
But what about the array.
No more difficult. Here you want an array that re-sizes. Guess what we have std::vector
int tab2[5];
while (true) {
cin >> tab2[i]; // Fails on the 6 number you input.
// STUFF
}
The loop can be written like this:
std::vector<int> tab2;
while (true) {
int val;
cin >> val;
tab2.push_back(val);
// STUFF
}
Instead of:
while (true)
put:
while (i < 5)
For C-style arrays, you have to set the width of the input stream to the number of characters allotted to the buffer, otherwise it will be possibly for you to write past the end of the array and get a buffer overflow. This is typically done using ios_base::width:
std::cin.width(5);
std::cin >> buffer;
You can also use the manipulator std::setw:
std::cin >> std::setw(5) >> buffer;
These will both set the maximum width of the stream to 5 characters. The width will be reset to its default after the first input operation.
Your loop condition should be
while(i < 5)
Also a for loop would fit perfectly
for(int i = 0; i < 5; i++) {
// body
}
You can use the algorithms part of the STL to bound your reads.
for example :
int main(){
char c[5];
auto newEnd = std::copy_n(std::istream_iterator<char>(std::cin), 5, std::begin(c));
// if newEnd != c + 5 then it failed to read 5 characters
}
The standard input is a stream. You don't get to decide what's in it. All you can do is read from it and see what you get -- either you get some data, or you learn that the stream has ended.
If you really only want to read five bytes, you can use std::cin.read(tab, 5); you must then call std::cin.gcount() to see how many bytes have actually been read and only consume as many bytes.
Alternatively, you can use C++'s dynamic containers and use std::getline(std::cin, line) to read into an std::string line as much data as is available up to a newline.
In either event, you first do the reading, then check whether and how much you actually read, and then check if what you read is of the form you expected (e.g. alphanumeric).