I have read columns from a .txt file (the file has at the beginning the number of columns (nCol)) and put the values into an array (float values[nCol][nLin]).
Now, I want to copy the values (ex.: values[0][nLin], values[1][nLin]...) into different float arrays depending on the number of columns.
How can I crate float arrays for each column if the number of columns my change depending on the file I am reading?
//------ Declares Array for values ------//
const int nCol = countCols;
float values[nCol][nLin];
// Fill Array with '-1'
for(int c=0; c<nCol; c++){
for(int l=0; l<nLin; l++) {
values[c][l] = -1;
}
}
//------ Skips the reading of line of values file ------//
getline(inFile, dummyLine);
// 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;
}
}
const int nValues = countLines;
float Col1[nValues]=-1,
Col2[nValues]=-1,
Col3[nValues]=-1,
Col4[nValues]=-1,
Col5[nValues]=-1;
//------ Put values in specific Arrays ------//
for(int v=0; v<nValues; v++) {
Col1[v] = values[0][v];
Col2[v] = values[1][v];
Col3[v] = values[2][v];
Col4[v] = values[3][v];
Col5[v] = values[4][v];
}
cout << endl;
I want that float Col1[] to be from 1 to nCol, the last one to be float ColnCol[]
The best way IMO would be to use std::vector< std::vector<float> >
You do not need to make different 1D columns as you can manipulate this vector of vector as you want.
Instead you should use std::vector. It is a better choice for dynamic size allocation of a data type.
Related
I am relatively new to programming and am trying to read an array of ints into a 2-D dynamic array. I'm relatively sure this is just a syntax issue.
The array is dynamic and therefore is of type int**. To try to populate the array, I've used a nested for loop to populate each element of the array with the next term from the ifstream. Input is assumed to be all ints separated by
whitespace.
//declare dynamic 2-D array
int** myArray = new int*[numRows]
for (int i = 0; i < numCols; i++)
{
myArray[i] = new int[numCols];
}
//populate array from ifstream
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < numCols; j++)
{
inFile >> myArray[i][j];
}
}
I expected to be able to store the ints from the ifstream (all between 0-100) directly into the array, but I seem to be storing addresses instead (very
large negative ints). What am I doing wrong?
Fixing the typo and a missing semicolon should fix it
// declare dynamic 2-D array
int** myArray = new int*[numRows]
// ^
// ;
for (int i = 0; i < numCols; i++) {
// ^^^^^^^
// numRows
myArray[i] = new int[numCols];
}
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);
So I have looked through some online questions to figure out how to setup and fill a dynamic multidimensional array and I thought I had it down but for some reason my function will not access the anything past the first(0) column. For my test I put in a 2X2 array:
2 2 (part of another function that gives the size of the matrix)
1 2
3 4
When I debug it I only get
1 random# from initializing the array
3 random# from initializing the array
I'm not sure what I am doing wrong with this piece of code, I am also new to C++.
double* matrix_read(const int m, const int n)
{
double **mat = new double*[m];
for (int j = 0; j < m; ++j) {
mat[j] = new double[n];
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
cin >> mat[i][j];
}
}
double debug = mat[2][2];
return *mat;
}
Inside the main function this is what I send to the function.
int x, y, m, n;
cin >> x;
cin >> y;
double *mat_a = matrix_read(x, y);
cin >> m; //2nd matrix read in
cin >> n;
double *mat_b = matrix_read(m, n);
Your matrix is represented as an array of pointers, each pointer in the array points, in turn, to an array of doubles. Each of these arrays are contiguous in memory, but not among themselves. This means that, mat[0][0] is right before mat[0][1] in memory. But mat[1][0] may be in a completely different location.
By returning only the first line of your matrix, *mat (the same as mat[0]), you will lose information. All you have access to is the first line.
You should return the whole matrix.
double** matrix_read(...) {
...
return mat;
}
(Edit: Besides, someone will have to delete the matrix later.. and they have to delete several arrays, ugh. You should make a structure wrapper for matrices, or use a single array, or use a vector of vectors)
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.
I want to read a raw file, which has 3 interleaving and has a size of about(3.5MB) large into a three dimensional array.. the code that I am using to read the file is:
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
for(int j=0; j<968; j++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
The thing is this array is not what i expect it to be.. I need the 1278 to be the width of the image.. the 968 to be the height and 3 bytes are the RGB values.. how should i write the code to read from the file such that the array gets populated correctly.. Thanks.
First, image files are usually stored, in order of smallest jump to largest, color values, column, row order. You are not reading them in that order.
ifile.open(argv[2], ios::in|ios::binary);
for(int j=0; j<968; j++){
for(int i=0; i<1278; i++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
That is how the loop should be arranged, though you may want to rename your variables to keep things straight:
ifile.open(argv[2], ios::in|ios::binary);
for(int row=0; row<968; row++){
for(int col=0; col<1278; col++){
for(int color=0; color<3; color++){
Imagedata1[col][row][color]=ifile.get();
}
}
}
Secondly, the way you allocate your array is really broken and inefficient. Here is how it should work:
#include <iostream>
#include <fstream>
class ColorValue {
public:
ColorValue(unsigned char r, unsigned char g, unsigned char b)
: r_(r), g_(g), b_(b) {}
ColorValue() : r_(0), g_(0), b_(0) {}
unsigned char getR() const { return r_; }
unsigned char getG() const { return g_; }
unsigned char getB() const { return b_; }
private:
unsigned char r_, g_, b_;
};
void readrows(const char *fname, ColorValue imagedata[][1278])
{
::std::ifstream ifile;
ifile.open(fname, ::std::ios::in|::std::ios::binary);
for (int row = 0; row < 968; ++row) {
for (int col = 0; col < 1278; ++col) {
char r, g, b;
ifile.get(r);
ifile.get(g);
ifile.get(b);
imagedata[row][col] = ColorValue(r, g, b);
}
}
}
int main(int argc, const char *argv[])
{
ColorValue (*imagedata)[1278] = new ColorValue[968][1278];
readrows(argv[1], imagedata);
delete[] imagedata;
}
Using a class for ColorValue keeps you from having magic indexes everywhere in your code for the 'r', 'g', and 'b' components. And allocating the array in this way keeps all the memory used for the image contiguous and removes several levels of unnecessary indirection. These both have the property of making your program much more cache friendly.
I also found a nice article that's a really comprehensive treatment of multi-dimensional arrays in C++.
C arrays don't work like that.
Let's say you wanted a 2D 1024*768 pixel buffer, with 4 bytes per pixel. You'd do something like this:
unsigned int pixbuf[1024*768];
for (int irow=0; irow < 1024; irow++)
for (int icol=0; icol < 768; icol++)
pixbuf[(irow*1024)+icol] = icolor;
Here is a good link that explains further:
http://c-faq.com/~scs/cclass/int/sx9.html
'Hope that helps!
As long as you always access your data through the three-dimensional array it does not matter how the structure of the array is laid down in memory. In your example you define the first index (i) as the column index, the (j) index as the row index and the (k) index as the pixel component index.
I suspect your image file has the data organized in the standard way, which is an array of rows, where each row is an array of pixels, where each pixel is an array of color components. If that is the case, then you can modify your code to work with that structure:
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
for(int j=0; j<968; j++){
for(int k=0; k<3; k++){
Imagedata1[j][i][k]=ifile.get();
}
}
}
Note that I just swapped the i and j indexes in the body of the innermost for loop, the rest of the code is identical to yours.
If you also need to access the image data as a planar buffer, then you should reorganize your arrays so that the data in memory mimics the layout from the file. For this you want the first dimension to be the rows, then columns, then color components. That would end up like this:
unsigned char Imagedata1[968][1278][3];
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<968; i++){
for(int j=0; j<1278; j++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
Update: after a quick discussion in the comments, it seems you do want to read this in a more efficient way. If you want to load this image on the stack (probably not a good idea) you would declare your image buffer as:
unsigned char Imagedata1[968][1278][3];
I would instead put it on the heap, like this:
unsigned char* Imagedata1 = new unsigned char[968*1278*3];
Then you can read the data from the file with:
if (fread(Imagedata1, 1278*3, 968, fd) != 968) {
// handle error here
}
Note that the numbers that you put as count and size in the fread call are not that important, as long as those two numbers multiplied are equal to width*height*components.
If you then need to access this image as a 3-dimensional array, I recommend that you create an auxiliary function, something like this:
unsigned char* getPixel(int col, int row)
{
return Imagedata1 + row * 1278 * 3 + col * 3;
}
The return value of this function can be used as a one dimensional array of three elements, the red, green and blue of the pixel.
As a final suggestion, I recommend that you wrap your image in a class, and add member variables that define the width and height (and maybe the number of color planes as well). You do not want to hardcode the 1278s and the 968s all over the place in your code!
I hope this helps.