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.
Related
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 read points frome a file, I use the library Lemon (because i want to use graph later) therefore each point is represented by the type : dim2 :: Point .
so I used the library lemon/dim2.h
My problem is that each point there have a number of the frame of the video, so i used this code to put variables from file in a vectors:
std::ifstream file("file1.txt");
std::vector<dim2::Point<int>> pointTable;
std::vector<int> frame;
int temp, temp2,temp3;
while (file >> temp >> temp2 >> temp3)
{
pointTable.push_back(dim2::Point<int>(temp, temp2));
frame.push_back(temp3);
}
//int tailleFmax = frame.max_size;
for (int i = 0; i < (36) ;i++)
//cout << frame[i] <<endl;
// cout << trajectoire[i].x << endl;
cout << trajectoire[i].y << endl;
My question : i dont know how to represent in c++ the connection betwen each point and his frame number and name this variable Trajectory.
Example of file :
155 // that is x
168 // that is y
0 // that is the frame number
364
245
20
546
156
I suspect that a map<int, dim2::Point<int>> is what you're looking for.
You could also simplify your code by reading in the point directly using dim2::Point's extraction operator: http://lemon.cs.elte.hu/pub/doc/latest-svn/a00862.html#g2dd3eccf5dece76c03bc6d1c2f348643
Your final code should look something like this:
ifstream file("file1.txt");
map<int, dim2::Point<int>> frame2PointTable;
pair<int, dim2::Point<int>> temp;
while(file >> temp.second >> temp.first) frame2PointTable.insert(temp);
To output this you could do something like:
for(const auto& i : frame2PointTable) cout << i.first << ": (" << i.second.x << ", " << i.second.y << ")\n";
Important notes:
Your example file contains 3 points but only 2 frame numbers, in this case only the 2 frame number-point combinations would be inserted
If you ever have multiple identical frame numbers in a file, only the first instance will be accepted by frame2PointTable
I've written you a live example using pair<int, int> instead of dim2::Point here: http://ideone.com/qtCZ8L
I have looked for a day or so on StackOverflow and other sites, and I can't find a solution to my problem. There are some that are similar, but I can't seem to make them work.
I have a tab-delimited .txt file. One line contains a heading, and 500 lines after that each contain an integer, an integer, a float, an integer, and an integer, in that order. I have a function that is supposed to read the first and third values (the first integer and the float) from each line. It skips the first line. This is in a do-while loop, because I need to be able to process files of different lengths. However, it's getting stuck in the loop. I have it set to output the mean, but it just outputs zeros forever.
void HISTS::readMeans(int rnum) {
int r;
char skip[500];
int index = 0; int area = 0; double mean = 0; int min = 0; int max = 0;
FILE *datafile = fopen(fileName,"r");
if(datafile == NULL) cout << "No such file!\n";
else {
//ignore the first line of the file
r = fscanf(datafile,"%s\n",skip);
cout << skip << endl; //just to check
//this is the problematic code
do {
r = fscanf(datafile,"%d\t%d\t%f\t%d\t%d\n",&index,&area,&mean,&min,&max);
cout << mean << " ";
} while(feof(datafile) != 1)
}
fclose(datafile);
}
Here is a sample data file of the format I'm trying to read:
Area Mean Min Max
1 262144 202.448 160 687
2 262144 201.586 155 646
3 262144 201.803 156 771
Thanks!
Edit: I said I need to read the first and third value, and I know I'm reading all of them. Eventually I need to store the first and third value, but I cut that part for the sake of brevity. Not that this comment is brief.
You should do it C++ style,
#include <iostream>
#include <fstream>
int main() {
std::ifstream inf("file.txt");
if (!inf) { exit(1); }
int idx, area, min, max;
double mean;
while (inf >> idx >> area >> mean >> min >> max) {
if (inf.eof()) break;
std::cout << idx << " " << area << " " << mean << " " << min << " " << max << std::endl;
}
return 0;
}
It is :
1) Easy to read.
2) Less code, so less chance of error.
3) Correct handling of EOF.
Although I have left handling of first line, that is upto you.
fscanf returns the number of arguments read. Thus, if it returns less than 5 you should exit the loop.
OP ended up using operator>>, which is the correct way to do this in C++. However, for the interested C reader, there were a couple of issues in the code posted:
mean was declared as double but read using the wrong format specifier %f instead of %lf.
The first line wasn't completely read, but only the first token, Area.
A possible way to implement the desired task is as follows:
r = fscanf(datafile,"%[^\n]\n",skip);
// ^^^^^ read till newline
while ( (r = fscanf(datafile,"%d%d%lf%d%d",&index,&area,&mean,&min,&max)) == 5 ) {
// ^^ correct format specifier for double
// ...
}
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
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.