I have a CSV file from which I want the values to be stored into a three dimensional array Cl[x][y][z] in C++.
The current file following format of a 2D array.
29 26 20 18
29 25 23 21
31 28 25 23
33 30 28 25
This 2D array has to be duplicated multiple times in the third dimension to yield a 3D array which I will be using further along in the code.
Currently I have trouble reading the values from the csv file and converting them to 3D array in C++.
This is the current code that I have:
unsigned short int widthX = wX;
unsigned short int widthY = wY;
unsigned short int widthZ = wZ;
unsigned short int x, y, z;
float clvDefault = 0.0;
float *** Cl = new float**[widthZ];
for (i=0; i<widthZ; i++)
{
Cl[i] = new float*[widthY];
for (j=0; j<widthY; j++)
{
Cl[i][j] = new float[widthX];
}
}
std::ifstream clvIn;
std::string clvFileName = "File_read.csv";
clvIn.open(clvFileName.c_str());
if(clvIn.fail())
{
// something bad happened when opening the file
}
std::string filejunk;
char delim;
std::getline(clvIn, filejunk);
int clvX, clvY, clvZ;
float clvValue;
for (z = 0; z < widthZ; z++)
{
for (y = 0; y < widthY; y++)
{
for (x = 0; x < widthX; x++)
{
Cl[z][y][x] = clvDefault;
}
}
}
while(clvIn >> clvY >> delim >> clvX >> delim >> clvValue)
{
Cl[0][clvY][clvX] = clvValue;
}
for(y = 0; y < widthY; y++)
{
for(x = 0; x < widthX; x++)
{
clvIn >> Cl[0][y][x] >> delim;
}
for (z = 1; z < widthZ; z++)
{
for (y = 0; y < widthY; y++)
{
for (x = 0; x < widthX; x++)
{
Cl[z][y][x] = Cl[0][y][x];
}
}
}
When I run the code, each element of array has the clvDefault value which I assigned and the values from the csv file are not read.
It looks like while loop is skipped during the run. Any suggestions on how to fix this issue is appreciated.
There are many, many errors in your program. Let me list up the most important:
Usage of raw pointers for owned memory. Never do this in C++ (if at all, use std::unique_ptr instead)
Do not use new in C++ to allocate memory (use std::make_unique)
If you allocate memory with new, then you must delete it afterwards
Best: Do use container from the standard library, in this case std::vector
Always initialize all variables
Always check the result of file operations like open or >>
Handle errors
Use ++v instead of v++
Define variables, when you need them. Keep them scoped. Prevent Namespace pollution
If you want to write C++ code, then use C++ language elements and not C
Try to design your code with modern C++ language elements
So. I fixed your code, so that it runs, reads your example file and displays the result. I removed the major bugs. Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
float*** get3dArry(unsigned short widthX, unsigned short widthY, unsigned short widthZ) {
unsigned short int i, j, x, y, z;
float clvDefault = 0.0;
float*** Cl = new float** [widthZ];
for (i = 0; i < widthZ; i++)
{
Cl[i] = new float* [widthY];
for (j = 0; j < widthY; j++)
{
Cl[i][j] = new float[widthX];
}
}
std::ifstream clvIn;
std::string clvFileName = "r:\\File_read.csv";
clvIn.open(clvFileName.c_str());
if (clvIn.fail())
{
std::cerr << "\n*** Error: Could not open input file\n";
}
else {
std::string filejunk, line;
char delim;
//std::getline(clvIn, filejunk);
int clvX, clvY, clvZ;
float clvValue;
for (z = 0; z < widthZ; z++)
{
for (y = 0; y < widthY; y++)
{
for (x = 0; x < widthX; x++)
{
Cl[z][y][x] = clvDefault;
}
}
}
for (y = 0; (y < widthY) && std::getline(clvIn, line); ++y) {
std::istringstream iss{ line };
for (x = 0; (x < widthY) && (iss >> Cl[0][y][x]); ++x)
;
}
for (z = 0; z < widthZ; z++)
{
for (y = 0; y < widthY; y++)
{
for (x = 0; x < widthX; x++)
{
Cl[z][y][x] = Cl[0][y][x];
}
}
}
}
return Cl;
}
int main() {
float*** a3d = get3dArry(4, 4, 3);
for (int z = 0; z < 3; ++z) {
std::cout << "\n";
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
std::cout << a3d[z][y][x] << "\t";
}
std::cout << "\n";
delete[] a3d[z][y];
}
delete[] a3d[z];
}
delete[] a3d;
return 0;
}
However. I would not recommend to use that. The quality is too bad. It is error prone and somehow still complete a C-Program.
Please see the part, where I read the CSV file. Of course, there is no external library necessary. I hear often such nonesense recomendations for ultra simple CSV files. So, no library. Example from above code:
for (y = 0; (y < widthY) && std::getline(clvIn, line); ++y) {
std::istringstream iss{ line };
for (x = 0; (x < widthY) && (iss >> Cl[0][y][x]); ++x)
;
}
Nobody can persuade me, that I need a library, for what I can do with 3 simple lines of code.
If you are interested to learn, then I show you also a "more-modern" C++ solution:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
// Make reading datatypes easier
using DataType = float;
using Matrix1dX = std::vector<DataType>;
using Matrix2dYX = std::vector<Matrix1dX>;
using Matrix3dZYX = std::vector<Matrix2dYX>;
// This is the number of z values for the 3rd dimension. Whatever you want
constexpr size_t NumberOfDimensionZ = 3U;
int main() {
// Open input csv file, and check, if open operation worked
if (std::ifstream clvIn("r:\\File_read.csv"); clvIn) {
// Define 2d array and initialize all values with 0.0;
Matrix2dYX myx{};
// Read all lines of the file and split values
for (std::string line{}; std::getline(clvIn, line); ) {
// Convert just read string to a std::istringstream
std::istringstream iss{ line };
// Add the new values to the 2d array. Iterate over all values in one line
// then create a 1d vector inplace and add this line values to our 2d matrix
myx.emplace_back(Matrix1dX(std::istream_iterator<DataType>(iss), {}));
}
// Define a 3d matrix, with a given size and having each z-value be the data from the csv file
Matrix3dZYX mzyx(NumberOfDimensionZ, myx);
// Some debug output
// Show result to user
for (const Matrix2dYX& m2 : mzyx) {
std::cout << "\n";
for (const Matrix1dX& m1 : m2) {
for (const DataType& d : m1) std::cout << d << "\t";
std::cout << "\n";
}
}
}
else {
std::cerr << "\n*** Error: Could not open input file\n";
}
return 0;
}
Please note that you can write elegant very elegant and compact code in C++.
For reading the file and creating the 3d vector, I do not need any loop.
Please read and try to understand. Please google unknwon language constructs. If you do not understand, then ask.
Related
I'm new to vectors programming, so my code is buggy:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::ifstream in("input.txt");
std::vector<std::vector<int> > v, w;
if (in) {
std::string line;
while (std::getline(in, line)) {
v.push_back(std::vector<int>());
for(int x=0; x<line.size(); x++){
v.back().push_back((int)line[x] - (int)'0');
}
}
}
for (int i = 0; i < v.size(); i++) {
for (int j = 0; j < v[i].size(); j++)
std::cout << v[i][j] << ' ';
std::cout << '\n';
}
int size = v.size(); //because its a square matrix
w = v; //w is our temp vector for storing new values;
int alive =0;
int z=0;
for (int i=0;i<size;i++)
{
for (int j=0;j<size; j++)
{
alive = 0;
for(int c = -1;c<2; c++)
{
for(int d = -1; d<2 ; d++)
{
if(!(c==0 && d == 0))
{
z = v[i+c][j+d];
if(z)
++alive;
}
}
if(alive<2) w[i].push_back(0);
else if(alive == 3) w[i].push_back(1);
else w[i].push_back(0);
}
}
}
return 0;
}
I think I am assigning values into my second variable wrong. My program reads from an input file along the lines:
1010101
0101010
1010101
and is to write to the second vector w after analyzing its neighbors (game of life problem), I think I should use w.push_back() but I'm not sure on the syntax for a 2D vector. Is there a better way to push the variable?
There are two problems that I notice right away. The main one that is causing your crash is you are accessing outside of the bounds for the v array. This happens when i is 0 and c is -1, and can also happen when i is size-1 and c is +1 (the same thing happens with j and d).
The other issue is with how you save the alive value into w. Since you start with w = v, you have all the elements you need. Just replace them with, for example, w[i][j] = 0. (You'll also want to move that conditional block outside of the c loop.)
I have a file with zero and one. The digits represent a ASCII map I want to read from a file and place in a array. Its a lot easier create the map on a text file that manually assign them to all array places
Here is my code below. I cant understand why there is an error. I will add the error image so one can see the red line under neath the part
The result should be reading them digits from the file and inserting them into the array
Any help with this tiny error would be much appreciated
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
int levelOneArray[29][29];
ofstream levelOne;
int digit;
levelOne.open("levelOne.txt");
for (int x = 0; x < 30; ++x)
{
for (int y = 0; y < 30; ++y)
{
levelOne >> digit;
int value = digit;
levelOneArray[y][x] = digit;
}
}
}
//This is what is contained in the levelOne.txt file
111111111111111111111111111111
100000000000000000111000000111
101111101110001110111001110111
101111101110001110000001110001
101111101110001111111101111111
101111100000001111111100011111
101111101110001111111100011111
100000000000001111111100011111
101111110000000000111100000001
101000010111111110111100000001
101111010000000010111111111101
101111011111111010111111111101
101111000000001010111101000001
101111111111101010111101000001
100000111111101010111101011111
101110111111101010111100011111
100000111111101011111110011111
100111111111101001111110011111
100110000000000001111110000001
100000111100001000000000111001
100000100101101111111110111011
100110110101101000011000111001
100110110101101011011011111001
100000000001101011000011111001
100000000011101011111111111001
111110110011101011111111111101
100110110011101011111111111001
101100000010000000100000100001
100000000000001000000100000011
111111111111111111111111111111
Here are my images
Image One Error Image One
Image Two Error Image two
Your array levelOneArray has 29 rows and 29 columns (i.e. indices 0..28), but in your for-loop you loop until 30, which is 1 too much.
int levelOneArray[29][29];
//...
for (int x = 0; x < 29; ++x)
{
for (int y = 0; y < 29; ++y)
{
// ..
}
}
Solution by OP.
int main()
{
char levelOneArray[30][30];
ifstream levelOne;
char digit;
levelOne.open("levelOne.txt");
for (int x = 0; x < 30; ++x)
{
for (int y = 0; y < 30; ++y)
{
levelOne >> digit;
char value = digit;
levelOneArray[y][x] = digit;
}
}
for (int x = 0; x < 30; ++x)
{
for (int y = 0; y < 30; ++y)
{
cout << levelOneArray[y][x];
}
cout << endl;
}
cout << endl;
int end;
cin >> end;
return 0;
}
I have a file with a grid of numbers that I'm trying to iterate through. I know the dimensions of the grid, but I can't seem to find a way to access the value at each location. Here's an outline of what I've got so far in partial pseudocode:
std::ifstream file(filename);
for (y = 0; y < height; y++)
{
string line = file[y]; // wrong
for (x = 0; x < width; x++)
{
int value = line[x] // wrong
}
}
What's the best way to accomplish this? Thanks in advance for any help.
It should look more like this:
for (int y = 0; y < height; y++)
{
string line;
getline(file,line);
std::istringstream line_stream(line);
for (int x = 0; x < width; x++)
{
int value;
line_stream >> value;
}
}
You can not access a stream like this, it is serial in nature.Using streams pseudo code could look like this (did not try to compile, however this is the idea)
#include <iostream> // std::cout
#include <fstream> // std::ifstream
int main () {
std::ifstream ifs ("test.txt", std::ifstream::in);
#define LINE_SIZE 10
char c = ifs.get();
for (int i=0;ifs.good();i++) {
// this element is at row :(i/LINE_SIZE) col: i%LINE_SIZE
int row=(int)(i/LINE_SIZE);
int col=(i%LINE_SIZE);
myFunction(row,col,c);
c = ifs.get();
}
ifs.close();
return 0;
}
Recently I am writing a program to generate a fixed number of permutation of alphabets inputted. For example, I inputted 3, 3, ABC, the program will output ABC, ACB, BAC, according to lexicographical order. But the program cannot get through all the test case and i cant find out where is the bug. Please help.
#include <iostream>
using namespace std;
int used[26], cou = 0, k, n, i;
string output;
string sorting(string x, int y)
{
char temp;
int i, j;
for (i = 0; i < y; ++i)
{
for (j = 0; j < y-1; ++j)
{
if (x[j]-'0' > x[j+1]-'0')
{
temp = x[j];
x[j] = x[j+1];
x[j+1] = temp;
}
}
}
return x;
}
void out(int x, string y)
{
int i;
if (cou == k)
{
return;
}
if (x == n+1)
{
cout << output << endl;
++cou;
}
else
{
for (i = 0; i < n; ++i)
{
if (used[i] == 0)
{
used[i] = 1;
output[x-1] = y[i];
out(x+1, y);
used[i] = 0;
}
}
}
}
int main()
{
char inpi;
string inp, ha;
cin >> n >> k >> inp;
output.resize(n);
for (i = 0; i < 26; ++i)
{
used[i] = 0;
}
inp = sorting(inp, n);
out(1, inp);
}
I am not sure that I understood the question.
Leaving the algorithm aside, you should know that a standard string is able to tell how long is. Therefore the y parameter in sorting is redundant. Use x.size() to find the size.
Another problem is output[x] = y[i];. You did not set output's size: it is zero. Since you are looking for permutations, I assume its size must equal y's size: output.resize( y.size() );.
One last thing: use meaningful identifiers. y may be good for a compiler; for a human, it may define a bad day.
There doesn't seem to be a need to create a global as you have done
string output;
Create a string to capture the output either within main() and pass it by reference to the functions which need them, in this case fill()
or
create it within fill() and return it by value once its populated
I am writing a program which will preform texture synthesis. I have been away from C++ for a while and am having trouble figuring out what I am doing wrong in my class. When I run the program, I get an unhandled exception in the copyToSample function when it tries to access the arrays. It is being called from the bestSampleSearch function when the unhandled exception occurs. The function has been called before and works just fine, but later on in the program it is called a second time and fails. Any ideas? Let me know if anyone needs to see more code. Thanks!
Edit1: Added the bestSampleSearch function and the compareMetaPic function
Edit2: Added a copy constructor
Edit3: Added main()
Edit4: I have gotten the program to work. However there is now a memory leak of some kind or I am running out of memory when I run the program. It seems in the double for loop in main which starts "// while output picture is unfilled" is the problem. If I comment this portion out the program finishes in a timely manner but only one small square is output. Something must be wrong with my bestSampleSearch function.
MetaPic.h
#pragma once
#include <pic.h>
#include <stdlib.h>
#include <cmath>
class MetaPic
{
public:
Pic* source;
Pixel1*** meta;
int x;
int y;
int z;
MetaPic();
MetaPic(Pic*);
MetaPic(const MetaPic&);
MetaPic& operator=(const MetaPic&);
~MetaPic();
void allocateMetaPic();
void copyPixelData();
void copyToOutput(Pic*&);
void copyToMetaOutput(MetaPic&, int, int);
void copyToSample(MetaPic&, int, int);
void freeMetaPic();
};
MetaPic.cpp
#include "MetaPic.h"
MetaPic::MetaPic()
{
source = NULL;
meta = NULL;
x = 0;
y = 0;
z = 0;
}
MetaPic::MetaPic(Pic* pic)
{
source = pic;
x = pic->nx;
y = pic->ny;
z = pic->bpp;
allocateMetaPic();
copyPixelData();
}
MetaPic::MetaPic(const MetaPic& mp)
{
source = mp.source;
x = mp.x;
y = mp.y;
z = mp.z;
allocateMetaPic();
copyPixelData();
}
MetaPic::~MetaPic()
{
freeMetaPic();
}
// create a 3 dimensional array from the original one dimensional array
void MetaPic::allocateMetaPic()
{
meta = (Pixel1***)calloc(x, sizeof(Pixel1**));
for(int i = 0; i < x; i++)
{
meta[i] = (Pixel1**)calloc(y, sizeof(Pixel1*));
for(int j = 0; j < y; j++)
{
meta[i][j] = (Pixel1*)calloc(z, sizeof(Pixel1));
}
}
}
void MetaPic::copyPixelData()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
meta[i][j][k] = source->pix[(j*z*x)+(i*z)+k];
}
}
}
void MetaPic::copyToOutput(Pic* &output)
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
output->pix[(j*z*x)+(i*z)+k] = meta[i][j][k];
}
}
}
// copy the meta data to the final pic output starting at the top left of the picture and mapped to 'a' and 'b' coordinates in the output
void MetaPic::copyToMetaOutput(MetaPic &output, int a, int b)
{
for(int j = 0; (j < y) && ((j+b) < output.y); j++)
{
for(int i = 0; (i < x) && ((i+a) < output.x); i++)
{
for(int k = 0; k < z; k++)
output.meta[i+a][j+b][k] = meta[i][j][k];
}
}
}
// copies from a source image to a smaller sample image
// *** Must make sure that the x and y coordinates have enough buffer space ***
void MetaPic::copyToSample(MetaPic &sample, int a, int b)
{
for(int j = 0; (j < sample.y) && ((b+j) < y); j++)
{
for(int i = 0; i < (sample.x) && ((a+i) < x); i++)
{
for(int k = 0; k < sample.z; k++)
{
**sample.meta[i][j][k] = meta[i+a][j+b][k];**
}
}
}
}
// free the meta pic data (MetaPic.meta)
// *** Not to be used outside of class declaration ***
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
main.cpp
#ifdef WIN32
// For VC++ you need to include this file as glut.h and gl.h refer to it
#include <windows.h>
// disable the warning for the use of strdup and friends
#pragma warning(disable:4996)
#endif
#include <stdio.h> // Standard Header For Most Programs
#include <stdlib.h> // Additional standard Functions (exit() for example)
#include <iostream>
// Interface to libpicio, provides functions to load/save jpeg files
#include <pic.h>
#include <string.h>
#include <time.h>
#include <cmath>
#include "MetaPic.h"
using namespace std;
MetaPic bestSampleSearch(MetaPic, MetaPic);
double compareMetaPics(MetaPic, MetaPic);
#define SAMPLE_SIZE 23
#define OVERLAP 9
// Texture source image (pic.h uses the Pic* data structure)
Pic *sourceImage;
Pic *outputImage;
int main(int argc, char* argv[])
{
char* pictureName = "reg1.jpg";
int outputWidth = 0;
int outputHeight = 0;
// attempt to read in the file name
sourceImage = pic_read(pictureName, NULL);
if(sourceImage == NULL)
{
cout << "Couldn't read the file" << endl;
system("pause");
exit(EXIT_FAILURE);
}
// *** For now set the output image to 3 times the original height and width ***
outputWidth = sourceImage->nx*3;
outputHeight = sourceImage->ny*3;
// allocate the output image
outputImage = pic_alloc(outputWidth, outputHeight, sourceImage->bpp, NULL);
Pic* currentImage = pic_alloc(SAMPLE_SIZE, SAMPLE_SIZE, sourceImage->bpp, NULL);
MetaPic metaSource(sourceImage);
MetaPic metaOutput(outputImage);
MetaPic metaCurrent(currentImage);
// seed the output image
int x = 0;
int y = 0;
int xupperbound = metaSource.x - SAMPLE_SIZE;
int yupperbound = metaSource.y - SAMPLE_SIZE;
int xlowerbound = 0;
int ylowerbound = 0;
// find random coordinates
srand(time(NULL));
while((x >= xupperbound) || (x <= xlowerbound))
x = rand() % metaSource.x;
while((y >= yupperbound) || (y <= ylowerbound))
y = rand() % metaSource.y;
// copy a random sample from the source to the metasample
metaSource.copyToSample(metaCurrent, x, y);
// copy the seed to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, 0, 0);
int currentOutputX = 0;
int currentOutputY = 0;
// while the output picture is unfilled...
for(int j = 0; j < yupperbound; j+=(SAMPLE_SIZE-OVERLAP))
{
for(int i = 0; i < xupperbound; i+=(SAMPLE_SIZE-OVERLAP))
{
// move the sample to correct overlap
metaSource.copyToSample(metaCurrent, i, j);
// find the best match for the sample
metaCurrent = bestSampleSearch(metaSource, metaCurrent);
// write the best match to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, i, j);
// update the values
}
}
// copy the metaOutput to the output
metaOutput.copyToOutput(outputImage);
// output the image
pic_write("reg1_output.jpg", outputImage, PIC_JPEG_FILE);
// clean up
pic_free(sourceImage);
pic_free(outputImage);
pic_free(currentImage);
// return success
cout << "Done!" << endl;
system("pause");
// return success
return 0;
}
// finds the best sample to insert into the image
// *** best must be the sample which consists of the overlap ***
MetaPic bestSampleSearch(MetaPic source, MetaPic best)
{
MetaPic metaSample(best);
double bestScore = 999999.0;
double currentScore = 0.0;
for(int j = 0; j < source.y; j++)
{
for(int i = 0; i < source.x; i++)
{
// copy the image starting at the top left of the source image
source.copyToSample(metaSample, i, j);
// compare the sample with the overlap
currentScore = compareMetaPics(best, metaSample);
// if best score is greater than current score then copy the better sample to best and continue searching
if( bestScore > currentScore)
{
metaSample.copyToSample(best, 0, 0);
bestScore = currentScore;
}
// otherwise, the score is less than current score then do nothing (a better sample has not been found)
}
}
return best;
}
// find the comparison score for the two MetaPics based on their rgb values
// *** Both of the meta pics should be the same size ***
double compareMetaPics(MetaPic pic1, MetaPic pic2)
{
float r1 = 0.0;
float g1 = 0.0;
float b1 = 0.0;
float r2 = 0.0;
float g2 = 0.0;
float b2 = 0.0;
float r = 0.0;
float g = 0.0;
float b = 0.0;
float sum = 0.0;
// take the sum of the (sqrt((r1-r2)^2 + ((g1-g2)^2 + ((b1-b2)^2))
for(int j = 0; (j < pic1.y) && (j < pic2.y); j++)
{
for(int i = 0; (i < pic1.x) && (i < pic2.x); i++)
{
r1 = PIC_PIXEL(pic1.source, i, j, 0);
r2 = PIC_PIXEL(pic2.source, i, j, 0);
g1 = PIC_PIXEL(pic1.source, i, j, 1);
g2 = PIC_PIXEL(pic2.source, i, j, 1);
b1 = PIC_PIXEL(pic1.source, i, j, 2);
b2 = PIC_PIXEL(pic2.source, i, j, 2);
r = r1 - r2;
g = g1 - g2;
b = b1 - b2;
sum += sqrt((r*r) + (g*g) + (b*b));
}
}
return sum;
}
I'm not sure if this is the root cause of the problem, but your assignment operator does not actually assign anything:
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
This should probably look something like the following (based off of the code in your copy constructor):
edit: with credit to Alf P. Steinbach
MetaPic& MetaPic::operator=(MetaPic mp)
{
mp.swap(*this);
return *this;
}
It turns out that the deallocate function is incorrect. It should be freeing in the same manner that it was allocating.
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}