How to put strings and integers from file into a multidimensional-array? - 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.

Related

Moving through text file c++

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.

C++ won't read in scientific notation data from a .txt file

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.

Storing file data variables in a dimentional array

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/

forloop lines of arrays

int lineInputs = 0;
cin >> lineInputs;
int whatever = 0;
char* myArray = new char[arrayElements*lineInputs];
int j =0;
for(int i = 0; i < lineInputs; i++)
{
cin >> whatever;
for(j; j<total; j+=39)
{
for(int nom=0; j<arrayElements; nom++)
{
cin >> myArray[j];
}
}
}
In my forloop say i have lineInputs = 4 and total = 156
Meaning 4 times we do this, we want to insert 156 chars into my array. But we want to make it so that every 40 characters we continue entering the array.
Bsically we need to insert this input into the array but i feel like my forloops are messed up. This will be the input
4
1
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
2
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
3
HHTTTHHTTTHTHHTHHTTHTTTHHHTHTTHTTHTTTHTH
4
HTHTHHHTHHHTHTHHHHTTTHTTTTTHHTTTTHTHHHHT
The first line 4 meaning 4 of these 40 character lines. And the number above the character lines just signifying line 1 2 3 4 ect.
How can i attempt this right?
So the array would basically look like this.
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTHHTTTHHTTTHTHHTHHTTHTTTHHHTHTTHTTHTTTHTHHTHTHHHTHHHTHTHHHHTTTHTTTTTHHTTTTHTHHHHT
You are making the same fundamental mistake you made in your other question, which is to fail to treat the input array correctly. You are repeatedly reading into the first 40 characters of myArray. What you need to do is read the first line into the first 40 characters, the second line into characters 40 to 79, etc.
Better yet, make it a two dimensional array so that you don't have to muck around with computing the indices.
Even better, make it an array of std::string rather than an array of char.

Getting input from external files?

I need to get very basic input from an external file in C++. I tried searching the internet a few times but nothing really applied to what I need. This would be a .txt file that the input it coming from, and it would be filled with lines like this:
131
241
371
481
I have code already to manually get this input, and it looks like this:
using namespace std;
//Gets the initial values from the user.
int control=0;
while (rowb!=0){
cout << "Row: ";
cin >> rowb;
cout << "Column: ";
cin >> columnb;
cout << "Number: ";
cin >> numb;
row[control]=rowb-1;
column[control]=columnb-1;
num[control]=numb;
control++;
}
This is part of a program that solves sudoko boards. The inputed numbers are the initial values that a sudoko board holds, and the user is inputing the row, column, and number that comes from a board.
What I need is to be able to create a .txt file with these numbers stored in rows so that I do not have to enter so many numbers. I have very little idea how to go about doing this. Mainly I'll only be using the txt file for testing my program as I move along with adding more code to it. It takes 150+ entered numbers within my program just to get a single board, and it takes a lot of time. Any accidentally wrong entered value is also a huge problem as I have to start again. So how would I get C++ to read a text file and use those numbers as input?
Aside from the other suggestions, you can simply redirect a file to standard input, like so (where $ is the command prompt):
$ myprogram < mytextfile.txt
That will run myprogram just as normal but take input from mytextfile.txt as if you had typed it in. No need to adjust your own program at all.
(This works on both Unix/Linux systems and on Windows.)
You can open a file for input with std::ifstream from the header <fstream>, then read from it as you would from std::cin.
int main()
{
std::ifstream input("somefile.txt");
int a;
input >> a; // reads a number from somefile.txt
}
Obviously, you can use >> in a loop to read multiple numbers.
Create an std::ifstream object, and read from it just like you would from std::cin. At least if I understand what you're trying to do, the 131 as the first input is really intended to be three separate numbers (1, 3, and 1). If so, it's probably easiest to change your input file a bit to put a space between each:
1 3 1
2 4 1
3 7 1
4 8 1
Personally, I would start with a different format of the file: enter a value for each cell. That is, each row in the input file would represent a row in the sudoko board. Empty fields would use a space character. The immediate advantage is that the input actually pretty much looks like the sudoko board. Also, you would enter at most 90 characters: 9 characters for the board and a newline for each line:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
int main(int ac, char* av[])
{
std::ifstream in(ac == 1? "sudoko.init": av[1]);
char board[9][9];
for (int i(0); i != 9; ++i)
{
in.read(board[i], 9).ignore();
}
if (!in)
{
std::cout << "failed to read the initial board\n";
}
else
{
typedef std::ostream_iterator<char> iterator;
std::fill_n(iterator(std::cout << "board:\n\n+", "+"), 9, '=');
for (int i(0); i != 9; ++i)
{
std::copy(board[i] + 0, board[i] + 9, iterator(std::cout << "\n|", "|"));
std::fill_n(iterator(std::cout << "\n+", "+"), 9, (i + 1) % 3? '-': '=');
}
std::cout << "\n";
}
}
This would take input like this:
4 5 3 8
71 3
16 7
6 4 7
6 8
1 9 5
6 42
5 94
4 7 9 3
Note that each of these lines uses 9 characters. You might want to use something more visible like ..