Read first two elements from multiple files C++ - c++

I have a 4*4 matrix in 4 files. I need to read the first two elements from each files and display it in a column. Here is an example:
File 1 File 2 File 3 File 4
1 2 3 4 2 3 4 5 3 5 8 9 1 4 6 9
3 4 4 5 3 4 5 6 6 7 9 2 6 0 8 6
1 2 4 5 4 5 6 6 8 7 6 5 4 5 6 7
1 2 3 4 4 4 7 9 3 4 5 6 5 6 7 9
I need to display first row 2 column elements from File 1, first row 2 column elements from file 2 and so on:
1 + 2 (File 1, 1st row 2 elements)
2 + 3 (File 2, 1st row 2 elements)
3 + 5 (File 3, 1st row 2 elements)
1 + 4 (File 4, 1st row 2 elements)
3 + 4 (file 1, 2nd row 2 elements)
3 + 4 (file 2, 2nd row 2 elements)
6 + 7 (File 3, 2nd row 2 elements)
and so on..
//std::fstream infile;
string st1 = "file_";
string st2 = ".txt";
string st3 = "_";
string filename;
string mystring;
float fading[16][16];
for( int row = 0 ; row < 5 ; ++row)
{
for( int column = 0 ; column < 5 ; ++column)
{
for ( int i = 1; i < 3; i++)
{
for(int j = 1; j < 3 ;j++)
{
stringstream ss, ss1;
ss << i;
ss1 << j;
filename = st1 + ss.str() + st3 + ss1.str() + st2;
std::fstream infile;
infile.open(filename.c_str());
if(infile.is_open())
{
infile >> fading[row][column];
cout << "fading[" << row << "][" << column << "] " << fading[row][column] << std::endl;
}
else
std::cout << " file " << filename << " not open" << std::endl;
infile.close();
}
}
}
}
}
I am not able to get the first row two elements from each file into a loop. Each time the file closes, the program starts from the 1 row of the first file again.

Why not read the entire matrices into memory buffers and fetch the fields you need from there? If it's really only four files with 16 entries each, that's not too expensive and you don't have the hassle of reading around in your file.

I guess You want to open the file before the loop , That will keep data pointers inside the file to the point where it last read .

Related

Reading each line from a text file, word by word and converting to int (Infinite loop or crashing?)

