My Code is reading a set of Elements from a file and adds those to a Vector. The for-loop reads all the elements and via push_back they are added to the vector. Works perfectly fine on paper BUT: In the end all the Elements in the Vector are equal and always the last read element.
I am 100 percent certain the Elements listed in the File aren't the same (because of the good old NotePad++). Ive tried to c-out the read in elements to check if there is a problem with the f_read function. The Program outputted the Elements perfectly fine and in the right order. I am guessing the error isn't with the file or the f_read function.
FILE* f = fopen(filepath, "rb");
unsigned char header[19];
fread_s(header, sizeof(header), sizeof(unsigned char), 19, f);
vector<char*> myVector;
int size = 28 * 28;
char temp[28 * 28];
for (int i = 0; i < 2; i++) {
fread_s(temp, 28*28, sizeof(unsigned char), size, f);
myVector.push_back(temp);
}
( the 19 bits i am reading into the "info" char array are the header)
I Expect the Vector to contain all the Read Elements in the right order.
As mentioned in the comments, you are pushing the pointers back not the actual strings. To get the actual strings you can do this:
void readFileToVec()
{
ifstream file;
file.open ("rb");
vector<string> v;
string word;
while (file >> word)
{
v.push_back(word);
}
}
This will work if the elements are all strings and are seperated by a space,tab, or newline. If your words are seperated by anything other than one of these three (for example a list of words separated by commas) then you can use getline and specify the separator.
In any case, reading about C++ streams and the difference between C-style strings and STL strings would be worthwhile if you intend to do this sort of thing with C++ again. You are using C Strings and old school FILE which is part of the C Library while C++ provides you with utilities to make your life easier. File streams and C++ strings are great examples of such utilities.
Related
First of all, I didn't code in C++ for more then 8 years, but there is a hobby project I would like to work on where I ran into this issue.
I checked a similar question: Only printing last line of txt file when reading into struct array in C
but in my case I don't have a semicolon at the end of the while cycle.
Anyway, so I have a nicknames.txt file where I store nicknames, one in each line.
Then I want to read these nicknames into an array and select one random element of it.
Example nicknames.txt:
alpha
beta
random nickname
...
Pirate Scrub
Then I read the TXT file:
int nicknameCount = 0;
char *nicknames[2000];
std::string line;
std::ifstream file("nicknames.txt");
FILE *fileID = fopen("asd.txt", "w");
while (std::getline(file, line))
{
nicknames[nicknameCount++] = line.data();
// (1)
fprintf(fileID, "%i: %s\n", nicknameCount - 1, nicknames[nicknameCount - 1]);
}
int randomNickIndex = rand() % nicknameCount;
// (2)
for (int i = 0; i < nicknameCount; i++)
fprintf(fileID, "%i: %s\n", i, nicknames[i]);
fprintf(fileID, "Result: %s\n", nicknames[randomNickIndex]);
fprintf(fileID, "Result: %i\n", randomNickIndex);
fclose(fileID);
exit(0);
What then I see at point (1) is what I expect; the nicknames. Then later at point (2) every single member of the array is "Pirate Scrub", which is the last element of the nicknames.txt.
I think it must be something obvious, but I just can't figure it out. Any ideas?
line.data() returns a pointer to the sequence of characters. It is always the same pointer. Every time you read a new line, the contents of line are overwritten. To fix this, you will need to copy the contents of line.
Change:
char *nicknames[2000];
to
char nicknames[2000][256];
and
nicknames[nicknameCount++] = line.data();
to
strcpy(nicknames[nicknameCount++], line.data());
However, using a vector to store the lines is probably better, since this is C++
Your nicknames array does not contain copies of the strings, all the nicknames are pointers to the same data owned by line.
Instead of char* nicknames[2000] i would recommend you use
std::vector<std::string> nicknames;
and then inside the loop:
nicknames.push_back(line);
This:
char *nicknames[2000];
is an array of 2000 pointers to char. Nowhere in your code you are actually storing the strings from the file. This
nicknames[nicknameCount++] = line.data();
merely stores pointers to the lines internal buffer in the array. In the next iteration this buffer is overwritten with contents of the next line.
Forget about all the C i/o. Mixing C and C++ is advanced and you don't need it here. If you want to store a dynamically sized array of strings in C++, that is a std::vector<std::string>:
std::vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
Also for writing to the output file you should use an std::ofstream.
I have a text file that contains several lines, each line containing two very large integers.
I need to read the first integer on the line, store each one of its digits in an int array, read the second integer on the line, store each one of its digits in another int array. Then I should perform some operations (adding them, multiplying them etc), then repeat the procedure for the second line in the text file and so on.
I don't know how to read the integers this way. I would be able to read one integer only as an array of digits, but I don't know how to differentiate between the integers separated by space, much less how to tell the compiler when to switch the line.
The reason why I can't read the integers as int variables is, as I said, that they are too large for common numeric operations, so I must do them the same way I would by hand. I've written functions to replicate the process, but they need arrays of digits.
I tried to use fscanf or getline , but anything similar will read both integers on the line in one single array. Also, anything that reads until a space is encountered will read ALL of my numbers, not only the ones on the line I'm at.
The ideal would be two arrays, each containing the digits of one integer, that I keep reinitialising every time I switch the line.
Any suggestions on how to do this (or ideas that follow a different approach to do the same) would be appreciated.
Using boost library (algorithm for string split function, and lexical cast for conversion), you may take a look at this code snippets - (without validation)
typedef std::vector<int> intarray;
intarray da[2];
std::string s;
std::fstream f(filename,std::ios::in);
while(!f.eof() && !f.fail())
{
std::getline(f, s );
std::vector<std::string> v;
boost::algorithm::split(v, s, boost::algorithm::is_any_of(" "));
for(int j = 0; j<1; ++j)
{
std::string fs = v.at(j);
for(int i = 0; i<fs.size(); ++i)
{
try
{
int d = boost::lexical_cast<int>(fs.at(i));
da[j].push_back(d);
}
catch(bad_lexical_cast& e)
{
std::cout << "caught exception.\n";
break;
}
}
}
}
I want to read in lines from a text file into a 2-d char array but without the newline character.
Example of .txt:
TCAGC
GTAGA
AGCAG
ATGTC
ATGCA
ACAGA
CTCGA
GCGAC
CGAGC
GCTAG
...
So far, I have:
ifstream infile;
infile.open("../barcode information.txt");
string samp;
getline(infile,samp,',');
BARCLGTH = samp.length();
NUMSUBJ=1;
while(!infile.eof())
{
getline(infile,samp,',');
NUMSUBJ++;
}
infile.close(); //I read the file the first time to determine how many sequences
//there are in total and the length of each sequence to determine
//the dimensions of my array. Not sure if there is a better way?
ifstream file2;
file2.open("../barcode information.txt");
char store[NUMSUBJ][BARCLGTH+1];
for(int i=0;i<NUMSUBJ;i++)
{
for(int j=0;j<BARCLGTH+1;j++)
{
store[i][j] = file2.get();
}
}
However, I do not know how to ignore the newline character. I want the array to be indexed so that I can access a sequence with the first index and then a specific char within that sequence with the second index; i.e. store[0][0] would give me 'T', but I do not want store[0][5] to give me '\n'.
Also, as an aside, store[0][6], which I think should be out of bounds since BARCLGTH is 5, returns 'G',store[0][7] returns 'T',store[0][8] returns 'A', etc. These are the chars from the next line. Alternatively, store[1][0],store[1][1], and store[1][2] also return the same values. Why does the first set return values, shouldn't they be out of bounds?
As you're coding in C++, you could do like this instead:
std::vector<std::string> barcodes;
std::ifstream infile("../barcode information.txt");
std::string line;
while (std::getline(infile, line))
barcodes.push_back(line);
infile.close();
After this the vector barcodes contains all the contents from the file. No need for arrays, and no need to count the number of lines.
And as both vectors and strings can be indexed like arrays, you can use syntax such as barcodes[2][0] to get the first character of the third entry.
I've been scratching my head and putting this homework off for a couple days but now that I hunker down to try and do it I'm coming up empty. There's 4 things I need to do.
1) Read a binary file and place that data into arrays
2) Sort the list according to the test scores from lowest to highest
3) Average the scores and output it
4) Create a new binary file with the sorted data
This is what the binary data file looks unsorted
A. Smith 89
T. Phillip 95
S. Long 76
I can probably sort since I think I know how to use parallel arrays and index sorting to figure it out, but the reading of the binary file and placing that data into an array is confusing as hell to me as my book doesn't really explain very well.
So far this is my preliminary code which doesn't really do much:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;
int get_int(int default_value);
int average(int x, int y, int z);
int main()
{
char filename[MAX_PATH + 1];
int n = 0;
char name[3];
int grade[3];
int recsize = sizeof(name) + sizeof(int);
cout << "Enter directory and file name of the binary file you want to open: ";
cin.getline(filename, MAX_PATH);
// Open file for binary write.
fstream fbin(filename, ios::binary | ios::in);
if (!fbin) {
cout << "Could not open " << filename << endl;
system("PAUSE");
return -1;
}
}
Sorry for such a novice question.
edit: Sorry what the data file stated earlier is what it SHOULD look like, the binary file is a .dat that has this in it when opened with notepad:
A.Smith ÌÌÌÌÌÌÌÌÌÌÌY T. Phillip ÌÌÌÌÌÌÌÌ_ S. Long ip ÌÌÌÌÌÌÌÌL J. White p ÌÌÌÌÌÌÌÌd
Reading a file in c++ is simple:
create a stream from file [so that to read from the stream] (you have filestream[input/output], stringstream ... )
ifstream fin; //creates a fileinput stream
fin.open(fname.c_str(),ifstream::binary); // this opens the file in binary mod
void readFile(string fname)
{
ifstream fin;
fin.open(fname.c_str()); //opens that file;
if(!fin)
cout<<"err";
string line;
while(getline(fin,line)) //gets a line from stream and put it in line (string)
{
cout<<line<<endl;
//reading every line
//process for you need.
...
}
fin.close();
}
as you specify, the file is simply a text file, so you can process each line and do whatever you want.
Reading from a binary file may seem confusing, but it is really relatively simple. You have declared your fstream using your file name and set it to binary, which leaves little to do.
Create a pointer to a character array (typically called a buffer, since this data is typically extracted from this array after for other purposes). The size of the array is determined by the length of the file, which you can get by using:
fbin.seekg(0, fbin.end); //Tells fbin to seek to 0 entries from the end of the stream
int binaryLength = fbin.tellg(); //The position of the stream (i.e. its length) is stored in binaryLength
fbin.seekg(0, fbin.beg); //Returns fbin to the beginning of the stream
Then this is used to create a simple character array pointer:
char* buffer = new char[binaryLength];
The data is then read into the buffer:
fbin.read(buffer, binaryLength);
All the binary data that was in the file is now in the buffer. This data can be accessed very simply as in a normal array, and can be used for whatever you please.
The data you have, however, does not at all seem binary. It looks more like a regular text file. Perhaps, unless explicitly stated, you ought to consider a different method for reading your data.
You know, with that low range of sorting index you can avoid actual sorting (with comparing indices and moving data forth and back). All you have to do is to allocate a vector of vector of strings, resize it to 101. Then traverse the data, storing each: "A. Smith" in 89-th element; "T. Phillip" in 95-th; "S. Long" in 76-th and so on.
Then by iterating the vector elements from begin() to end() you would have all the data already sorted.
It's almost linear complexity (almost, because allocation/resizing of subvectors and strings can be costly) easy and transparent.
I have a data file which contains data in row/colum form. I would like a way to read this data in to a 2D array in C or C++ (whichever is easier) but I don't know how many rows or columns the file might have before I start reading it in.
At the top of the file is a commented line giving a series of numbers relating to what each column holds. Each row is holding the data for each number at a point in time, so an example data file (a small one - the ones i'm using are much bigger!) could be like:
# 1 4 6 28
21.2 492.1 58201.5 586.2
182.4 1284.2 12059. 28195.2
.....
I am currently using Python to read in the data using numpy.loadtxt which conveniently splits the data in row/column form whatever the data array size, but this is getting quite slow. I want to be able to do this reliably in C or C++.
I can see some options:
Add a header tag with the dimensions from my extraction program
# 1 4 6 28
# xdim, ydim
21.2 492.1 58201.5 586.2
182.4 1284.2 12059. 28195.2
.....
but this requires rewriting my extraction programs and programs which use the extracted data, which is quite intensive.
Store the data in a database file eg. MySQL, SQLite etc. Then the data could be extracted on demand. This might be a requirement further along in the development process so it might be good to look into anyway.
Use Python to read in the data and wrap C code for the analysis. This might be easiest in the short run.
Use wc on linux to find the number of lines and number of words in the header to find the dimensions.
echo $((`cat FILE | wc -l` - 1)) # get number of rows (-1 for header line)
echo $((`cat FILE | head -n 1 | wc -w` - 1)) # get number of columns (-1 for '#' character)
Use C/C++ code
This question is mostly related to point 5 - if there is an easy and reliable way to do this in C/C++. Otherwise any other suggestions would be welcome
Thanks
Create table as vector of vectors:
std::vector<std::vector<double> > table;
Inside infinite (while(true)) loop:
Read line:
std::string line;
std::getline(ifs, line);
If something went wrong (probably EOF), exit the loop:
if(!ifs)
break;
Skip that line if it's a comment:
if(line[0] == '#')
continue;
Read row contents into vector:
std::vector<double> row;
std::copy(std::istream_iterator<double>(ifs),
std::istream_iterator<double>(),
std::back_inserter(row));
Add row to table;
table.push_back(row);
At the time you're out of the loop, "table" contains the data:
table.size() is the number of rows
table[i] is row i
table[i].size() is the number of cols. in row i
table[i][j] is the element at the j-th col. of row i
How about:
Load the file.
Count the number of rows and columns.
Close the file.
Allocate the memory needed.
Load the file again.
Fill the array with data.
Every .obj (3D model file) loader I've seen uses this method. :)
Figured out a way to do this. Thanks go mostly to Manuel as it was the most informative answer.
std::vector< std::vector<double> > readIn2dData(const char* filename)
{
/* Function takes a char* filename argument and returns a
* 2d dynamic array containing the data
*/
std::vector< std::vector<double> > table;
std::fstream ifs;
/* open file */
ifs.open(filename);
while (true)
{
std::string line;
double buf;
getline(ifs, line);
std::stringstream ss(line, std::ios_base::out|std::ios_base::in|std::ios_base::binary);
if (!ifs)
// mainly catch EOF
break;
if (line[0] == '#' || line.empty())
// catch empty lines or comment lines
continue;
std::vector<double> row;
while (ss >> buf)
row.push_back(buf);
table.push_back(row);
}
ifs.close();
return table;
}
Basically create a vector of vectors. The only difficulty was splitting by whitespace which is taken care of with the stringstream object. This may not be the most effective way of doing it but it certainly works in the short term!
Also I'm looking for a replacement for the deprecated atof function, but nevermind. Just needs some memory leak checking (it shouldn't have any since most of the objects are std objects) and I'm done.
Thanks for all your help
Do you need a square or a ragged matrix? If the latter, create a structure like this:
std:vector < std::vector <double> > data;
Now read each line at a time into a:
vector <double> d;
and add the vector to the ragged matrix:
data.push_back( d );
All data structures involved are dynamic, and will grow as required.
I've seen your answer, and while it's not bad, I don't think it's ideal either. At least as I understand your original question, the first comment basically specifies how many columns you'll have in each of the remaining rows. e.g. the one you've given ("1 4 6 28") contains four numbers, which can be interpreted as saying each succeeding line will contain 4 numbers.
Assuming that's correct, I'd use that data to optimize reading the data. In particular, after that, (again, as I understand it) the file just contains row after row of numbers. That being the case, I'd put all the numbers together into a single vector, and use the number of columns from the header to index into the rest:
class matrix {
std::vector<double> data;
int columns;
public:
// a matrix is 2D, with fixed number of columns, and arbitrary number of rows.
matrix(int cols) : columns(cols) {}
// just read raw data from stream into vector:
std::istream &read(std::istream &stream) {
std::copy(std::istream_iterator<double>(stream),
std::istream_iterator<double>(),
std::back_inserter(data));
return stream;
}
// Do 2D addressing by converting rows/columns to a linear address
// If you want to check subscripts, use vector.at(x) instead of vector[x].
double operator()(size_t row, size_t col) {
return data[row*columns+col];
}
};
This is all pretty straightfoward -- the matrix knows how many columns it has, so you can do x,y indexing into the matrix, even though it stores all its data in a single vector. Reading the data from the stream just means copying that data from the stream into the vector. To deal with the header, and simplify creating a matrix from the data in a stream, we can use a simple function like this:
matrix read_data(std::string name) {
// read one line from the stream.
std::ifstream in(name.c_str());
std::string line;
std::getline(in, line);
// break that up into space-separated groups:
std::istringstream temp(line);
std::vector<std::string> counter;
std::copy(std::istream_iterator<std::string>(temp),
std::istream_iterator<std::string>(),
std::back_inserter(counter));
// the number of columns is the number of groups, -1 for the leading '#'.
matrix m(counter.size()-1);
// Read the remaining data into the matrix.
m.read(in);
return m;
}
As it's written right now, this depends on your compiler implementing the "Named Return Value Optimization" (NRVO). Without that, the compiler will copy the entire matrix (probably a couple of times) when it's returned from the function. With the optimization, the compiler pre-allocates space for a matrix, and has read_data() generate the matrix in place.