using function to read a matrix in file .txt - c++

Im trying to read a .txt file with the values of a matrix [n]x[m] by using a function and then call it in my main but I am having some problems... Here is the read function:
bool read_file(int row, int column, char *file_name, float **elems)
{
int i, j;
FILE *pfile;
fopen_s(&pfile, file_name, "r");
if (pfile == NULL) {
return false;
}
fscanf_s(pfile, "%d", &row);
fscanf_s(pfile, "%d", &column);
//printf_s("%d %d\n", row,column);
for (i = 0; i < row; i++)
{
for (j = 0; j < column; j++) {
fscanf_s(pfile, "%f", &elems[i][j]);
//printf("%f\n", elems[i][j]);
}
}return true;
}
My program asks me to do product between two matrices and i have to do it by 2 types of input, keybord or file. I used in my main if-else to choose between the 2 inputs. When it does keybord input, everything goes right (dinamic alocation is working as well as the product of matrices). I then call the function like this in the main:
int main(){
int i, j, row1, column1, row2, column2;
char* file_name1 = { "C:\\Users\\Lc\\Documents\\Matrix1.txt" };
char* file_name2 = { "C:\\Users\\Lc\\Documents\\Matrix2.txt" };
if (...) {
...
/* Input by keybord. */
...
}
else if(...){ /*Input by file*/
read_file(row1, column1, file_name1, matrix1);
read_file(row2, column2, file_name2, matrix2);
...
}
...
And then it says matrix1 and matrix2 are undefined... I understand why they are undefined but my problem is that i dont know how to define them like i did with the keybord input

float **elems is a pointer to an array of pointers to arrays of floats. You can create such a thing by calling malloc() in a loop.
Note the way it's used in your code:
fscanf_s(pfile, "%f", &elems[i][j]);
So elems[0..N] are meant to point to the rows. First, allocate the outer array:
float** elems = malloc(row * sizeof(float*));
assert(elems);
That's one float* for each row. Then, allocate each row:
for (i = 0; i < row; i++)
{
elems[i] = malloc(column * sizeof(float));
assert(elems[i]);
}
Now elems points to an array of float* initialized with each element pointing to an array of float (which numbers are uninitialized).

Related

How to create a dynamic array using new C++?

I'm trying to initialize an array of integers dynamically, since the size of the array changes based on input.
The program is as follows:
int main()
{
int* list = createList("dis.bin");
for (int i = 0; i < sizeof(list) / sizeof(int); i++)
{
printf("%d\n", list[i]);
}
}
With createList() function as written:
int* createList(const char* file_name)
{
int counter = 1;
int* inst{};
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst = new int[counter];
inst[i] = x;
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, inst[i], ToBinary(inst[i], 0));
counter += 1;
x = 0;
}
return inst;
}
createList reads from a .bin file (basically containing an array of bytes) and inserts each pair of 4 bytes to an item in the array inst. I do this by allocating a new amount of space for the array based on the counter variable. (So whatever value counter is becomes the size of the array with inst = new int[counter]) Then I set the contents of the array at the given index i equal to x (the pair of bytes read) I would assume it is working correctly in createList at least, because of the printf statement which is printing each element in inst[].
However, when I call createList("dis.bin") in main and assign it to the variable int* list, I try to iterate through each value. But this just prints out one uninitialized value (-842150451, if you're curious). So I'm not sure what I'm doing wrong here?
I should mention that I am NOT using vectors or really any std container. I am just working with arrays. I also am using printf for specific reasons.
This question is tagged as C++, but OP is showing C code and says they need it in C, so I will show this in C... but the pre-req is that it uses new and not malloc
int* createList(const char* file_name, int& count)
{
// initialize count, so that way if we return early, we don't have invalid information
count = 0;
// open the file ad "READ" and "BINARY"
FILE* myFile = fopen(file_name, "rb");
if (!myFile)
{
printf("\nFile not opened\n");
return 0;
}
// calculate how many 4-byte integers exist in the file using
// the file length
fseek(myFile, 0, SEEK_END);
count = ftell(myFile) / sizeof(int);
rewind(myFile);
// allocate the memory
int* returnData = new int[count];
// read in 4-byte chunks to our array until it can't read anymore
int i = 0;
while (fread(&returnData[i++], sizeof(int), 1, myFile) == 1);
// close the file
fclose(myFile);
// return our newly allocated data
return returnData;
}
int main()
{
int count;
int* myInts = createList("c:\\users\\andy\\desktop\\dis.bin", count);
for (int i = 0; i < count; ++i) {
printf("%d\n", myInts[i]);
}
// don't forget to delete your data. (another reason a vector would be better suited... no one remembers to delete :)
delete myInts;
}
Two things here:
The usage of new was misinterpreted by me. For whatever reason, I thought that each time I allocated new memory for inst that it would just be appending new memory to the already allocated memory, but this is obviously not the case. If I wanted to simulate this, I would have to copy the contents of the array after each iteration and add that to the newly allocated memory. To solve this, I waited to allocate memory for inst until after the file iteration was complete.
As Andy pointed out, sizeof(list) / sizeof(int) would not give me the number of elements in list, since it is a pointer. To get around this, I created a new parameter int &read for the createList() function in order to pass the number of items created.
With these points, the new function looks like this and works as intended:
int* createList(const char* file_name, int &read)
{
int counter = 1;
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, x, ToBinary(x, 0));
counter += 1;
}
int* inst = new int[counter];
read = counter;
rewind(myFile); // rewind to beginning of file
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst[i] = x;
x = 0;
}
return inst;
}
With main changed a bit as well:
int main()
{
int read;
int* list = createList("dis.bin", read);
for (int i = 0; i < read; i++)
{
printf("%d\n", list[i]);
}
}
As for the comments about the invalidity of !(feof(myFile)), although helpful, this was not a part of my question and thus not of my concern. But I will source the solution to that for the sake of spreading important information: Why is "while ( !feof(file) )" always wrong?