I'm trying to read in this text file:
8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4
9 4 3 9 9
8 2 1 5 4
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8
11 2 11 10 7
And printing it exactly as shown to the console (to make sure I got every input).
However, for some reason my code crashes after reading in the first line. I can't even terminate the debugger.
Here's my code:
while(getline(inFile, buffer)){
buffer2 = strdup(buffer.c_str());
line = strtok(buffer2, " ");
size = atoi(line);
cout << size << " ";
while(line!=NULL){
line = strtok(NULL, " ");
cout << line << " ";
}
cout << "~~~~~~~~~" << endl;
}
If you are going to use C++ you should take advantage of that, use string streams:
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std; //for sample purposes, should not be used
int main() {
int temp, count = 0, sum = 0, total = 0;
string buffer;
ifstream myFile("in.txt");
if (!myFile.is_open())
cout << "No file" << endl;
else{
while(getline(myFile, buffer)){
sum = 0;
stringstream ss(buffer);
while(ss >> temp){
count++; //number count
sum += temp; //line sum
cout << temp << " ";
}
total += sum; //total sum
cout << endl << "count: " << count << endl
<< "sum: " << sum << endl << "total: " << total << endl << endl;
}
myFile.close();
}
cout << "~~~~~~~~~" << endl;
}
You are leaking the memory allocated by strdup(). You need to call free() when you are done using buffer2.
But more importantly, strtok() returns NULL when there are no more tokens to return. But it is undefined behavior to pass a NULL char* pointer to operator<<. Your while loop is doing exactly that when it reaches the end of each line, so anything could happen, including crashing.
Try this instead:
while (getline(inFile, buffer)) {
buffer2 = strdup(buffer.c_str());
if (buffer2 != NULL) {
line = strtok(buffer2, " ");
while (line != NULL) {
size = atoi(line);
cout << size << " ";
line = strtok(NULL, " ");
}
free(buffer2);
}
cout << "~~~~~~~~~" << endl;
}
That being said, why are you using strdup(), strtok(), and atoi() at all? You are writing C++ code, you should C++ semantics instead of C semantics. For example, you can use std::istringstream instead, eg:
while (getline(inFile, buffer)) {
istringstream iss(buffer);
while (iss >> size) {
cout << size << " ";
}
cout << "~~~~~~~~~" << endl;
}
As always, there are many possible solutions. I would like to show an additional one. This is using more modern C++ elements, mainly from the algorithm and iterator library.
So, what will we do?
First we read each line as a std::string in a simple for loop with std::getline. Then we will put the line again in a std::istringstream so that we can take advantage of C++ iterator: std::istream_iterator.
This iterator will iterate over the elements in the string and extract all integers. It is like calling the extractor operator ( >> ) for all elements in the line string.
We use the iterator in the so called range constructor of os a std::vector. This inplace created vector, will be added to the destiantion data. So, as a result, we will get vector of vector of int: A 2-dimensional vector.
For debug purposes, we copy each row of intes to std::cout.
Please note that we do really need only very few and very simple statements to fulfill the task.
Please check.
#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
#include <iterator>
std::istringstream sourceFile{R"(8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4
9 4 3 9 9
8 2 1 5 4
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8
11 2 11 10 7)"};
int main()
{
// Here we will store the resulting int values
std::vector<std::vector<int>> data{};
for (std::string line{}; std::getline(sourceFile, line); ) {
// Split the line into integers and add to target array
std::istringstream iss(line);
data.emplace_back(std::vector<int>(std::istream_iterator<int>(iss), {}));
}
// Now all data is in our vector of vector of int
// Show read data on screen
std::for_each(data.begin(), data.end(), [](const std::vector<int>& v){
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << "\n";});
return 0;
}
Please note. I do not have files on SO. So I used a std::istringstream as input stream. You may of course exchange it with any other std::ftream

Read from text file into 2D array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I've got a text file which contains several lines of integers, each integer is separated by a space, I want to read these integers into an array, where each new line is the first dimension of the array, and every integer on that line is saved into the second dimension.
My text file looks something like this:
0 1 2 3 4 5 6 7 8 9
9 0 1 2 3 4 5 6 7 8
8 9 0 1 2 3 4 5 6 7
7 8 9 0 1 2 3 4 5 6
6 7 8 9 0 1 2 3 4 5
5 6 7 8 9 0 1 2 3 4
4 5 6 7 8 9 0 1 2 3
3 4 5 6 7 8 9 0 1 2
2 3 4 5 6 7 8 9 0 1
So here's what i tried so far, but it looks like a mess
string array[30][30]; //row, column
ifstream myfile("numbers.txt");
int row = 0;
int col = 0;
while(!myfile.eof())
{
//Extract columns
while(getline(myfile, array[row][col]),!'\n')
{
getline(myfile,array[row][col],' ');
col++;
}
//Extract rows
// getline(myfile,array[row][col],'\n');
// row++;
cout<< row << '\t' << array[row][col] << "\n";
}
while(!myfile.eof()) is rarely a good idea. When you've read your last line, that condition will still evaluate to true. eof() will only be set once you've tried to read beyond the last character in the file. Also, string array[30][30] is a hardcoded 30x30 C style array that doesn't fit your data. Instead, use the C++ container std::vector (that can be nested in as many dimensions as you'd like) to dynamically add numbers.
Assuming that you don't have blank lines in numbers.txt you could do like this:
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <stdexcept>
std::vector<std::vector<int>> get_2d_array_of_ints_from_stream(std::istream& is) {
std::vector<std::vector<int>> return_value;
std::string line;
while(std::getline(is, line)) { // if this fails, EOF was found or there was an error
std::istringstream iss(line); // put the line in a stringstream to extract numbers
int value; // temporary used for extraction
std::vector<int> line_values; // all values on this line
while(iss >> value) // extract like when reading an int from std::cin
line_values.push_back(value); // put the value in the 1D (line) vector
// check that all lines have the same amount of numbers
if(return_value.size() && return_value[0].size()!=line_values.size())
throw std::runtime_error("file format error");
return_value.emplace_back(std::move(line_values)); // move this line's vector<int>
// to the result_value
}
return return_value;
}
int main() {
if(std::ifstream is{"numbers.txt"}; is) {
try {
// auto arr2d = get_2d_array_of_ints_from_stream(is);
// would be the same as:
std::vector<std::vector<int>> arr2d = get_2d_array_of_ints_from_stream(is);
std::cout << "Got a " << arr2d[0].size() << "x" << arr2d.size() << " array\n";
for(const std::vector<int>& line_values : arr2d) {
for(int value : line_values) {
std::cout << " " << value;
}
std::cout << "\n";
}
std::cout << "--\n";
// or you can use the subscript style of arrays
for(size_t y = 0; y < arr2d.size(); ++y) {
for(size_t x = 0; x < arr2d[y].size(); ++x) {
std::cout << " " << arr2d[y][x];
}
std::cout << "\n";
}
} catch(const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << "\n";
}
}
}

