Just wonder, for a matrix stored in a file as what it is, i.e. each line in the file being a row of the matrix where elements are separated by space(s), how can I predetermine the size of the matrix, then create an array of the same size and read it into the array in C and C++? If you have some code example, that would be appreciated!
Thanks and regards!
Something like this. You need to include vector, sstream and string.
There is no need to find out the size of the vector in advance.
std::vector<int> readRow(std::string row) {
std::vector<int> retval;
std::istringstream is(row);
int num;
while (is >> num) retval.push_back(num);
return retval;
}
std::vector<std::vector<int> > readVector(std::istream &is) {
std::string line;
std::vector<std::vector<int> > retval;
while (std::getline(is, line))
retval.push_back(readRow(line));
return retval;
}
In C you might use fgets to read one line at a time, and strtok or similar to process the lines and atof or sscanf to read the numbers. The first line can be processed to determine the matrix width and allocate memory, then re-processed to insert the first row. If the height may be different then you would either need to dynamically allocate the memory, or read the whole file counting lines then reprocess it.
Read the first row, count the fields and then use fseek() to go back to the start of the file.
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'm trying to write my own vocabulary with a test for my little brother, but I have a problem when I want to read data from file into two arrays - first with English words, and second with Polish words. File looks alike
black - czarny
red - czerwony etc.
And my function:
void VOC::readout()
{
fstream file;
VOC *arr = new VOC;
string line;
file.open("slowka.txt");
if(file.good())
{
int i=0;
while(!file.eof())
{
getline(file, line);
size_t pos = line.find(" - ");
int position = static_cast<int>(pos);
file>>arr[i].en;
file>>arr[i].pl;
++i;
}
}
}
I thought it could be a good idea to insert a line into first array until the function finds " - ", and after that insert the rest of line into second array, but I have some problems with that. Could someone help me? I know I can solve it by using std::vector but I care to do that by using arrays.
If you insist on using plain arrays, you'll first have to count the number of lines in your file and then allocate enough memory. Arrays -- unlike std::vector objects -- won't grow automatically but have a fixed size.
That being said, note that using !file.eof() is not the best way to read a stream until the end is reached. You can use the simpler
std::string line;
while (std::getline(file, line)) {
// ...
}
idiom instead, which also takes care of error conditions. See this question (and corresponding answers) for more information on that.
I have set of zeroes and ones as my input like below, I need to do some pairwise Boolean operation (and, or, Xor, not) between them (consider each line as).
111100000000
101100000010
111011100000
111100000001
001100010001
The code for reading and storing each line is:
int lineCounter = 0;
while (std::getline(infile, line))
{
myinput[lineCounter] = bitset<LEN> (std::string(line));
lineCounter++;
}
Right now I am using array of bitset to store each line bitset<LEN> myinput[NUMBER]; that LEN is size of each line and NUMBER is number of lines in my input file. But the problem is I don't want to specify LEN and NUMBER during compile time since I have to work with different input. having said that I want user give the LEN and NUMBER as an input argument when running the program. Since I can not do dynamic allocation for bitset I want to use vector but don't know how should I use it to fulfill my job!
can you please tell how can read and store my input and do pairwise boolean operation with help of vector or anything else that can handle dynamic allocation.
You can read the input like this:
vector< vector<bool> > set;
int lineCounter = 0;
while (std::getline(infile, line))
{
string input = string(line)
vector<bool> line;
while(input.size!=0){
if(input.front()=='0'{
line.pushBack(false);
}
else{
line.pushBack(true);
}
input.erase(0,1);
}
set.pushback(line);
lineCounter++;
}
As far as pairwise boolean operations, iterating over the two vectors and performing the appropriate bitwise opperation should suffice.
I am trying to load data from a text file that looks like this:
161,77,88,255
0,44,33,11,111
etc. I have functions to manipulate it, and am ensured that the array is the correct size (which may still vary). Below is my attempt at implementation:
bool loadData(int **imgPix, string fileName) {
ifstream inputFile;
inputFile.open(fileName.c_str());
string tempLineRow; //The resulting line from the text file
string tempElementColumn; //The individual integer element
int numberOfCols = 0;
int numberOfRows = 0;
if (!inputFile.is_open()) {
return false;
}
imgPix = new int* [numberOfRows];
while (getline(inputFile, tempLineRow, '\n')) {
stringstream ss;
ss << tempLineRow; //Stringstream version of the line
while (getline(ss, tempElementColumn, ',' )) {
stringstream ss2;
ss2 << tempElementColumn;
ss2 >> numberOfCols;
//Prob? (**imgPix) = *(*(imgPix + numberOfRows) + numberOfCols);
numberOfCols++;
}
numberOfRows++;
}
inputFile.close();
return true;
}
I've marked the line with the double pointer assignment with a comment, because I believe it be the source of my error, although there could be others. I'm not sure how to use the while loop structure I've implemented to iteratively update the 2D array.
Can anyone offer any assistance? Would be greatly appreciated!
imgPix = new int* [numberOfRows]
Here numberOfRows = 0, so you don't allocate enough memory. You need to know dimensions of the array before you allocate the memory.
And then you should also allocate a memory for each row in the array:
imgPix[currentRow] = new int [TotalCols];
For a 2-dimensional rectangular array, it would be more efficient to create 1-dimensional array of TotalRows*TotalCols elements, and then access it using formula A(row, col) = A[row*TotalCols + col].
Your code has several issues, mostly I guess because you did not fully understand how built-in arrays work in C++. The main issue here is that those cannot easily grow dynamically, there is no "resize" operation for those arrays (but you will need one here). So I suggest kindly that you try to rewrite your code using std::vector<int> and std::vector< std::vector<int> >, make sure you use of .resize when you store a new row or column and come back and ask again when you run into problems with this new implementation.
Previous answers are valid, but if contiguous memory is not a requirement, std::deques may be a better choice in this case compared to std::vectors to avoid lots of memory reallocations.
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.