Populating an array from a .txt file

I'm trying to populate an array from a .txt that I am reading. I am using this code that I am using as a function to read the file:
double* read_text(const char *fileName, int sizeR, int sizeC)
{
double* data = new double[sizeR*sizeC];
int i = 0;
ifstream myfile(fileName);
if (myfile.is_open())
{
while (myfile.good())
{
if (i > sizeR*sizeC - 1) break;
myfile >> *(data + i);
//cout << *(data + i) << ' '; // Displays converted data.
i++;
}
myfile.close();
}
else cout << "Unable to open file";
//cout << i;
return data;
}
Now when I read the file I am trying to take the elements from the 1D data array and store them into a 2D array.
I've tried to create an array in a public class, however I have no idea on how to move the data that I am reading to a 2D array.
I know it's not very clear but basically I'm doing the nearest neighbour search algorithm to compare 2 images. I have taken one image and converted it into the values using this bit of code above. However now I am trying to store the data that I am reading into a 2D public array?
Here is a more compact version of reading in a 2D matrix:
int quantity = sizeR * sizeC;
double * matrix = new double [quantity];
double value = 0.0;
double * p_cell = matrix;
//...
while ((myfile >> value) && (quantity > 0))
{
*p_cell++ = value;
--quantity;
}
In the above code snippet, a pointer is used to point to the next slot or cell of the matrix (2D array). The pointer is incremented after each read.
The quantity is decremented as a safety check to prevent buffer overrun.
Assuming every double returned represents a pixel. You can define a function that retrieves pixels like so:
double get_pixel(int x, int y, double* data, int sizeC)
{
return data[x + y*sizeC];
}
Where sizeC is the width of the image (number of columns).
You can then use the function above to fill your 2D array like so:
for(int i = 0; i < sizeC; i++)
for(int j = 0; j < sizeR; j++)
my2Darray[i][j] = get_pixel(i, j, data, sizeC);
But then notice how unnecessary this is. You don't really need a 2D array :) keep it simple and efficient.
The function above could be a part of a struct that represents the Image where you'd have sizeC, sizeR and data defined as members.
struct Image
{
int sizeC;
int sizeR;
double* data;
get_pixel(int x, int y)
{
return data[x + y*sizeC];
}
};
Then to access the image pixels you can simply do:
Image img;
// read image data and stuff
double p = img.get_pixel(4, 2);
You can even make it look prettier by overriding the operator() instead of get_pixel so retrieving the pixel would look something like:
double p = img(4, 2);

cannot use push_back to insert an integer to a 1D/2D vector

