I am trying to see what is the easiest way to read input from a text file with information:
7
12
v1-v2 7
v1-v3 11
v1-v4 1
v2-v4 12
v2-v5 5
v3-v4 8
v3-v6 10
v4-v5 6
v4-v6 3
v4-v7 4
v5-v7 9
v6-v7 2
Normally this should be very simple but I need to account for those first 2 lines which contain 2 different numbers needed.
So far I have set up:
int nodes;
int lines;
string line;
int count=0;
while(cin) {
getline(cin, line);
for(int i = 0; i < line.length(); i++) {
if(count >2)
break;
if(! (s[i] >= '0' && s[i] <= '9')
break;
else if(count=0) {
nodes = s[i]-'0';
}
else
lines = s[i]-'0';
count++;
}
//Space for code to account for other lines
}
So this is a round about way of getting those first 2 numbers but I believe there should be an easier way of doing this. Any suggestions or if someone can point me in the right direction
Why would you not read in the two numbers before the loop:
cin >> nodes >> lines;
In case there is nothing on the input the variables will be set to 0.
If you need to handle this in a better way, you can do something similar to this:
if (cin) cin >> nodes;
else { /* handle error situation */ }
if (cin) cin >> lines;
else { /* handle error situation */ }
Related
I was solving ArithmaticII.I am getting correct output for the below input
Input:
4
1 + 1 * 2 =
29 / 5 =
103 * 103 * 5 =
50 * 40 * 250 + 791 =
Output:
4
5
53045
500791
I am getting correct output ,But when i am submitting my solution to spoj , I
am getting runtime error as SIGABRT ,Due to the overflow issue I am using stoll,When i tried to debug my program everything was seemed to be running fine .
Note->It may also contain spaces to improve readability.
This line looks suspicious to me because my programs stops(runtime error) when i doesn't provide
space in the input (1 * 1+2=)
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoll
Please help where I am doing wrong?
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main() {
int t;
string str;
cin >> t;
while (t--) {
///using cin.ignore() as input as preceded by a single line
cin.ignore();
getline(cin, str, '\n');
stringstream split(str);
///now use getline with specified delimeter to split string stream
string intermediate;
int flag = 0;
long long int ans=1;
while (getline(split, intermediate, ' ')) {
if (intermediate == "=") {
cout << ans<<"\n";
break;
}
if (intermediate == "*") {
flag = 1;
continue;
}
else if (intermediate == "/") {
flag = 2;
continue;
}
else if (intermediate == "+") {
flag = 3;
continue;
}
else if(intermediate == "-"){
flag = 4;
continue;
}
if (flag == 1) {
ans *= stoll(intermediate);
}
else if (flag == 2) {
ans /= stoll(intermediate);
}
else if (flag == 3) {
ans += stoll(intermediate);
}
else if (flag == 4) {
ans -= stoll(intermediate);
}
else if (flag == 0) {
ans = stoll(intermediate);
}
}
}
}
Using exactly the input you posted above:
4
1 + 1 * 2 =
29 / 5 =
103 * 103 * 5 =
50 * 40 * 250 + 791 =
I'm able to reproduce your error:
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoll
Aborted
I'll bet you removed the newlines in the sample input to simplify things--that's what it looks like from your code anyways. You're doing a getline and pulling exactly as many lines as you're told in the first input. That means you'll pull an empty line (intermediate will be an empty string) and you'll try to process it.
And what happens when you try to call stoll("")? The error you got!
You could try to check if you get an empty line and then continue, something like:
getline(cin, str, '\n');
if(str.empty()) {
t++; //we didn't actually do anything, so increment t
continue;
}
stringstream split(str);
...
Or, you could use the fact that the >> operator already stops when it hits whitespace (and eats all the whitespace it can to get to the next edible character). So instead of reading a line at a time, you could continue reading until you hit a = character.
cin >> t; does not eat the newline character after reading the number 4 from the input. As the program enters the loop cin.ignore() finishes the first line of the input and then getline(...) reads a blank line. You get an empty string which cannot be converted to an int.
Putting one more cin.ignore() after reading t fixes the runtime error.
You still have to handle the case when there are no spaces between the tokens. This requires rethinking the inner while loop:
long long int ans;
char op;
split >> ans;
while (split >> skipws >> op) {
if (op == '=') {
cout << ans << '\n';
break;
}
long long int n;
split >> n;
if (op == '*')
ans *= n;
else if (op == '/')
ans /= n;
else if (op == '+')
ans += n;
else if(op == '-')
ans -= n;
}
I'm trying to find the fastest way for getting numbers from file. There can be negative numbers. My e.x. input:
5 3
-5 -6 2 -1 4
1 2 3 4
4 3 2 1
I'm using:
getline(cin, line);
istringstream linestream(line);
linestream >> var;
The result is okay but my program has run time error with last test, maybe min. 100 000 numbers. My question is, is there a faster way to get string and split it to numbers than my solution? The time is the most important.
If there's only numbers in your input, you could do:
std::vector<int> numbers;
int i;
while(cin >> i) {
numbers.push_back(i);
}
To stop the input from cin you'll need to send the EOF (End Of File) signal, which is either Ctrl+D or Ctrl+Z depending on your OS.
The input from a file will automatically stop when the end of the file is reached.
See c++ stringstream is too slow, how to speed up?
For your runtime error, you didn't post compilable code, and your error is in what you didn't post.
The best is make a function that reads a file line by line and puts each line elements in an array( if you are just printing just print it dont store in an array).I am using c function instead of c++ streams because for large data they are faster.The function should use fgetc which is faster than fscanf when used for large data.If in your system fgetc_unlocked works fine then you should replace that to fgetc
-5 -6 2 -1 4
1 2 3 4
Assume the input is like above and is stored in input.txt. Just make the input.txt in your dir and run the following code in the same dir. You can make changes later how you want to use the numbers
#include<iostream>
#include<cstdio>
using namespace std;
#define GC fgetc // replace with fgetc_unlocked if it works in your system(Linux)
//This function takes a line of f and put all integers into A
//and len is number of elements filled
void getNumsFromLine( FILE* f, int *A, int& len){
register char ch=GC(f);
register int n=0;
register bool neg = false;
len=0;
while( ch!='\n' ){
while( ch !='-' && (ch>'9' || ch<'0') ) ch=GC(f);
if( ch=='-') {
neg = true;
ch = GC(f);
}
while( ch>='0' && ch<='9' ){
n = (n<<3)+(n<<1)+ch-'0';
ch = GC(f);
}
if(neg) {
n=-n;
neg=false;
}
A[len++]=n;
n=0;
}
}
int main(){
FILE* f=fopen("input.txt", "r");
int A[10][2],len;
for( int i=0; i<2; i++ ){
getNumsFromLine( f, A[i], len );
for( int j=0; j<len; j++ ) cout << A[i][j] <<" ";
cout << endl;
}
fclose(f);
return 0;
}
I have a txt file with numbers with this format 12345678-A plus some random numbers and text in between. I need to read the file and save only the 8 digit integrers to an array. How do I do it?
Current code I have, works if there are numbers only:
const int MAX = 1000;
ifstream file("file.txt");
int data;
int index = 0;
int bigdata[MAX];
while (!file.eof() && index < MAX)
{
file >> data;
if (data > 20000000 && data < 90000000)
{
bigdata[index] = data;
index++;
}
}
Sample of input text:
48251182-D 6,5 6
49315945-F 7 3
45647536-I 3,5 3
45652122-H 7 6,5
77751157-L 2 2,5
75106729-S 2 5
77789857-B 4 3 3,5 3
59932967-V 4 8,5
39533235-Q 8 8,5
45013275-A 5 2
48053435-Y 6 8
48015522-N 3,5 4
48015515-T
48118362-B 7,5 3,5
39931759-Q 5,5 3
39941188-D 3,5 1,5
39143874-I 3,5 4
48281181-O 6,5 6
If all you need is to strip out the first number in each line then you can use the stream's operator >> to read in the integer part and then use std::getline to consume the rest of the line. Using
std::vector<int> data;
ifstream fin("file.txt");
int number;
std::string eater;
while (fin >> number) // get first 8 digit number. stops at the '-'
{
data.push_back(number);
std::getline(fin, eater); // consume the rest of the line
//now we are on the next line
}
// now data has all of the numbers that start each line.
You need this:
...
#include <string>
...
string line;
while (getline(file, line)) // read the whole line
{
int data = stol(line); // get number at start of line (stops
// automatically at the '-' sign
// data is the 8 digit number
// process data here...
...
}
...
One solution to this problem would be to read the stream character by character and search for 8-digit numbers:
static const int MAX = 1000;
int index = 0;
int bigdata[MAX];
int value = 0;
int digits = 0;
for (auto c = file.get(); c != EOF 0; c = file.get())
{
if (c >= '0' && c <= '9')
{
value = (digits ? (value * 10) : 0) + (c - '0');
++digits;
if (digits == 8)
{
if (index < MAX)
bigdata[index++] = value;
digits = 0;
}
} else
{
digits = 0;
}
}
The code reads byte by byte and builds an integer number if decimal digits are read. If the digit count reaches 8 the number is stored and the integer number buffer is reset. The integer number buffer is reset immediatly if the character read is not a decimal digit.
istream.get() returns EOF if reading past the end of the file so no need for a call to the .eof() member function.
Please note that this code stores all 8-digit numbers. You have to add another test if you need only numbers in the range 20000000..90000000.
If your lines are always starting with an 8-digit number followed by a minus then you could use this simple solution which I would recommend because of improved readability.
std::string buffer;
std::vector<int> target;
while (std::getline(file, buffer))
target.push_back(atoi(buffer.c_str()));
But this solution does not check for the presence of a valid number and simply stores 0 for each line not starting with a number.
I am having issues with the following code and I cant figure out why out of loop is not being printed. With this code I want the program to ignore any spaces inputted by the user and after a space is inputted the number previously entered is stored in an array location. Like this I want 6 and 78 to be stored in 2 array locations not store them individually as 6 7 8.
This is my code:
while ((in=getchar()) != '0')
{
if (in == ' ')
{
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
input[i]=in;
}
i++;
}
printf("Out of Loop");
My output when inputting 5 6 78 is:
assigning
space
assigning
space
assigning
assigning
assigning
With this output I doubt whether 78 is being stored in one memory location.
I would really appreciate your help,Thankyou
C++:
std::vector<int> v;
std::string s;
int i;
std::getline( std::cin, s); // read full line with whitespaces
std::istringstream iss( s); // prepare to process the line
while( iss >> i) v.push_back( i); // read into i and push into vector if
// operator>> was successful
C:
int array[ 10];
int i = 0, retval;
while( i < 10 && ( retval = scanf( "%d", &array[ i++])) == 1) ;
if( i == 10) {
// array full
}
if( retval == 0) {
// read value not an integer. matching failure
}
if( retval == EOF) {
// end of file reached or a read error occurred
}
You are deciding character by character. Thus, you will only store single digits or ignore those digits.
You could store the whole numbers like this (extending your code):
bool currentNumberStarted = false;
int currentNumber = 0;
int idx = 0;
while ((in=getchar()) != '0')// you probably want '\0' instead of '0'
{
if (in == ' ')
{
if (currentNumberStarted)
{
input[idx]=currentNumber;
idx++;
currentNumberStarted = false;
}
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
currentNumberStarted = true;
currentNumber *= 10;
currentNumber += in;
}
}
printf("Out of Loop");
First of all I highly doubt that your while loop will ever end, even if you made that to '\0' ,Because you are using char variable to store input. Not strings, Only strings uses '\0' at the end,How can we enter '\0' from keyboard..???. even if you want to keep it as '0',you would alwasy have to enter 0 as last number to end the loop(which i think you dont want to.)
So the Solution is this:-
After Entering Numbers You will Hit ENTER key, which would generate a newline character '\n' so you have to check for new line character('\n'), And as you are using getchar() function, it will returns EOF (-1) at the end of input, so its important to check for it too.So you have to check for both '\n' and EOF at once in while loop.And at last you should also check for array index number(it should be less than 1) in which you are storing numbers.
I made some effort to make you understand the program in comments.
int main()
{
int i=0;
int input[10]={0}; //here only 10 integers can be entered(hence i should be i<10)
int in; //To store input character
int num=0; //To store number which is converted from character.
int new=1; //To check if new number is started 0=false 1=True.
int count=0;//This is just to know how many numbers entered,also used to print numbers at end.
while ((in=getchar()) != '\n' && (in!=EOF) && i<10)//should check for both '\n' and EOF and array index also
{
if (in == ' ')
{
printf("space\n ");
if(new==0) //if new Number is not started yet.
{
new=1; //Start of a New number.(a number entered after space)
i++; //As new number is started it should be stored in new array index.
}
continue; //if space is entered just go to begining
}
else
{
printf("assigning\n ");
num=in-48; //converts a character to number (ex:- converts '3' to 3)
input[i]=(input[i]*10)+num; //storing the number..This is important do a paper work to understand this step.
new=0; //still in same number(we are still processing same number)
}
}
printf("Out of Loop \n");
count=i+1; //This gives correct count of numbers entered
for(i=0;i<count;i++) //to print numbers.
printf("%d ",input[i]);
return 0;
}
OUTPUT:-
E:>example.exe
78 2 65 998 1
assigning
assigning
space
assigning
space
.
.
.
space
assigning
Out of Loop
78 2 65 998 1
So I have a data file that looks something like this:
x + y + z
30 45 50
10 20 30
The only characters I needed was the operators, so '+' '+' I was able to use file.get() to successfully get those characters and put them in an array. Problem is I need to get the next line of numbers, and assign them to the values x , y z . I know I cant use .get() , I would have to use getline. Will i have to eliminate the file.get() and use getline instead for first part also?
I looked at some of the questions posted on here but none of them were quite like mines. Note I'm actually going to be using these values for another part of my program, just used cout to see if my values were being read correctly
Here's my previous code:
main(int argc, char *argv[])
{
int a=0;
int n;
fstream datafile;
char ch;
pid_t pid;
int a, b, c, result;
string line;
datafile.open("data1.txt");
if(datafile)
{
for(int i=0; i <9; i++)
{
datafile.get(ch);
if (ch == '*'||ch == '/'||ch == '+'||ch == '-')
{
operations[a] = ch;
cout<<operations[a];
a++;
}
}
}
else
cout<<"Error reading file";
}
So this is how I was getting the first line of the file in the beginning. It worked like I wanted it to, may have not been the nicest coding but it worked. Nevertheless I tried to get the rest of the file, this time using getline, but instead of getting the numbers I was getting a bunch of random gibberish/numbers. I know if I use getline, the first line cannot be in my loop. I know this is how I would get the numbers.
while(getline(datafile, line))
{
istringstream ss(line);
ss >> x >> y >> z;
cout<<x<<""<<y<<""<<z;
}
Would the following make sense for the first line, or am I missing something:
string input;
std::getline(datafile, input)
for (int i = 0; i < input.size(); i++)
if (input[i] == '+' || ...)
{
operations[a] = input[i];
a++;
}
If you don't want to use getline, you could simply read the entire file stream (note that the bool is a rather naive way to handle the problem, I'd recommend something more elegant in your actual code):
bool first = true;
string nums;
int lines = 0;
vector<vector<int>> numlines;
vector<int> topush;
while (!datafile.eof())
{
char ch = datafile.get()
if (ch == 12 && first) //I don't know if '\n' is valid, I'd assume it is but here's the sure bet
first = false;
else if (first && (ch == '+' || ...))
{
operator[a] = ch;
a++;
}
else if (!first && (ch >= '0' && ch <= '9'))
{
if (!(datafile.peek() >= '0' && datafile.peek() <= '0'))
{
numlines[lines].push_back(atoi(nums.c_str());
nums.clear();
if (datafile.peek() == 12)
{
numlines.push_back(topush);
lines++;
}
}
else
nums = nums + ch;
}
Honestly, I can't be sure the above will work exactly right, I'd recommend you just modify your code to use getline exclusively. You'll need to add #include to get atoi.
Add this to your code:
while(!datafile.eof()){
string s;
getline(datafile, s);
istringstream in(s);
string tmp;
while(in >> tmp){
int i = stoi(tmp)
//Do something with i....
}
}