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.
Related
I have a 2D grid class which is made up of cells, I must store the cells in a 1D std::vector (due to specification) that models the 2D grid.
I have written a Grid::resize function that resizes the grid to a new width and height but preserves the content of the grid within the kept region (all new cells are set to
Cell::DEAD).
I have written a resize function that when run causes a segmentation fault: 11, which I assume means the function is trying to access data outside the bounds of the vector but I am not sure where the error is.
Class
class Grid {
private:
std::vector<Cell> grid_cells;
unsigned int width;
unsigned int height;
public:
Grid(const unsigned int width, const unsigned int height);
}
Constructor code
Grid::Grid(const unsigned int width, const unsigned int height) {
std::vector<Cell> cells(width*height);
int i;
for(i=0;i<(width*height);i++){
cells[i] = Cell::DEAD;
}
this->width = width;
this->height = height;
this->grid_cells = cells;
}
Resize function
void Grid::resize(const unsigned int new_width, const unsigned int new_height) {
std::vector<Cell> new_cells(new_width*new_height);
unsigned int x, y;
for(x = 0; x < new_width; x++) {
for(y = 0; y < new_height; y++) {
if(x < this->width && y < this->height) {
new_cells[get_index(x,y)] = this->grid_cells[get_index(x,y)];
}
else {
new_cells[get_index(x,y)] = Cell::DEAD;
}
}
}
this->width = new_width;
this->height = new_height;
this->grid_cells = new_cells;
}
My code is being tested by running pre-made test suites on it, I believe the error comes from the body of the for loops because when I comment this out the test suite runs to the end but when its left it I get a segmentation fault and it stops running.
Edit:
get_index function for converting the 2D x,y coordinate to the 1D index:
const unsigned int Grid::get_index(const unsigned int x, const unsigned int y) const{
return ((y * this->width) + x + 1);
}
const unsigned int
Grid::get_index(const unsigned int x, const unsigned int y) const{
return ((y * this->width) + x + 1);
}
You are using the original grid width to compute the index in the new grid. They can be vastly different, so you will copy the wrong cell or access memory out of bound of new_cells
Furthermore, as it is, you always perform invalid memory accesses when trying to access the last cell with coordinate (width-1, height-1), which is at height*width - width + width -1 + 1 = height*width. The last valid index for the vector is height*width-1
You could use a free function
unsigned int
get_index(const unsigned int x, const unsigned int y, const unsigned int width) const{
return (y * width) + x ;
}
and have
new_cells[get_index(x,y, new_width)] = this->grid_cells[get_index(x,y, this->width)]
I'm attempting to write a C++ program that uses a Point class consisting of x and y coordinates (ints) and a boolean. The x and y coordinates should be in the range from 0-100, but upon execution and with a print statement to test, the values printed out are corrupted.
My code looks like this:
int main(int argc, const char * argv[]) {
vector<Point> points;
for (int i = 0; i<200; i++) {
int rand_X = (rand() % 100) + 1;
int rand_Y = (rand() & 100) + 1;
Point point = Point(rand_X, rand_Y, false);
cout<< point.getX() << " " << point.getY() << endl;
points.push_back(point);
}
return 0;
and the Point class looks like this, if that's relevant:
struct Point {
public:
int x;
int y;
bool in_layer;
Point(int x, int y, bool in_layer) {}
int getX() {return this->x;}
int getY() {return this->y;}
};
And the output is just "-272632592 32766" repeated 200 times, which I'm assuming is a corrupted value.
Any ideas what could be causing the issue?
Your constructor didn't do anything, which contribute to an UB when you call getX getY methods. Plus, I think there's no need to use constructor and getx gety methods here.
If that's a code for learning, you may need to assign to the member x, y in the constructor or use the folowing technique (initialization list):
Point(int _x, int _y, bool _in_layer) : x(_x), y(_y), in_layer(_in_layer){}
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;
}
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.
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.