Moving pieces in an array? C++

How could you move array characters?????????
Here is some basic code with high-level comments. It is not exactly as you desire. But since you have provided some code it is nearly there.
After reading the comments and understanding what is happening, it should be relatively straightforward to modify the below code to your requirements:
#include <iostream>
void printArray(int gameboard[5][5]){
std::cout << "This is what the gameboard looks like now:" << std::endl;
for ( int i = 0; i < 5; i++ ) {
for ( int j = 0; j < 5; j++ ) {
std::cout << gameboard[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main() {
// Declare array and print what it looks like
int gameboard[5][5] = { {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
printArray(gameboard);
// Get input for which coordinates the user wants to swap
int row1, column1, row2, column2;
std::cout << "Please enter the coordinates of the first piece:" << std::endl;
std::cout << "Row:";
std::cin >> row1;
std::cout << "Column:";
std::cin >> column1;
std::cout << "Please enter the coordinates of the second piece:" << std::endl;
std::cout << "Row:";
std::cin >> row2;
std::cout << "Column:";
std::cin >> column2;
// Swap values at provided coordinates by using a temp variable
int temp = gameboard[row1][column1];
gameboard[row1][column1] = gameboard[row2][column2];
gameboard[row2][column2] = temp;
printArray(gameboard);
return 0;
}
Example Usage:
This is what the gameboard looks like now:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Please enter the coordinates of the first piece:
Row: 0
Column: 0
Please enter the coordinates of the second piece:
Row: 4
Column: 4
This is what the gameboard looks like now:
5 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 1
Tasks TO-DO for you:
Change printArray to allow arrays of varying sizes not just 5 x 5.
Ensure user input for row, column and value are numbers.
Ensure user input row, and column values are within the bounds of the array.

How to format this output C++

I've got a map containing a word and a set of integers as the value.
I want to output the word left aligned and then the integer values in the set in columns that are lined up. I thought that this would work but it seems to output very badly.
How would I go about adjusting this so that the number columns line up with one another and have a decent amount of spaces in between them?
for (auto cbegin = ident_map.begin(); cbegin != ident_map.end(); cbegin++) {
outFile << left << (*cbegin).first << setw(10);
for (set<int>::iterator setITR = (*cbegin).second.begin(); setITR != (*cbegin).second.end(); setITR++) {
outFile << right << *setITR << setw(4);
}
outFile << endl;
}
I think that this should output correctly but it comes out looking like this:
BinarySearchTree 4
Key 4 27
OrderedPair 1 4 8 14
T 4
erase 27
first 7 13
insert 1 4
key 27
kvpair 1 4
map_iterator 1 3 8 14
mitr 3 7 8 13 14
result 4 6 7 13
result2 8 9 14 15
second 6
t 4
value_type 1
Try Boost.Format
Here is a toy example that is similar in spirit to what you want to do. The %|30t| and %|50t| formatters ensure that your numbers are left-justified at the columns 30 and 50 respectively.
#include <iostream>
#include <boost/format.hpp>
int main(int argc, char *argv[]) {
std::cout << "0 1 2 3 4 5 " << std::endl;
std::cout << "012345678901234567890123456789012345678901234567890123456789" << std::endl;
for (int i = 0; i < 10; i++) {
// Set up the format to have 3 variables with vars 2 and 3 at
// columns 30 and 50 respectively.
boost::format fmt("string %1%: %|30t|%2% %|50t|%3%");
// Append values we want to print
fmt = fmt % i;
for (int j = 0; j < 2; j++) {
fmt = fmt % rand();
}
// Write to std::cout
std::cout << fmt << std::endl;
// Or save as a string...
std::string s = fmt.str();
}
return 0;
}
Which when run, produces:
$ ./a.out
0 1 2 3 4 5
012345678901234567890123456789012345678901234567890123456789
string 0: 16807 282475249
string 1: 1622650073 984943658
string 2: 1144108930 470211272
string 3: 101027544 1457850878
string 4: 1458777923 2007237709
string 5: 823564440 1115438165
string 6: 1784484492 74243042
string 7: 114807987 1137522503
string 8: 1441282327 16531729
string 9: 823378840 143542612
How about try using \t instead of setw(). \t is the tab special character. This will do wonders for your formatting as you can just figure out the number of tabs to your first position for each line, then it is as simple as following what format you would like, works great because tab is a uniform size

File stops being read after a newline character

I'm trying to create a spam filter. I need to train the model first. I read the words from a text file which has the word "spam" or "ham" as the first word of a paragraph, and then the words in the mail and number of its occurrences just after the word. There are paragraphs in the file. My program is able to read the first paragraph that is the words and their number of occurrences.
The problem is that, the file stops reading after encountering the newline that and doesn't read the next paragraph. Although I have a feeling that the way I am checking for a newline character that is the end of a paragraph is not entirely correct.
I have given two paragraphs so you just get the idea of the train text.
Train text file.
/000/003 ham need 1 fw 1 35 2 39 1 thanks 1 thread 2 40 1 copy 1 else 1 correlator 1 under 1 companies 1 25 1 he 2 26 2 168 1 29 2 content 4 1 1 6 1 5 1 4 1 review 2 we 1 john 3 17 1 use 1 15 1 20 1 classes 1 may 1 a 1 back 1 l 1 01 1 produced 1 i 1 yes 1 10 2 713 2 v6 1 p 1 original 2
/000/031 ham don 1 kim 5 dave 1 39 1 customer 1 38 2 thanks 1 over 1 thread 2 year 1 correlator 1 under 1 williams 1 mon 2 number 2 kitchen 1 168 1 29 1 content 4 3 2 2 6 system 2 1 2 7 1 6 1 5 2 4 1 9 1 each 1 8 1 view 2
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
int V = 0; // Total number of words
ifstream fin;
fin.open("train", ios::in);
string word;
int wordnum;
int N[2] = {0};
char c, skip;
for (int i = 0; i < 8; i++) fin >> skip; // There are 8 characters before the first word of the paragraph
while (!fin.fail())
{
fin >> word;
if (word == "spam") N[0]++;
else if (word == "ham") N[1]++;
else
{
V++;
fin >> wordnum;
}
int p = fin.tellg();
fin >> c; //To check for newline. If its there, we skip the first eight characters of the new paragraph because those characters aren't supposed to be read
if (c == '\n')
{
for (int i = 0; i < 8; i++) fin >> skip;
}
else fin.seekg(p);
}
cout << "\nSpam: " << N[0];
cout << "\nHam :" << N[1];
cout << "\nVocab: " << V;
fin.close();
return 0;
}
std::ifstream::operator>>() doesn't read \n in the variable; it drops it. If you need to manipulate with whitespaces and \n symbols, you can use std::ifstream::get()