writing to 2D vector, is crashing my program - c++

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.)

Related

Reading data from csv file into an array

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.

Correct implementation of 2d vector population

I have a constructor and a method in an implementation file:
Boggle::Boggle(std::string boardString){
dim = sqrt(boardString.size());
vector<vector<char> > grid(dim, vector<char>(dim));
int co = 0;
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
grid[i][j] = boardString[co];
co++;
}
}
}
void Boggle::printMe() {
for (auto inner : grid)
{
for (auto item : inner)
{
cout << item << " ";
}
cout << endl;
}
}
The program executes, but doesn't do anything. As you can see I have sized my vector when I declared it. I believe the issue lies in my logic of assigning a character to a vector from a string perhaps.
As hinted in comments your vector grid is local to your function. You mostly likely wanted to use a class variable but ended up creating a local variable. You can use resize to set the dimensions of your grid. Also its better to ceil the sqrt to make sure that we are not missing any characters.
Example:
#include <stdio.h>
#include <vector>
#include <string>
#include <cmath>
#include <iostream>
using namespace std; // Avoid this
class Boggle{
public:
int dim;
vector<vector<char>> grid;
Boggle(string boardString);
void printMe();
};
Boggle::Boggle (std::string boardString)
{
dim = ceil(sqrt(boardString.size ()));
grid.resize(dim, vector <char>(dim));
int co = 0;
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++)
{
grid[i][j] = boardString[co];
co++;
}
}
}
void Boggle::printMe ()
{
for (auto inner:grid) {
for (auto item:inner)
{
cout << item << " ";
}
cout << endl;
}
}
int main(){
Boggle boggle("hello world");
boggle.printMe();
return 0;
}
Result:
h e l l
o w o
r l d

c++ 2d array leads to Segmentation fault (core dumped)

I have a program (below) to build a matrix of distances between points (in my test file there are ~8000 points in 3D space). So I want a (roughly) 8000x8000 matrix, but when I try to build it using an array of doubles (or floats), I always get a 'Segmentation fault (core dumped)' error. Any ideas why? I have 16GB of RAM, so this should be feasible, since 8000 * 8000 * 8 is only roughly 0.5GB. Also (commented out in code below), I can build the matrix as a vector of vectors, but this is slow - takes around 30 seconds. As it happens, I only need to record distances less than 1.5, so the matrix is very sparse - no doubt there are better ways of implementation, but it's bugging me that this doesn't work. Any advice gratefully received!
//Get distance matrix from .dms file
#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
double dist(vector<double> a, vector<double> b) {
if (a.size() != b.size()) return -1;
else
{
double dist = 0;
for (int i = 0; i < a.size(); i++) dist += pow(a[i] - b[i], 2);
return dist;
}
}
int main() {
ifstream infile;
ofstream outfile;
vector<vector<double> > points;
string line;
infile.open("1dwr.dms");
outfile.open("1dwr.mat");
while (getline(infile,line))
{
if ((line.at( line.length() - 1)) != 'A')
{
double x[3] = {atof((line.substr(13,8)).c_str()), atof((line.substr(21,9)).c_str()), atof((line.substr(30,9)).c_str())};
vector<double> point;
for (int i=0; i<3; i++)
{
point.push_back(x[i]);
}
points.push_back (point);
}
}
infile.close();
int len = points.size();
double dist_matrix[len][len];
for (int i=0; i<len; i++)
{
for(int j=i; j<len; j++)
{
double d = dist(points[i], points[j]);
if(d < 2.25)
{
dist_matrix[i][j] = sqrt(d);
dist_matrix[j][i] = sqrt(d);
}
}
}
// vector<vector<double> > dist_matrix;
// for (int i=0; i<len; i++)
// {
// vector< double> row;
// for (int j=0; j<len; j++)
// {
// double d = dist(points[i], points[j]);
// if (d < 2.25) row.push_back (sqrt(d));
// else row.push_back (0);
// }
// dist_matrix.push_back (row);
// }
outfile.close();
return 0;
}
The problem is that statements int len = points.size(); double dist_matrix[len][len] lets the program create a 8000 x 8000-array of doubles on the stack, and the size of the stack is - compared to the heap - rather limited. So it is very likely that you get a "stack overflow", indicated probably by a "Bad access"-error. If you try your code with 80x80, it will probably work.
So for len==8000, you'd have to create the array on the heap; yet there is - to my knowledge - no way to do a statement like double x[len][len] = new double... if len is not known at compile time.
You could come around this by allocating a 1D-array of size len * len and calculate the "2D"-index manually, as shown in the code below:
int main() {
int len = 8000;
double *dist_matrix = new double[len*len];
for (int i=0; i<len; i++)
{
for(int j=i; j<len; j++)
{
size_t idx = len*i + j;
dist_matrix[idx] = 5.0;
}
}
return 0;
}

Size of a vector of pairs

