I am writing a program which is reading in an array from a text file which has both normal integers, and also multiple numbers that are in scientific notation, of the form: #.#####E##. Here is a few sample lines of the input .txt file:
21 -1 0 0 501 502 0.00000000000E+00 0.00000000000E+00 0.17700026409E+03 0.17700026409E+03 0.00000000000E+00 0. -1.
21 -1 0 0 502 503 0.00000000000E+00 0.00000000000E+00 -0.45779372796E+03 0.45779372796E+03 0.00000000000E+00 0. 1.
6 1 1 2 501 0 -0.13244216743E+03 -0.16326397666E+03 -0.47746002227E+02 0.27641406353E+03 0.17300000000E+03 0. -1.
-6 1 1 2 0 503 0.13244216743E+03 0.16326397666E+03 -0.23304746164E+03 0.35837992852E+03 0.17300000000E+03 0. 1.
And here is my program which simply reads in the text file and puts it into an array (or more specifically, a vector of vectors):
vector <float> vec; //define vector for final table for histogram.
string lines;
vector<vector<float> > data; //define data "array" (vector of vectors)
ifstream infile("final.txt"); //read in text file
while (getline(infile, lines))
{
data.push_back(vector<float>());
istringstream ss(lines);
int value;
while (ss >> value)
{
data.back().push_back(value); //enter data from text file into array
}
}
for (int y = 0; y < data.size(); y++)
{
for (int x = 0; x < data[y].size(); x++)
{
cout<<data[y][x]<< " ";
}
cout << endl;
}
// Outputs the array to make sure it works.
Now, this code works beautifully for the first 6 columns of the text file (these columns are entirely integers), but then it completely ignores every column 6 and higher (these are the columns containing scientific notation numbers).
I have tried redefining the vectors as both types double and float, but it still does the same thing. How can I get C++ to recognize scientific notation?
Thanks in advance!
Change int value; to double value; and also change your vector to double instead of int.
Better yet, since you have three declarations that must all be synchronized to the correct type, make an alias to that type like this: using DATA_TYPE = double; then declare your vectors and such like this: vector<vector<DATA_TYPE> > data;, DATA_TYPE value;, etc. That way if you change the type of the data for whatever reason, all your vector and variable declarations will update automatically, thus avoiding these kinds of bugs.
Related
I'm trying to save numbers from first txt file to second one in reversed order.
To be clear, inside 1st txt I have typed numbers from 1 to 10 (decimal notation). When I try to count them, I get 5 or 7, depending on what's between them (space or enter).
Then, another error is that inside 2nd txt program saves as much "0s" as dl's variable value is equal to instead of loaded numbers in reversed order.
I paste the whole code, because I don't know file operation rules good enough to determine which exact part could be the source of problem. Thank You in advance.
#include <fstream>
#include <iostream>
using namespace std;
int main() {
fstream plik1;
plik1.open("L8_F3_Z2a.txt", ios::in | ios::binary);
fstream plik2;
plik2.open("L8_F3_Z2b.txt", ios::out);
if(!plik1.good() || !plik2.good()) {
cout << "file(s) invalid" << endl;
return 1;
}
plik1.seekg(0, ios::end);
int dl = plik1.tellg() / sizeof(int);
cout << "length = " << dl << endl;
int a;
for(int i = 0; i < dl; i++) {
plik1.seekg((i + 1) * sizeof(int), ios::end);
plik1 >> a;
plik2 << a;
cout << i + 1 << ". a = " << a << endl;
}
plik1.close();
plik2.close();
return 0;
}
edit the output is:
length = 7
1. a = 0
2. a = 0
3. a = 0
4. a = 0
5. a = 0
6. a = 0
7. a = 0
--------------------------------
Process exited after 0.03841 seconds with return value 0
Press any key to continue . . .
Problem
When a file is encoded as text the binary size of the data is irrelevant.
int dl = plik1.tellg() / sizeof(int);
will get you the side of the file in integers, but the file isn't storing integers. It is storing a stream of characters. Say for example the file holds one number:
12345
which is five characters long. Assuming the file is using good ol ASCII, that's 5 bytes. When 12345 is converted to an int it will probably be 4 or 8 bytes and almost certainly not 5 bytes. Assuming the common 32 bit (4 byte) int
int dl = plik1.tellg() / sizeof(int);
int dl = 5 / 4;
int dl = 1;
Yay! It worked! But only by the grace of whatever deity or cosmic entity you worship. Or don't worship. I'm not going to judge. To show why you can't count on this, lets look at
123
this is three characters and 3 bytes, so
int dl = plik1.tellg() / sizeof(int);
int dl = 3 / 4;
int dl = 0;
Whoops.
Similarly
1 2 3 4 5
is five numbers. The file length will probably be the sum of one byte per digit and one byte per space, 9 bytes.
Where this gets weird is some systems, looking at you Windows, use a two character end of line marker, carriage return and a line feed. This means
1
2
3
4
5
will sum up to 13 bytes.
This is why you see a different size depending on whether the numbers are separated with spaces or newlines.
Solution
The only way to find out how many numbers are in the file is to read the file, convert the contents to numbers, and count the numbers as you find them.
How to do that:
int num;
int count = 0;
while (plik1 >> num) // read numbers until we can't read any more
{
count++;
}
From this you can determine the size of the array you need. Then you rewind the file, seek back to the beginning, allocate the array and read the file AGAIN into the array. This is dumb. File IO is painfully slow. You don't want to do it twice. You want to read the file once and store as you go without caring how many numbers are in the file.
Fortunately there are a number of tools built into C++ that do exactly that. I like std::vector
std::vector<int> nums;
int num;
while (plik1 >> num)
{
nums.push_back(num);
}
vector even keeps count for you.
Next you could
std::reverse(nums.begin(), nums.end());
and write the result back out.
for (int num: nums)
{
plik2 << num << ' ';
}
Documentation for std::reverse
If your instructor has a no vector policy, and unfortunately many do, your best bet is to write your own simple version of vector. There are many examples of how to do this already on Stack Overflow.
Addendum
In binary 5 integers will likely be 20 or 40 bytes no matter how many digits are used and no separators are required.
It sounds like storing data as binary is the bees knees, right? Like it's going to be much easier.
But it's not. Different computers and different compilers use different sizes for integers. All you are guaranteed is an int is at least 2 bytes and no larger than a long. All of the integer types could be exactly the same size at 64 bits. Blah. Worse, not all computers store integers in the same order. Because it's easier to do some operations if the number is stored backwards, guess what? Often the number is stored backwards. You have to be very, very careful with binary data and establish a data protocol (search term for more on this topic: Serialization) that defines the how the data is to be interpreted by everyone.
I have a basic text file which has one entry per line, most entries are are numerical, however there are a few lines with the word and (evenly spaced) in them. Here is an example of one such spacing between and :
<event>
4
0
0.1005960E+03
0.2722592E+03
0.7546771E-02
0.1099994E+00
21
-1
0
0
501
502
0.00000000000E+00
0.00000000000E+00
0.17700026409E+03
0.17700026409E+03
0.00000000000E+00
0.
-1.
21
-1
0
0
502
503
0.00000000000E+00
0.00000000000E+00
-0.45779372796E+03
0.45779372796E+03
0.00000000000E+00
0.
1.
6
1
1
2
501
0
-0.13244216743E+03
-0.16326397666E+03
-0.47746002227E+02
0.27641406353E+03
0.17300000000E+03
0.
-1.
-6
1
1
2
0
503
0.13244216743E+03
0.16326397666E+03
-0.23304746164E+03
0.35837992852E+03
0.17300000000E+03
0.
1.
</event>
What I need to do is create a numerical matrix (using only the numerical values) where each column holds all the data values between each separate instance of and .
This is what I have so far:
using namespace std;
int main()
{
vector <string> data;
string str;
ifstream fin("final_small.txt");
while (fin >> str)
{
data.push_back(str);
}
fin.close(); // Close the file.
int N = data.size();
int matrix[13][19];
for (int i = 0; i < 13; i++) {
for (int j = 0; j < 19; j++) {
matrix[i][j] = data[i];
}
}
}
Obviously this is a huge work in progress. First of all, I read the text file in to a vector, which can not be of type int because of the words. This then causes problems later on when I try to input it into the matrix.
Does anyone have any suggestions?
Thanks in advance!
In C++11, use std::stoi to convert a string to an int. Note that std::stoi will throw an exception of type std::invalid_argument if the conversion cannot be performed.
Could you give some example inputs? What you could do is iterate through each line and only convert characters that are numbers. You can check this with the stdlib function isdigit() which you can see here. You can then use atoi() for numerical conversion. Hope this helps!
I have a .txt file which I'm trying to gather data from, that can then be used within variables within my code to be used in other functions.
Here's an example of my text file:
0 10 a namez 1 0
0 11 b namea 1 1
1 12 c nameb 1 1
2 13 d namec 0 1
3 14 e named 1 1
So my file will not always be the same number of lines, but always the same number of variables per line.
I currently have this, to firstly get the length of the file and then change the amount of rows within the array:
int FileLength()
{
int linecount = 0;
string line;
ifstream WorkingFile("file.txt");
while(getline(WorkingFile, line))
{
++linecount;
}
return linecount;
}
int main()
{
string FileTable [FileLength()][6];
}
Firstly I don't know if the above code is correct or how I can add the values from my file into my FileTable array.
Once I have my FileTable array with all the file data in it, I then want to be able to use this in other functions.
I've been able to do:
if(FileTable[2][0] = 1)
{
cout << "The third name is: " << FileTable[2][3] << endl;
}
I understand my code may not make sense here but I hope it demonstrates what I'm attempting to do.
I have to do this for a larger text file and all the 6 variables per line relate to be input to a function.
Hold each line in its own object, this is much clearer:
struct Entry
{
std::array<std::string, 6> items; // or a vector
};
In main:
std::vector<Entry> file_table( FileLength() );
Note that it is a waste of time to read the whole file first in order to find the number of entries. You could just start with an empty vector, and push in each entry as you read it.
Your access code:
if( file_table.size() > 2 && file_table[2].items[0] == "1" )
{
cout << "The third name is: " << FileTable[2].items[2] << endl;
}
I would actually recommend giving the members of Entry names, instead of just having an array of 6 of them. That would make your code more readable. (Unless you really need to iterate over them, in which case you can use an enum for the indices).
You could define an operator[] overload for Entry if you don't like the .items bit.
since the number of lines is dynamic I suggest to use vector instead of array. you can push back your data to the vector line by line until you read eof.
also try to study about OOP a little , it would make your code more understandable.
take look at these:
http://www.cplusplus.com/reference/vector/vector/
http://www.geeksforgeeks.org/eof-and-feof-in-c/
Lets say there is a competition, and we have x races, and y contestants.
Each race, every contestant gets a point between 0 and 10.
So there is a file, looking something like this( without the dots, of course):
Chet 10 Katie 8 Mark 3 Rachel 5
Chet 3 Katie 9 Mark 6 Rachel 8
Chet 6 Katie 6 Mark 7 Rachel 0
My problem is that here the strings and integers are alternating, and I dont know how to put them into the multidimensional-array.
Below is how I would do this, if there were only integers in a file. Is it possible to modify this so I can use it with my program?
string x;
int score,row=0,column=0;
int marray[10][10] = {{0}};
string filename;
ifstream fileIN;
cout<<"Type in the name of the file!"<<endl;
cin>> filename;
fileIN.open(filename);
while(fileIN.good()) //reading the data file
{
while(getline(fileIN, x))
{
istringstream stream(x);
column=0;
while(stream >> score)
{
marray[row][column] = score;
column++;
}
row++;
}
}
Array (even multidimensional array) are homogeneous, all the entry must be of the same type. This property let the CPU to compute the address of any entry of the array with a simple displace operation.
In your case you want to store a string and a integer. So you can simple use a struct as entry of your array.
struct Result {
Result() : point(0)
{}
std::string contestantName;
unsigned int point;
};
Result results[10][10];
the rest of the code is really similar of what you have written.
I am trying to write data from a 2D array into a binary file. I am only writing the data that has a value greater than 0. Therefore, if the data is is 0, it will not be written to the file. The data is as follows:
Level 0 1 2 3 4 5
Row 0 4 3 1 0 2 4
Row 1 0 2 4 5 0 0
Row 2 3 2 1 5 2 0
Row 3 1 3 0 1 2 0
void {
// This is what i have for writing to file.
ofstream outBinFile;
ifstream inBinFile;
int row;
int column;
outBinFile.open("BINFILE.BIN", ios::out | ios::binary);
for (row = 0; row < MAX_ROW; row++){
for (column = 0; column < MAX_LEVEL; column++){
if (Array[row][column] != 0){
outBinFile.write (reinterpret_cast<char*> (&Array[row][column]), sizeof(int)
}
}
}
outBinFile.close();
// Reading to file.
inBinFile.open("BINFILE.BIN", ios::in | ios::binary);
for (row = 0; row < MAX_ROW; row++){
for (column = 0; column < MAX_LEVEL; column++){
if (Array[row][column] != 0){
inBinFile.read (reinterpret_cast<char*> (&Array[row][column]), sizeof(int)
}
}
}
inBinFile.close();
}
All the data being read is being inserted into the first row, how can i get the data to load as i exited the program?
You are reading only when data is not equal zero, means that it gets locked with first zero. Once it reaches zero it stops reading.
Before "if command" read file to some other varaible then in if (variable != 0) Array[row][column] = variable.
If your Array is initialized with data, maybe take a look into setting position of your reading. So to set ok I have zero, I should read from another position next.
Binary files take a simple memory dump. I'm on a mac so I had to find a way to calculate the size of the array since sizeof(array name) doesn't return the memory size of the array for some reason (macintosh, netbeans IDE, xCode compiler). The workaround I had to use was:
to write the file:
fstream fil;
fil.open("filename.xxx", ios::out | ios::binary);
fil.write(reinterpret_cast<char *>(&name), (rows*COLS)*sizeof(int));
fil.close();
//note: since using a 2D array &name can be replaced with just the array name
//this will write the entire array to the file at once
Reading was the same. Since the examples from the Gaddis book I was using did not work correctly on Macintosh I had to find a different way to accomplish this. Had to use the following code snippet
fstream fil;
fil.open("filename.xxx", ios::in | ios::binary);
fil.read(reinterpret_cast<char *>(&name), (rows*COLS)*sizeof(int));
fil.close();
//note: since using a 2D array &name can be replaced with just the array name
//this will write the entire array to the file at once
Instead of just getting the size of the entire array you need to calculate the size of the entire array by multiplying the rows*columns for a 2d array then multiplying it by the size of the data type (since I used integer array it was int in this case).