I am trying to write a function to extract a slice from a given matrix, where the input is 1D and the slice can be 1D or 2D.
I am trying to use the push_back function for this purpose but for some reasons the push_back does not work.
I receive an error in my line OutPut.push_back(DumyValue);
Can anyone help me why I am receiving this error?
Also, it would be appreciated if you can tell me how to solve this issue.
Also, if the first part becomes clear, can anyone tell me how I should use the push_back for inserting an integer in a specific location so I can use it for extracting a 2D slice?
If you remove the line OutPut.push_back(DumyValue); the code should work.
#include<iostream>
#include<vector>
using namespace std;
int MatrixSlice(vector<vector<int>> Input, int Row1, int Row2, int Col1, int Col2) {
//define the slice size, if it is iD or 2D
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int>> OutPut;
}else{
vector<int> OutPut;
}
int i2;
int j2;
for (int i = Row1; i <= Row2; i++) {
i2=0;
for (int j = Col1; j <= Col2; j++) {
int DumyValue=Input[i][j];
OutPut.push_back(DumyValue);
i2++;
//cout << Input[i][j] << endl;
}
j2++;
}
return 0;
}
int main() {
//Define a matrix for test:
vector<vector<int>> Matrix2(4, vector<int>(5, 1));
int R = 4;
int C = 4;
vector<vector<int>> MatrixInput(R, vector<int>(C, 1));;
for (int i = 0; i < MatrixInput.size(); i++) {
for (int j = 0; j < MatrixInput[0].size(); j++) {
int temp;
temp = i^2+j^2;
MatrixInput[i][j] = temp;
}
}
MatrixSlice(MatrixInput, 0, 3, 1, 1);
printf("\n");
return 0;
}
Matrix slice has a couple problems:
It is impossible define a variable with two possible types and have both active in the same scope.
The return type of int makes little sense. The matrix is sliced up, but then what? It can't be handed back to the caller to do anything with it.
This can be fixed with a union, but yikes! The bookkeeping on that will be a Smurfing nightmare. Don't do it!
The next is to always use a vector of vectors, but I don't like that idea for a couple reasons I'll get into below.
Instead I pitch a simple wrapper object around a single vector. This is done for two reasons:
It preserves the ability to back a 1 dimensional matrix with a 1 dimensional container. If you have many rows of one column, all of the row data remains contiguous and cache friendly.
It tends to be much faster. The data of one vector is contiguous in memory and reaps the rewards of cache friendliness. A vector of vectors is basically a list of pointers to arrays of data, sending the poor CPU on an odyssey of pointer-chasing through memory to find the columns. If the columns are short, this can really, really hurt performance.
Here we go:
template<class TYPE>
class Matrix
{
private:
size_t mNrRows; // note size_t. This is unsigned because there is no reason
// for a matrix with a negative size. size_t is also guaranteed
// to fit anything you can throw at it.
size_t mNrColumns;
std::vector<TYPE> mVec;
public:
// make a default-initialized matrix
Matrix(size_t nrRows, size_t nrColumns) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns)
{
}
// make a def-initialized matrix
Matrix(size_t nrRows, size_t nrColumns, TYPE def) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns,
def)
{
}
// gimme a value and allow it to be changed
TYPE & operator()(size_t row, size_t column)
{
// could check for out of bounds and throw an exception here
return mVec[row * mNrColumns + column];
}
//gimme a value and do not allow it to be changed
TYPE operator()(size_t row, size_t column) const
{
return mVec[row * mNrColumns + column];
}
// gimme the number of rows
size_t getRows() const
{
return mNrRows;
}
// gimmie the number of columns.
size_t getColumns() const
{
return mNrColumns;
}
// printing convenience
friend std::ostream & operator<<(std::ostream & out, const Matrix & mat)
{
int count = 0;
for (TYPE val: mat.mVec)
{
out << val;
if (++count == mat.mNrColumns)
{
out << '\n';
count = 0;
}
else
{
out << ' ';
}
}
return out;
}
};
The vector member handles all of the heavy lifting so the Rule of Zero recommends leaving the copy and move constructors, assignment operators, and destructor up to the compiler.
What does this do to MatrixSlice? Well, first it now received and returns a Matrix instead of vector<vector> and int. The insides use Matrix and the confusion about 1D or 2D is just plain gone, resulting in a simpler function.
Matrix<int> MatrixSlice(const Matrix<int> & Input,
int Row1,
int Row2,
int Col1,
int Col2)
{
Matrix<int> OutPut(Row2-Row1 + 1,
Col2-Col1 + 1); // but what if Row1 > Row2?
int i2;
int j2= 0; // definitely need to initialize this sucker.
for (int i = Row1; i <= Row2; i++) // logical problem here: What if Row2 >= input.getRows()?
{
i2 = 0;
for (int j = Col1; j <= Col2; j++) // similar problem here
{
int DumyValue = Input(i, j);
OutPut(j2, i2) = DumyValue;
i2++;
}
j2++;
}
return OutPut;
}
Not that this completely ignores the very logical option of making slice a Matrix method. While it makes sense, it doesn't need to be a method and the stock recommendation is to prefer a free function. One good improvement is to make the function a template so that it can handle all sorts of Matrix in addition to Matrix<int>.
And finally, what happens to main?
int main()
{
//Define a matrix for test:
Matrix<int> Matrix2(4, 5, 1); // initialize matrix to all 1s
int R = 4;
int C = 4;
Matrix<int> MatrixInput(R, C); // default initialize the matrix
for (int i = 0; i < MatrixInput.getRows(); i++)
{
for (int j = 0; j < MatrixInput.getColumns(); j++)
{
int temp;
temp = i ^ 2 + j ^ 2;
// WARNING: ^ is XOR, not exponent. Maybe OP wants i XOR 2, but not
// likely. But if XOR is the desired operation, there is a lurking
// order of operation bug that needs to be addressed
MatrixInput(i, j) = temp;
}
}
std::cout << MatrixInput << '\n';
std::cout << MatrixSlice(MatrixInput, 0, 3, 1, 1);
return 0;
}
In your code
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int> > OutPut;
// OutPut dies here
}else{
vector<int> OutPut;
// OutPut dies here
}
// here is no OutPut
OutPut lives only to the end of IF statement.
You either use it without the if statement or you add all code that uses it to the if statement.