I am filling up an adjacency list of vector with pairs given by :
vector<pair<int, int>> adj[1000];
I am doing a depth first search on the list but experiencing some weird behaviour. The first print statement prints some value which means I have some items in adj[s][0], adj[s][1], adj[s][2] and so on. However when I calculate the size of adj[s] in the next line it prints out to be zero. Am I missing something here?. Is my definition for vector of pairs correct?. The adjacency list is correctly filled because when I ran cout << adj[s][0].first << endl; in dfs, it was correctly showing me the neighbors of each and every node.
Complete code
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <utility>
#include <climits>
#include <algorithm>
using namespace std;
vector<pair<int, int>> adj[1000];
bool visited[1000];
int nodeweight[1000];
void initialize()
{
for(int i = 0; i < 1000; i++)
visited[i] = false;
for(int i=0; i < 1000; i++)
adj[i].clear();
for(int i = 0; i <1000; i++)
nodeweight[i] = INT_MAX;
}
void dfs(int s)
{
visited[s] = true;
cout << adj[s][1].first << endl;
int minimum = INT_MAX, tovisit = 0;
for(int i = 0; i < adj[s].size(); i++)
{
cout << adj[s][i].second;
if(!visited[adj[s][i].first] && adj[s][i].second < minimum)
{
minimum = adj[s][i].second;
tovisit = adj[s][i].first;
}
}
nodeweight[tovisit] = minimum;
//dfs(tovisit);
}
int main() {
int N, E;
cin >> N >> E;
while(E--)
{
int i, j, w;
cin >> i >> j >> w;
adj[i].push_back(make_pair(j,w));
adj[j].push_back(make_pair(i,w));
}
initialize();
for(int i = 1; i <= N; i++)
{
dfs(i);
}
return 0;
}
You are clearing adj again after filling in initialize().
First you fill adj in the while loop in main. Then you call initialize() which includes this loop clearing all vectors in it:
for(int i=0; i < 1000; i++)
adj[i].clear();
Then you have cout << adj[s][1].first << endl; in dfs which is undefined behavior because there are no elements in adj[s]. The fact that you seem to get the correct results is just coincidental undefined behavior (although practical it is because the memory holding the vector data was not cleared.)
adj[s].size() is correctly reported as 0.

Can't read integer from file to matrix

I have to read from a file an array of numbers with an unknown size and save it as a matrix. The code must be as compact as possible, which is why I don't want to read file as string and then convert it to an int.
int main()
{
ifstream infile("array.txt");
int n, counter = 0, **p;
while (!infile.eof()) {
counter++;
}
counter = sqrt(counter);
cout << "counter is " << counter << endl;
p = new int*[counter];
for (int i = 0; i < counter; i++)
p[i] = new int[counter];
while (!infile.eof()) {
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++)
p[i][j] = n;
}
}
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++) {
cout << p[i][j] << " ";
}
cout << endl;
}
_getch();
return 0;
}
Here is my code, it was made for a square matrix. The problem is, I can't read the file at second time to save the numbers to the matrix.
You have a lot of problems in your code. A big one is that you have several infinite loops and aren't even reading from a file. An even bigger problem is that you're not using C++ constructs. I've written a small program that does what you're trying to do using more C++ concepts. In this case, you should use a std::vector - they will handle all the dynamic sizing for you.
test.cc
#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
// Nobody wants to write `std::vector<std::vector<int>>` more than once
using int_matrix = std::vector<std::vector<int>>;
void populate_matrix(int_matrix& mat, const std::string& line) {
int num;
std::stringstream ss(line);
std::vector<int> row;
// Push ints parsed from `line` while they still exist
while(ss >> num) {
row.push_back(num);
}
// Push the row into the matrix
mat.push_back(row);
}
// This is self-explanatory, I hope
void print_matrix(const int_matrix& mat) {
size_t n = mat.at(0).size();
for(size_t i = 0; i < n; ++i) {
for(size_t j = 0; j < n; ++j) {
std::cout << mat.at(i).at(j) << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char** argv) {
int_matrix mat;
// Pass the file as a command-line arg. Then you don't need to worry about the path as much.
if(argc != 2) {
std::cout << "Number of arguments is wrong\n";
return EXIT_FAILURE;
}
// Open file with RAII
std::ifstream fin(argv[1]);
std::string line;
// Handle each line while we can still read them
while(std::getline(fin, line)) {
populate_matrix(mat, line);
}
print_matrix(mat);
return EXIT_SUCCESS;
}
This code assumes the text file looks something like this:
numbers.txt
1 2 3
4 5 6
7 8 9
i.e., n lines with n numbers per line separated by whitespace.
To compile and run this code, you can follow these steps:
13:37 $ g++ test.cc -std=c++14
13:37 $ ./a.out /path/to/numbers.txt
As far as I can see the program runs once through the file and later you run another while loop to read from the file. When you read from a file, then its like your "cursor" moves forward. So basicly, if you hit the end, you have to reset the cursor back to the start of the file.
You can set your cursor back with seekg(0).(http://www.cplusplus.com/reference/istream/istream/seekg/)