I am attempting to write a program that reads in integers from an input file and outputs a dynamic array. This array would be the size of the input. For verification, I'd also like to print the array. The output will be passed to a function to create a sorted linked list.
I tried the following, but it did not work:
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int get, count = 0;
while (input >> get)
count++;
cout << "Number of integers: " << count << endl;
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
delete[] array;
Here's an online example of my code.
The problem is that the output shows some weird numbers, completely unrelated to the input:
Number of integers: 8
-1217944384
-1217944384
-1
538976266
540226080
824193844
Where did I go wrong?
As πάντα ῥεῖ pointed out, the solutions that I did provide are not totally safe, that's why I will provide a third example, using boost::spirit.
See the points fast fix and good solution, as well as πάντα ῥεῖ's answer to get it working without using boost.
my personal favourite solution: note that this example does require to have read the text file into a string.
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
template<typename Iterator>
bool
parse_numbers(Iterator first, Iterator last, std::vector<int>& v)
{
bool r =
boost::spirit::qi::parse(first, last,
// Begin grammar
(boost::spirit::qi::int_[boost::phoenix::push_back(
boost::phoenix::ref(v), _1)]
% *(boost::spirit::qi::char_("a-zA-Z")
| boost::spirit::ascii::space)));
if (first != last) // fail if we did not get a full match
return false;
return r;
}
const std::string s = "23 43 12 67 \n18 15 22\n12 xxx 23 12 xx 34556 11 11 www";
std::string::const_iterator start = s.begin(), stop = s.end();
std::vector<int> results;
parse_numbers(start, stop, results)));
for(int i : results)
std::cout << value << ' ';
the result would be, as expected:
23 43 12 67 18 15 22 12 23 12 34556 11 11
The above example is partially built on the example given in the boost::spirit documentation.
input >> get moves the current curser position, so after your while loop you have nothing left to read.
fast fix:
ifstream input;
input.open("file.txt");
int get, count = 0;
while (input >> get)
count++;
input.close();
input.open("file.txt");
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
input.close();
delete[] array;
To close and reopen the stream should work, but there are more efficient solutions out there...
good solution:
One could be to read and insert into a dynamically growing vector for example. See the documentation for further reference.
std::vector<int> dataArray;
while (input >> get)
{
dataArray.insert(dataArray.end(), get);
}
for(auto&& value : dataArray)
{
std::cout << value << std::endl;
}
That would have multiple advantages:
allocating the vector on the stack prevents you from being forced to call delete. An alternative would be a standard smart pointer.
the for each loop works even without counting the elements. If you need the number of elements you could just ask the vector about his size.
Your code has several misconceptions and flaws:
(1) After applying this loop to count your inputs
while (input >> get)
count++;
the input stream's state is left over the result of last extraction operation (input >> get) that has failed. Thus no further input can be read, without completely resetting the stream.
(2) The second loop you're showing
for (int i = 0; i < count; i++) {
input >> array[i];
}
uses the input stream in invalid state (the whole stream was already read to input.eof()), and thus reading from it results in 'weird values' (in other words: It's undefined behavior at this point).
I would write the following proven code to solve this
// Your literal input file formatting goes here
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int current;
vector<int> allIntInputs;
while (input >> current || !input.eof()) {
if(input.fail()) {
input.clear();
string crap;
input >> crap; // read anything up to the next
// whitespace delimiter (the default deleimiters)
continue; // with the next item
}
// Everything's fine we'll add another number
allIntInputs.push_back(current);
}
// Print all integer values extracted
cout << "Integer values read from input:" << endl;
for(vector<int>::iterator it = allIntInputs.begin();
it != allIntInputs.end();
++it) {
if(it != allIntInputs.begin()) {
cout << ' ';
}
cout << *it;
}
cout << endl;
Output
Integer values read from input:
23 43 12 67 18 15 22 12 23 12 34556 11 11
Related
I have a file and I want to read in those elements into structs.
The file is structured like this:
n
m
lat1 lon_1
...
lat_n lon_n
nodeStart_1 nodeTo_1 nodeweight_1
...
nodeStart_m nodeTo_m nodeweight_m\
And this is the content of my file:\
3
4
48.5 6.6
48.3 5.5
48.3 4.8
23 24 25
26 27 28
29 30 31
29 41 43\
The numbers inside the file are just random ones.
n and m are integers, lan and lon are floats and the m edges are integers as well.
I have n nodes and m edges. So the 2nd to the n+2nd line should be read into nodeGr and all the m lines after that should be read into edgeGr.
These are my structs:
struct edgeGr{
int s,t,c;
}
struct nodeGr{
float lat, lon;
};
And here is my code, which doesn't work properly:
The problem is with reading in the nodes. I got it to work with lat and lon being integers but not with them being floats. When lat and lon are floats my edges are behaving weird and just become 000. I am not sure what exactly is wrong anymore since I tried way too many things and none of them work. Can you help me or give me some hints?
EDIT: it now works but the while loop is being executed twice, why is that?
void readGraph(std::ifstream & in, struct edgeGr edges[], struct nodeGr nodes[]){
int n;
int m;
while (!in.fail()){
in >> n;
in >> m;
for (int i = 0; i < n; i++) {
//TODO: get this to work
in >> nodes[i].lat >> nodes[i].lon;
}
for (int i = 0; i < m; i++) {
in >> edges[i].s >> edges[i].t >> edges[i].c;
std::cout << edges[i].s << edges[i].t << edges[i].c << '\n';
//This prints out all my edges just fine but twice and only if lat and lon are integers.
}
}
in.close();
std::cout << m << " " << n;
};
int main() {
std::ifstream in("test.txt");
nodeGr nodes[3]; //3 should be n
edgeGr edges[4]; //4 should be m
readGraph(in, edges, nodes);
std::cout << '\n' << edges[1].s <<" "<< edges[1].t <<" "<< edges[1].c << '\n';
return 0;
}
it now works but the while loop is being executed twice, why is that?
while (!in.fail()){
Because the read doesn't fail in the first iteration.
If you want to have the content of the loop be executed once, you can easily achieve that by moving it outside the loop.
Note that hard-coding the size of the array, and the accepting user input to access indices of the array without validation is a recipe for buffer overflow.
I want to make a program that works with integers that were inputted using space and not enter. when you input the integers 12 80 33 99 with space between each one of them, then the code will separate the integers and put them into an array.
I'm using codeblocks, C++
int main(){
int A;
int j [10] ={0,0,0,0,0,0,0,0,0,0};
cin >> A;
string As;
bool code = true;
int hasil [A][10];
getline(cin,As);
for (int i = 0 ; i < A ; i++){
while (code){
if( cin.get() != '\n'){
cin >> hasil[i][j[i]];
j[i]++;
}else{ code = false;}
}}
for (int i = 0 ;i < A ; i++){
for (int x = 0; x != j[i]; x++){
cout << hasil[i][x]<< " " ;
}
cout << " " << endl;
}
return 0;}
When I input 25 17 70 88, I expected the output to be 25 17 70 88 too, but the actual output was 5 17 70 88. Where is my first 2?
Your 2 was eaten by the call to cin.get() which reads one character which your code then throws it away.
I can't understand exactly what you are trying to do but i can see an error in your code which might cause undefined behaviour. int hasil[A][10] is a static array which means compiler must know its size at compile time, however A is not a compile time constant. If you don't know the size of your array you should use a pointer instead or even better a std container such as std::vector.
To make your code more readable you can also delete the code variable and replace your first for loop body with
while(cin.get() != '\n)
{
cin >> .....
...
}
I want to read a text file line by line (I do not have many integers in each line). I want to sort each line and put them into a vector of a vector. The problem is I cannot insert them into vector line by line. I cannot let them stop at the end of the line. This is what I have now. Can anyone help me?
For example, my text file like this:
1 5 3 7 29 17
2 6 9 3 10
3 89 54 67 34
I want my output like this:
1: 1 3 5 7 17 29
2: 2 3 6 9 10
3: 3 34 54 67 89
vector<int> v;
vector<vector<int>> G_AL;
if(line!=0){ // Build matrics
string lines;
while (getline(fin, lines)) {
istringstream os(lines);
float temp;
while(os >> temp ) {
if(temp != '\n') {
v.push_back(temp);
sort(v.begin(), v.end());
// get v
}
else
{
}
G_AL.push_back(v);
}
}
}
Try this:
std::stringstream fin("2 1 3\n4 6 5\n10 9 7 8"); // Test data
std::vector<std::vector<int>> G_AL;
std::string lines;
while (getline(fin, lines)) {
std::istringstream os(lines);
std::vector<int> v;
float temp;
while(os >> temp)
v.push_back(temp);
sort(v.begin(), v.end());
G_AL.push_back(v);
}
for (size_t i=0; i<G_AL.size(); ++i)
{
std::cout << i+1 << ": ";
for (auto const & v : G_AL[i])
std::cout << v << " ";
std::cout << std::endl;
}
There are some problems in the code you provided:
The v vector is declared outside of the loop, so the values keeps accumulating every line since v is not cleared. Declaring it inside the loop fixes the problem and avoid having to clear it.
The sort can be done only once we finished reading the line.
You push the v vector into G_AL after ever value instead of after every line.
You compare a float with a character (\n), which doesn't work. In fact, the line os >> temp will evaluate to false if there is no floating point value to read, so there is no need to test once more for the end of the stream.
I am currently trying to read information from an .txt file and essentially store this appropriately. Data from the input file would look something like this
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
765DEF 01:01:05:59 enter 17
ABC123 01:01:06:01 enter 17
765DEF 01:01:07:00 exit 95
ABC123 01:01:08:03 exit 95
My question is that, assuming I have read "01:01:05:59" into a string, how do I parse this to store the numbers in an int variable. In addition, all I really need is the third pair of numbers in that string(from the left) and I was also wondering how to skip the first two and last pair of numbers in that string. I have read on delimiters but I'm a little confused on how to use them. The code I have so far is shown below and is basically that information to strings.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
int arr[25];
ifstream File;
File.open("input.txt");
for (int a = 0; a < 25; a++)
{
File >> arr[a];
}
for (int i = 0; i < 25; i++)
{
cout << arr[i] << " ";
}
cout << endl;
string license, datetime;
File >> license >> datetime; // reads in license plate and datetime information into two separte strings
cout << license << endl << datetime;
system("pause");
}
Background:
If we know the start and end indices (or the length) of the sub-string we need, then we can read it by using std::string::substr.
Its usage is as follows:
#include <string>
...
std::string foo = "0123456789stack:overflow";
// start index = 4, length = 2
std::string subStr1 = foo.substr(4,2); // result = "45"
// start index = 3, end index = 5 => length = 5 - 3 + 1 = 3
std::string subStr2 = foo.substr(3,3); // result = "345"
// The first parameter is the start index whereas the second one is
// the length of the wanted sub-string.
// If only the start index is known:
std::string subStr2 = foo.substr(9); // result = "9stack:overflow"
// In that case we get the rest of the string starting from the start index 9.
For more information on that please refer to: http://www.cplusplus.com/reference/string/string/substr/
Suggested solution to the OP:
Since you said "all I really need is the third pair of numbers" then you need two characters starting from index 6:
std::string a = "01:01:05:59";
std::string sub = a.substr(6, 2); // will give you "05"
then convert them using:
int number = std::stoi(sub);
These steps can be shortened to:
int number = std::stoi( a.substr(6, 2) );
Further references:
First part: http://en.cppreference.com/w/cpp/string/basic_string/substr
Second part: How to parse a string to an int in C++?
PS: if you want to use character array instead of std::string then you just can get the characters with their corresponding indices. For example: i = 6 and i = 7 in your specific case. Then, get yourArray[6]=0 and yourArray[7]=5. Then perform integer conversion on them.
Could you do:
int num = std::stoi(string.substr(6, 2);
assuming I have read "01:01:05:59" into a string
One easy way is using streams:
#include <iostream>
#include <sstream>
int main()
{
int n[4];
std::istringstream iss("02:30:41:28");
if (iss >> n[0] && iss.get() == ':' &&
iss >> n[1] && iss.get() == ':' &&
iss >> n[2] && iss.get() == ':' &&
iss >> n[3] >> std::ws && iss.eof())
std::cout << n[0] << ' ' << n[1] << ' ' << n[2] << ' ' << n[3] << '\n';
else
std::cerr << "parsing error\n";
}
On ideone.com
I am doing a program that outputs a list of prime numbers with fstream.
I have this so far:
int export_list (int lim = 50)
{
int x;
last_in_txt = ????????????; // assigns last number on txt
ofstream file ("Primes.txt" , ios::app);
if (file.is_open()) // if it opens correctly
{
for (x = last_in_txt ; x < lim ; x++)
{
if (check_prime (x)) // returns 1 when x is prime, returns 0 when not
{
file<< x << " ";
}
}
cout << "Done!" << endl << pressenter;
cin.get();
}
else
{
cout << "Unable to open file" << endl << pressenter;
cin.get();
}
return(0);
}
So, as you can see, this should append a list of prime numbers to Primes.txt, starting with the prime 1234547.
Primes.txt looks like this:
2 3 5 7 11 13 17 19 23 29 31 37 (...) 1234543 1234547
My question is how do I assign 1234547 (which is the last number of the txt) to the variable last_in_txt?
Other (not so important) question:
Should I save the numbers the way I'm currently doing, or should I store each number in a separate line?
One simple way: keep reading and assign until the whole file is read.
For example,
int last_in_txt = 0;
{
ifstream infile("Prime.txt");
int k;
while(infile >> k) {
last_in_txt = k;
}
}
// Now last_in_txt is assigned properly, and Prime.txt is closed
This works well no matter the numbers in Prime.txt are separated by space characters (' ') or by newline characters ('\n').
My suggestion is that you write using binary format into the text file(using wb in C). In this case you will know how many bytes does the last number occupy and you will be able to use seekg and tellg to get it. If you use plain text format you will have to read char by char from the end and this is more error-prone and also slower.