This is a difficult issue but I'm not sure where to turn. To sum it up from the start, I'm having trouble with arrays in c++. To head off your inevitable response, I have to use arrays, I can't use vectors. The reason being that I will eventually be interfacing this with CUDA which can't accept vectors.
Anyway, I have written my own class to handle 2D arrays and all the stuff that goes with that behind the scenes. The header file is reproduced at the bottom of this question. I use this class to define a 6 x 10 array. I then loop over many items, primarily using the add method of my class. At some point in this complicated loop, the size of my array switches from 6 x 10 to 0 x 1074266112. I have tried to debug my code and figure out what the issue is but for the life of me I cannot find the issue.
I've printed out all the values at the moment the array size changes, and none of them are out of the norm and I'm never trying to index the array outside of the 6x10 size. In fact, it never even happens at the same point of the loop, it just seems to happen randomly for each run. The only constant I can find between each issue is that the new array size is always exactly 0 x 1074266112.
Sorry I can't provide a minimum working example, but this issue only crops up in my large program and I can't reproduce it in a smaller program. I was at least hoping anyone could see if I'm doing anything wrong with my Matrix program below and possibly suggest a method of debugging.
EDIT: If I change this to use a vector rather than an array, the issue goes away. I.e., if I change the relevant parts to vector<double> data and upon instantiating, data = *(vector<double>(x * y)), the issue mentioned above is no longer a problem. However I have no idea what could be the problem with making this an array.
#include <vector>
#include <iostream>
#ifndef MATRIX_H
#define MATRIX_H
using std::vector; using std::cout; using std::endl;
class Matrix {
//Define the private variables associated with any instance of this class.
double * data; //The 1D pointer which points to the array
int w, h; //The width and height of the 2D array that the 1D data array represents
public:
Matrix(){}
Matrix(int x, int y){ setSize(x,y); }
void setSize(int x, int y){ w = x; h = y; data = new double[x * y]; setAll(0); }
//Two methods to get the height and width of the effective 2D array
int getWidth(){ return w; }
int getHeight(){ return h; }
//Several methods used to set and get the values of elements within the array as well as extracting
//rows and columns as vectors.
void set(int x, int y, double value){ data[y*w + x] = value; }
void setAll(double value);
double get(int x, int y){ return data[y*w + x]; }
vector<double> getCol(int x);
vector<double> getRow(int y);
//Several methods to adjust the current value by the input
void increment(int x, int y){ data[y*w + w] += 1; }
void add(int x, int y, double value){ data[y*w + x] += value; }
void subtract(int x, int y, double value){ data[y*w + x] -= value; }
void multiply(int x, int y, double value){ data[y*w + x] *= value; }
void divide(int x, int y, double value){ data[y*w + x] /= value; }
};
void Matrix::setAll(double value){
for (int i = 0; i < w*h; i++){
data[i] = value;
}
}
vector<double> Matrix::getCol(int x){
vector<double> column(h);
for (int i = 0; i < h; i++){ column[i] = data[i*w + x]; }
return column;
}
vector<double> Matrix::getRow(int y){
vector<double> row(w);
for (int i = 0; i < w; i++){ row[i] = data[y*w + i]; }
return row;
}
#endif /* MATRIX_H */
Your increment method is wrong; it depends only on y when from context it looks like you intended to also use x in the array index calculation. If you're calling this increment somewhere in your program, you're probably writing to memory off in la-la land somewhere. I don't know if that's the only cause of your issue, but anyway it will corrupt your heap in probably unhelpful ways.
Related
I'm looking to define a 2 dimensional character array where arguments I pass to a function holding the array will be used to determine the size each dimension of the array.
int func(const int x, const int y) {
char maze[x][y] = { 0 };
return 0;
}
When defining x & y inside the function as constant integers the array is defined just fine. When x and y are arguments to the function the program won't compile. Why is this and how do I get around it?
You can make a wrapper around 1-dimensial array like this:
class Maze {
friend class Row;
public:
/* This helper class represents a single row of the maze */
class Row {
friend class Maze;
Maze& owner;
std::size_t row;
Row(Maze& owner_, std::size_t row_) : owner(owner_), row(row_) {}
/* this operator resolves 2nd pair of brackets */
public:
inline char& operator[](std::size_t col) { return owner.data[col + row*owner.cols]; }
};
Maze(std::size_t rows_, std::size_t cols_)
: data(rows_ * cols_, 0)
, cols(cols_)
{}
/* this operator resolves 1st pair of brackets */
inline Row operator[](std::size_t index) { return Row(*this, index); }
private:
std::vector<char> data;
std::size_t cols;
};
...
Maze m(5, 10);
m[2][3] = 1;
You need to use dynamic memory allocation. Variadic length arrays is not a part of c++ standart. However variadic length arrays available as an extension for GCC. Although you can use STL or implement your class, dont forget about new[] and the one-dimensional representation for two-dimensional array:
char* maze = new char[x*y]; // create
maze[i + j * x]; // access
delete[] maze; // delete
It is compact and in most cases fast.
When defining x & y inside the function as constant integers the array is defined just fine
It works because the size of your array is defined and known by your compiler, known at compile-time
When x and y are arguments to the function the program won't compile.
When you wish to define you array only when you call your function, you ask your program to do that during runtime
. As answered by Dmytro Dadyka, you have to use use dynamic memory allocation and manage yourself memory deallocation (delete[] maze; // delete)
Here is an alternative of defining dynamically your 2D array using template! Notice that it is always done at compile-time.
template<int X, int Y>
int f()
{
char c[X][Y];
for(int x=0; x < X; ++x)
{
for(int y=0; y < Y; ++y)
{
c[x][y] = '1';
}
}
// write your algorithm now!....
c[2][2] = 'a';
for(int x=0; x < X; ++x)
{
for(int y=0; y < Y; ++y)
{
std::cout << c[x][y] << " ";
}
std::cout << std::endl;
}
return 0;
}
int main()
{
f<5,5>();
f<7,4>();
return 0;
}
I want to give a minimal example. If the code provided is not enough, please tell me what else you need. It's nothing super secret ;)
Consider the following two implementations:
Using 3d array:
.h
class Grid
{
public:
Grid();
uint8_t get(int x, int y, int z);
void set(int x, int y, int z, uint8_t value);
private:
uint8_t blocks[Chunk::width][Chunk::height][Chunk::depth];
};
.cpp
Grid::Grid()
{
memset(blocks, 0, sizeof(blocks));
}
uint8_t Grid::get(int x, int y, int z)
{
return blocks[x][y][z];
}
void Grid::set(int x, int y, int z, uint8_t value)
{
blocks[x][y][z] = value;
}
Now a 1D array:
.h
class Grid
{
public:
Grid();
uint8_t get(int x, int y, int z);
void set(int x, int y, int z, uint8_t value);
private:
uint8_t blocks[Chunk::width * Chunk::height * Chunk::depth];
int to1D(int x, int y, int z) { return x + (y * Chunk::width) + (z * Chunk::width * Chunk::height); }
};
.cpp
Grid::Grid()
{
memset(blocks, 0, sizeof(blocks));
}
uint8_t Grid::get(int x, int y, int z)
{
return this->blocks[x + (y * Chunk::width) + (z * Chunk::width * Chunk::height)];
}
void Grid::set(int x, int y, int z, uint8_t value)
{
this->blocks[x + (y * Chunk::width) + (z * Chunk::width * Chunk::height)] = value;
}
Now with the 3D version everything works like a charm, while for the same overall size I get a
SUMMARY: AddressSanitizer: heap-buffer-overflow src/Grid.cpp:16 in Grid::get(int, int, int)
And I really wonder why that is. Both implementations hold uint8_ts... What is the optimization going on in the 3d-array version I cannot seem to see/grasp?
(Yes, this is a minecrafty voxel engine experiment ;))
If you're building an environment for a game, my guess is you're having memory allocation issues. Lets say that you need 50 MB of memory for the game you're running. Getting that 50 MB from anywhere isn't a big deal. But trying to get 50 MB of continuous memory is waaaaaayyy more difficult. Most OS's these days use a paging system to keep track of allocated and unallocated memory. Here's more info: https://en.wikipedia.org/wiki/Paging
A 3D array is basically a pointer to a array of pointers, of each of these pointers point to another array of pointers. And each of those pointers contains a finite chunk of memory to interact with. So in this case the OS can give you 5,000 50 KB chunks of memory and the pointers can keep all of this memory in different places.
Please take a look at the code below:
#include <iostream>
using namespace std;
int main(){
char matrix[2][2][2];
return 0;
}
int getMatrixData(char matrix[][2][2], int x, int y, int z) {
return matrix[x][y][z];
}
When matrix 3d array passed in as a parameter into a function, why is it ok not to specify the first [] size? How this missing dimension can be explained?
Your code is syntactically incorrect. Assuming you meant int getMatrixData(char matrix[][2][2], int x, int y, int z).
When you pass array arguments to function, array decays to pointer to first element (type char [2][2] in this case).
Now some syntax of array and pointer are similar so you don't find much difference.
When multidimensional array is passed, for example 3d in your case, it can be seen as array of 2-d arrays. So you need to give the type of each element char [2][2] in your case and you can skip the dimension of final array as it will decay to pointer anyway. char [2][2] is the information compiler needs to compute the offset of each element.
offset of matrix[x][y][z] = base address of matrix +
x * sizeof(char [2][2]) +
y * sizeof(char [2]) +
z
If you don't pass the dimensions of initial element, compiler can't resolve sizeof in above equation. Passing skipped dimension is optional.
In c++ I would use multidimensional arrays in a different way. There are many topics on the internet about it.
This topic explains how you could do it using a char***. E.g.:
char getMatrixData(char*** matrix, int x, int y, int z)
{
return matrix[x][y][z];
}
int main()
{
char ***matrix = new char**[2];
for (auto i = 0; i < 2; i++)
{
matrix[i] = new char*[2];
for (auto j = 0; j < 2; j++)
{
matrix[i][j] = new char[2];
}
}
getMatrixData(matrix, 1, 1, 1);
// N.B.! you should normally free the memory using delete []!!
// But in this case the program ends, so the memory is freed anyhow.
return 0;
}
But you could also use the std::vector type
#include <vector>
using std::vector;
using CharVector1D = vector<char>;
using CharVector2D = vector<CharVector1D>;
using CharVector3D = vector<CharVector2D>;
char getMatrixData(CharVector3D const& matrix, int x, int y, int z)
{
return matrix[x][y][z];
}
int main()
{
CharVector3D matrix(2, CharVector2D(2, CharVector1D(2)));
getMatrixData(matrix, 1, 1, 1);
return 0;
}
However, c++ is supposed to be an object oriented programming language. So it is probably better to define an matrix object.
#include <vector>
using std::vector;
template <class T>
class Matrix3D
{
private:
size_t _sizeX;
size_t _sizeY;
size_t _sizeZ;
vector<T> _data;
public:
Matrix3D(size_t const x_size, size_t const y_size, size_t const z_size)
: _sizeX(x_size)
, _sizeY(y_size)
, _sizeZ(z_size)
, _data(vector<T> (x_size*y_size*z_size))
{}
T GetData(size_t const x, size_t const y, size_t const z) const
{
return _data.at(x + (_sizeX * (y + (_sizeY * z))));
}
};
int main()
{
Matrix3D<char> matrix(2, 2, 2);
matrix.GetData(1, 1, 1);
return 0;
}
I am trying to learn c++. I have created a vector class vec and I am trying to implement a method to compute the dot product.
It compiles fine but I get a segmentation error when running it. I have pinned the x(i) reference in the dot product method down as the cause, but I have no idea why. I gather it is something about accessing memory incorrectly, but I have no idea what I am doing incorrectly nor what the correct way would be.
My vector class:
class vec{
private:
vector<double> data;
int n; // size
public:
vec (int s) { n = s; data.reserve(n); }
double get(int i) { return data[i]; }
void set(int i, double val) { data[i] = val; }
int size() { return n; }
double operator[] (int i) { return get(i); }
double operator() (int i) { return get(i); }
double dot (vec x) {
assert(n == x.size());
int z = 0;
for (int i = 0; i < n; i++){
z += data[i] * x(i);
}
return z;
}
};
I am trying to use it like so:
int main(int argc, char *argv[]) {
vec x = vec(3);
x.set(0, 1);
x.set(1, 1);
x.set(2, 2);
vec y = vec(3);
y.set(0, 2);
y.set(1, 2);
y.set(2, 3);
double z = x.dot(y);
}
Change this:
data.reserve(n);
To this:
data.resize(n);
The reserve does not create the items in a vector. All it does is increase the capacity. To actually create n objects up front, you use resize.
Also on a side note, I highly suggest you not use extraneous variables such as n to keep track of a vector's size. Use the vector::size() function instead. The reason is that you're risking bugs if for some reason n is not updated correctly.
Thus this should be your constructor:
vec (int s) : data(s) {}
and dump the n member variable.
In this clause:
vec y = vec(3);
y.set(0, 2);
y.set(1, 2);
y.set(2, 3);
You're setting index 3, which is out of bounds of this vector. To fix it, either initialize vec to be of length 4, or index somewhere else. :)
You should also be resizing instead of reserving, but getting this wrong shouldn't cause a segfault. It should just confuse people.
I want to work with Images, and I want to create my structure Image with first 2 values to be it's size (grayscale) and the third - data (2D array of size m by n).
How can I implement it? If I don't know the image's size in advance. Something like this:
struct Image{
int n;
int m;
data = 2D array of size mxn
}
Instead I would use
struct Image{
int n;
int m;
vector<vector<int>> data;
}
Of you could use a 1D vector that has size
vector<int> data(m * n);
Ignoring encapsulation, something like this could work:
#include <vector>
struct Image {
int n;
int m;
std::vector<std::vector<int>> data; // May want to change int type ?
Image(int n, int m) : n(n), m(m), data(n) {
for (int row = 0; row < n; row++) {
data[row].resize(m);
}
}
};
// Example Usage
Image img(10, 10);
for (int row = 0; row < img.n; row++) {
for (int col = 0; col < img.m; col++) {
img.data[row][col] = valueFromImageFile;
}
}
If you're not just looking for something quick and dirty, and this is going to be an ongoing project, I would recommend that you learn more about object oriented concepts :)
There are two common patterns for that (even if inherited from C). Both share a common principle : a logical separation between a fixed size header and a variable part.
First method : the struct contains the fixed size part and a pointer (or pointers in a generic case) to memory allocated with new (in constructor) and deallocated in destructor. It is a bit hand-driven, but easy to use and to understand.
Image could look like (I assume Pixel is a class representing a single pixel):
class Image {
private:
int _x, _y;
Pixel *data;
public:
Image(int x, int y);
~Image();
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image::Image(int x, int y) {
data = new Pixel[x * y];
_x = x;
_y = y;
}
Image::~Image() {
delete[] data;
data = NULL;
}
Second method : the pseudo-struct is composed of a fixed size header, and of a dynamic part. The dynamic part is declared in the struct to be of size 1. It is obviously false, and you cannot use sizeof on such a struct, but as C does not inforce comparison of array to the declared size it works :
class Image {
private:
int _x, _y;
Pixel data[1];
Image(int x, int y); // private to force usage of createImage
public:
static Image* createImage(int x, int y);
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image* Image::createImage(int x, int y) {
Image* image = (Image *) malloc(sizeof(Image) + (x * y - 1) * sizeof(Pixel));
image->_x = x;
image->_y = y;
return image;
}
I must admit it is really C code embedded in C++, but I cited it because it is heavily used in Microsoft Win32 API.