C++ and Root, passing 2D array to function and use it in TGraph

How can I pass a 2D array into a function and use it like myArray[i][j] but without knowing the size of that array inside that function?
I can know the size inside the main.
I want to use it like this:
TGraph *myGraph = new TGraph(nValues, myArray[0][j], myArray[1][j]);
// I'll not use a loop for j, since TGraph receives all the values in the array,
like "x values" and "y values"
If I do it like this it works, but I would have to pass to the function Col1 and Col2 that are two 1D arrays:
main() {
...
graphWaveTransmittance("a", nValues, Col1, Col2,
" Au ", "Evaporated", "thickness 5nm", kGreen+1);
...
}
void graphWaveTransmittance(char *n, int nValues, float Param1[], float Param2[],
char *title, char *header, char *entry, Color_t color) {
TGraph *myGraph = new TGraph(nValues, Param1, Param2);
...
}
The Array:
float valuesArray[nCol][nValues];
for(int y=0; y<nValues; y++){
for (int i=0; i<nCol; i++) {
valuesArray[i][y] = values[i][y];
}
i=0;
}
Note: I've made it like this because values[ ][ ] is an array with values that are read from a text file. Before read the file I don't know how many lines are going to be necessary. With this second array (valuesArray[ ][ ]) I can make it to have just the size of the number of values that are read.
Firstly, I've put all the values in values[ ][ ] with "-1" and it's size very large. Then I've counted the number of lines and just used that value for valuesArray[ ][ ]. This is the first array with values (the large one):
const int nCol = countCols;
float values[nCol][nLin];
// reads file to end of *file*, not line
while(!inFile.eof()) {
for(int y=0; y<nLin; y++){
for (int i=0; i<nCol; i++) {
inFile >> values[i][y];
}
i=0;
}
}
One other question, I've seen that "while(!inFile.eof())" shouldn't be used. What can I use instead? (I don't know the total number of lines from the .txt file at this point)
Importing values in columns in a .txt, till now I have:
vector<vector<float> > vecValues; // your entire data-set of values
vector<float> line(nCol, -1.0); // create one line of nCol size and fill with -1
bool done = false;
while (!done)
{
for (int i = 0; !done && i < nCol; i++)
{
done = !(inFile2 >> line[i]);
}
vecValues.push_back(line);
}
The problem of this is that the values are like vecValues[value][column number from .txt]
I want to have vecValues[column number from .txt][value].
How can I change it?
I'm reading from the file like this:
main() {
...
vector < vector <float> > vecValues; // 2d array as a vector of vectors
vector <float> rowVector(nCol); // vector to add into 'array' (represents a row)
int row = 0; // Row counter
// Dynamically store data into array
while (!inFile2.eof()) { // ... and while there are no errors,
vecValues.push_back(rowVector); // add a new row,
for (int col=0; col<nCol; col++) {
inFile2 >> vecValues[row][col]; // fill the row with col elements
}
row++; // Keep track of actual row
}
graphWaveTransmittance("a", nValues, vecValues, " Au ",
"Evaporated", "thickness 5nm", kGreen+1);
// nValues is the number of lines of .txt file
...
}
//****** Function *******//
void graphWaveTransmittance(char *n, int nValues,
const vector<vector <float> > & Param, char *title, char *header,
char *entry, Color_t color) {
// like this the graph is not good
TGraph *gr_WTransm = new TGraph(nValues, &Param[0][0], &Param[1][0]);
// or like this
TGraph *gr_WTransm = new TGraph(Param[0].size(), &Param[0][0], &Param[1][0]);
Note: TGraph can accept floats, my previous arrays were floats
Do you know why the graph is not appearing correctly?
Thank you
I ran into a similar problem recently. I ended up using two dimensional vectors, which don't need to know the inner dimension when passed to a function.
Declare vectors like this
vector< vector<int> > vec(xRange, vector<int>(yRange, initialValue));
While replacing xRange with your size in the x dimension, yRange with your size in the y direction, and initialValue with what you want to initialize your 2d vector with.
At this point, you can access or update vector contents using
vec[x][y]
To pass this to a function, use this
void myFunc(std::vector< std::vector<int> >& vec) {
Be sure to
#include <vector>
You can use vectors to sove this problem as Michael Parker already mentioned. To make it work in root with graphs, note that TGraph expects two arrays of double or float as parameters.
Therefore you have to use
std::vector<std::vector<double> >
or
std::vector<std::vector<float> >
in your case.
Then your function looks like:
void drawGraph(const std::vector<std::vector<double> > & data)
{
TGraph* graph = new TGraph(data[0].size(), &data[0][0], &data[1][0]);
//...
}
The &data[0][0] "converts" the vectors to arrays as needed by TGraph.
Concerning your second question, instead of using !inFile.eof(), I typically directly ask whether the reading process was succesful, i.e. in your case:
if(!(inFile >> values[i][y]))
{
//at end of file
}
I prefer to use this in a while loop but thats a matter of taste.
By the way, by using vectors you no longer need to run though the whole file in advance to count the number of lines, just use push_back(...).
If you do not know the number of lines nor the number of columns, you can use getline to read out the file and to determine the number of columns:
std::vector<std::vector<float> > data;
std::string buffer;
getline(infile,buffer)//I do not check that the file has at least one line here
istringstream firstLine(buffer);
float value;
while(firstline >> value)
{
data.push_back(std::vector<float>(1,value));
}
while(getline(infile,buffer))
{
istringstream line(buffer);
float value;
unsigned int counter = 0;
while(line >> value)
{
data[counter].push_back(value));
counter++;
}
}
Note that this requires:
#include<sstream>
and that this assumes that the number of columns does not change over the file size.

Error when library receives the FILE pointer and read the file

The function read a matrix from a file, and print it on the screen. but there is something wrong when library fscanf(fp, "%u", &elem); read file from fp.
It's OK when I change uint8_t elem to uint8_t *elem .
I want to know why! What should pay attention when program transfers a FILE pointer to the library. Thx!
main function:
int main(int argc, char *argv[]){
Matrix8g mat;
FILE *fp;
if((fp = fopen("mat.dat","r")) == NULL){
printf("can't open the file");
}
//matrix with 24 rows and 11 cols
mat.Make_from_file(fp, 24, 11);
//print the matrix
mat.Print();
fclose(fp);
}
Part of library file (Make_from_file):
/* Set the matrix from a file */
int Matrix8g::Make_from_file(FILE *fp, int rows, int cols){
int i, j;
uint8_t elem;
this->rr = rows;
this->cc = cols;
Resize_matrix();
try{
for(i = 0; i < rows; i++){
for(j = 0; j < cols; j++){
fscanf(fp, "%u", &elem);
Set(i, j, elem);
}
}
}catch(...){
NOTE("Error when set the matrix from a file");
return 0;
}
return 1;
}
If you look at this reference c reference
You would see that fscanf needs a reference to the data structure to which the extracted date should be written. fscanf copies from the given file/stream to the given pointer. It has no information about what type the data has. It uses the format string to interpret the byte from the input. Its similar to a type casting. fscanf can't know which type is needed as target structure but a pointer allows a straight copy operation.