I have currently a problem with the following C++ class, which holds the model logic of a cube. The constructor creates a dynamic 2d char array with the following content:
[ [0,0,0,0,0,0],
[1,1,1,1,1,1],
[2,2,2,2,2,2],
[3,3,3,3,3,3],
[4,4,4,4,4,4],
[5,5,5,5,5,5] ].
CubeModel.h
#ifndef CUBEMODEL_H_INCLUDED
#define CUBEMODEL_H_INCLUDED
#include <iostream>
class CubeModel
{
private:
const unsigned short m_faces;
const unsigned short m_fields;
char **m_cube_base_pointer;
public:
CubeModel(const unsigned short faces, const unsigned short fields);
~CubeModel();
void output();
};
#endif // CUBEMODEL_H_INCLUDED
CubeModel.cpp
#include "CubeModel.h"
CubeModel::CubeModel(const unsigned short faces, const unsigned short fields): m_faces(faces), m_fields(fields) {
m_cube_base_pointer = new char*[m_faces];
for (unsigned int i = 0; i < m_faces; ++i) {
m_cube_base_pointer[i] = new char[m_fields * m_fields];
memset(m_cube_base_pointer[i], i, sizeof m_cube_base_pointer[i]);
}
}
CubeModel::~CubeModel() {
for (unsigned int i = 0; i < m_faces; ++i) {
std::cout << (int) m_cube_base_pointer[i][0];
delete [] m_cube_base_pointer[i];
}
delete [] m_cube_base_pointer;
}
/*
Console output of the cube model
*/
void CubeModel::output() {
for (unsigned int i = 0; i < m_faces; ++i) {
for (unsigned int j = 0; j < m_fields * m_fields; ++j) {
std::cout << (int) m_cube_base_pointer[i][j] << std::endl; // output the model
}
}
}
main.cpp
#include <iostream>
#include "CubeModel.h"
using namespace std;
int main() {
CubeModel cube = CubeModel(6, 3);
cube.output();
system("PAUSE");
return 0;
}
When I create a CubeModel object in the main function and call the output method, I got the following error message in Visual Studio:
Exception raised at 0x00FC1DC8 in Cube.exe: 0xC0000005: Access violation at reading a position 0x00000000.
The exception is raised inside the output() method in CubeModel.
What I'm doing wrong here?
The third argument of memset is the number of bytes you want to set.
However
sizeof m_cube_base_pointer[i]
will give you the size of the pointer, not the size of the dynamic array you just allocated. So in order to get the right number of bytes you want to set, you should do
sizeof(char) * m_fields * m_fields
instead. And your memset call should become this:
memset(m_cube_base_pointer[i], i, sizeof(char) * m_fields * m_fields);
Related
class A{
char info[256];
public:
char* getInfo();
A(char i[256]);
//A.cpp
#include "A.h"
char * A::getInfo(){
return(&info[256]);
}
A::A(char i[256]){
info[256]=i[256];
}
I'm struggling with the accessor. When I try to use getInfo(), I get a char*, and thus with
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
I get
╠╠╠╠╠╠╠╠test
I guess I'm doing things the wrong way, but I cant figure it out..
By the way, VScode also warn me on
info[256]=i[256]
by telling me that 257 octets bytes might be written (C6386) but I dont get it ...
Could you help me please ? Thanks !
The problem is, your constructor is not initializing the contents of the info array correctly, and your accessor is returning a bad pointer.
In the constructor, info[256]=i[256] does not do what you think it does. You are trying to copy the 257th element of i into the 257th element of info, which is Undefined Behavior since neither array has 257 elements. That is why the compiler is warning you about it.
Try this instead:
A::A(char i[256]){
for(int x = 0; x < 256; ++x){
info[x] = i[x];
}
}
Alternatively:
#include <algorithm>
A::A(char i[256]){
std::copy_n(i, 256, info);
}
As for the accessor, it is returning a pointer to the non-existent 257th element. You need to return a pointer to the 1st element instead:
char * A::getInfo(){
return(&info[0]);
}
Or simply:
char * A::getInfo(){
return info;
}
This declaration of the constructor
A(char i[256]);
does not make a great sense because the compiler will adjust the parameter declaration like
A(char *i);
Taking into account this code snippet
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
It seems you want that the constructor would accept a string. If so then it should be declared like
A( const char * );
and it can be defined like
#include <cstring>
//...
A::A( const char *i ){
strncpy( info, i, sizeof( info ) );
info[sizeof( info ) - 1] = '\0';
}
The member function getInfo should return the array instead of the address of the non-existent element info[256]
char * A::getInfo(){
return info;
}
This method should be also overloaded
const char * getInfo() const;
And this loop
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
should be substituted for this statement
std::cout << d.getInfo();
I need to modifiy an existing API and basically the only option I have is returning a pointer to a ragged array through a function argument (this would normally not be me personal preference). I can't get my head around doing this and keep getting a segmentation fault at this part of the code:
void getMxByArg(int ***pppX) {
*pppX = m_ppMx; // SEGMENTATION FAULT HERE
}
I've provided an example below which doesn't have any external dependencies and encapsulates the problem.
#include <stdint.h>
#include <iostream>
using namespace std;
class Mx {
public:
Mx() {
int *buff01 = (int*)malloc(3 * sizeof(int));
int *buff02 = (int*)malloc(3 * sizeof(int));
buff01[0] = 0;
buff01[1] = 1;
buff01[2] = 3;
buff02[0] = 4;
buff02[1] = 5;
buff02[2] = 6;
m_n = 2;
m_ppMx = (int**)malloc(m_n * sizeof(int*));
m_ppMx[0] = buff01;
m_ppMx[1] = buff02;
}
~Mx() {
for (int i=0; i<m_n; ++i) {
free(m_ppMx[i]);
}
free(m_ppMx);
}
int** getMx() {
return m_ppMx;
}
void getMxByArg(int ***pppX) {
*pppX = m_ppMx; // SEGMENTATION FAULT HERE
}
private:
int **m_ppMx;
int m_n;
};
int main()
{
Mx mx;
// SUCCESS
int **ppX = mx.getMx();
// FAILURE, Results in segmentation fault in getMxByArg
int ***pppX;
mx.getMxByArg(pppX);
return 0;
}
In the posted code, you are dereferencing an uninitialized pointer. That's cause for undefined behavior.
The solution is:
Create a variable of type int**.
Pass the address of that variable to the function.
int **ppX2;
mx.getMxByArg(&ppX2);
Another option is to change the argument type to int**&.
void getMxByArg(int**& ppX) {
ppX = m_ppMx;
}
Then, you can use:
int **ppX2;
mx.getMxByArg(ppX2);
I'm having some trouble writing a circular buffer in C++. Here is my code base at the moment:
circ_buf.h:
#ifndef __CIRC_BUF_H__
#define __CIRC_BUF_H__
#define MAX_DATA (25) // Arbitrary size limit
// The Circular Buffer itself
struct circ_buf {
int s; // Index of oldest reading
int e; // Index of most recent reading
int data[MAX_DATA]; // The data
};
/*** Function Declarations ***/
void empty(circ_buf*);
bool is_empty(circ_buf*);
bool is_full(circ_buf*);
void read(circ_buf*, int);
int overwrite(circ_buf*);
#endif // __CIRC_BUF_H__
circ_buf.cpp:
#include "circ_buf.h"
/*** Function Definitions ***/
// Empty the buffer
void empty(circ_buf* cb) {
cb->s = 0; cb->e = 0;
}
// Is the buffer empty?
bool is_empty(circ_buf* cb) {
// By common convention, if the start index is equal to the end
// index, our buffer is considered empty.
return cb->s == cb->e;
}
// Is the buffer full?
bool is_full(circ_buf* cb) {
// By common convention, if the start index is one greater than
// the end index, our buffer is considered full.
// REMEMBER: we still need to account for wrapping around!
return cb->s == ((cb->e + 1) % MAX_DATA);
}
// Read data into the buffer
void read(circ_buf* cb, int k) {
int i = cb->e;
cb->data[i] = k;
cb->e = (i + 1) % MAX_DATA;
}
// Overwrite data in the buffer
int overwrite(circ_buf* cb) {
int i = cb->s;
int k = cb->data[i];
cb->s = (i + 1) % MAX_DATA;
}
circ_buf_test.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "circ_buf.h"
int main(int argc, char** argv) {
// Our data source
std::string file = "million_numbers.txt";
std::fstream in(file, std::ios_base::in);
// The buffer
circ_buf buffer = { .s = 0, .e = 0, .data = {} };
for (int i = 0; i < MAX_DATA; ++i) {
int k = 0; in >> k; // Get next int from in
read(&buffer, k);
}
for (int i = 0; i < MAX_DATA; ++i)
std::cout << overwrite(&buffer) << std::endl;
}
The main issue I'm having is getting the buffer to write integers to its array. When I compile and run the main program (circ_buf_test), it just prints the same number 25 times, instead of what I expect it to print (the numbers 1 through 25 - "million_numbers.txt" is literally just the numbers 1 through 1000000). The number is 2292656, in case this may be important.
Does anyone have an idea about what might be going wrong here?
Your function overwrite(circ_buf* cb) returns nothing (there are no return in it's body). So the code for printing of values can print anything (see "undefined behavior"):
for (int i = 0; i < MAX_DATA; ++i)
std::cout << overwrite(&buffer) << std::endl;
I expect you can find the reason of this "main issue" in the compilation log (see lines started with "Warning"). You can fix it this way:
int overwrite(circ_buf* cb) {
int i = cb->s;
int k = cb->data[i];
cb->s = (i + 1) % MAX_DATA;
return k;
}
I wanted a heap allocated buffer common to a class (to use as a scratchpad during computations). At some point I may free and then reallocate the buffer if it is not large enough. I wanted the buffer to exist without having to call a "myclass::initialize();" in main(); I came up with the following code that compiles and works well for my purpose.
My questions are: Why does this code compile correctly? Why is malloc() allowed to be outside of main() or any other function? Is the compiler interpreting this somehow and removing the malloc?
Code compiled on linux 64bit using "g++ example.cpp" and checked with valgrind
// example.cpp
#include <cstdio>
#include <cstdlib>
class myclass {
public:
static char* pbuf; // buffer
static unsigned int length; // buffer length
const static unsigned int chunk_size; // allocation chunck size
};
// set constants and allocate buffer
const unsigned int myclass::chunk_size = sizeof(long unsigned int) * 8;
unsigned int myclass::length = chunk_size; // start with smallest chunk
char* myclass::pbuf = (char*)malloc(sizeof(char)*myclass::length);
int main() {
// write to buffer (0 to 63 on 64bit machine)
for (int i = 0; i < myclass::length; i++) {
*(myclass::pbuf+i) = i;
}
// read from buffer (print the numbers 0 to 63)
for (int i = 0; i < myclass::length; i++) {
printf("%d\n", *(myclass::pbuf+i));
}
free(myclass::pbuf); // last line of program
}
Thanks for the answers. Sound like this is more common than I thought. "Functions calls are allowed in static initializers". This leads me to a slightly modified version catching a possible malloc error:
#include <cstdio>
#include <cstdlib>
class myclass {
public:
static char* pbuf; // buffer
static unsigned int length; // buffer length
const static unsigned int chunk_size; // allocation chunck size
static void* malloc_buf(unsigned int);
};
// set constants and allocate buffer
const unsigned int myclass::chunk_size = sizeof(long unsigned int) * 8;
unsigned int myclass::length = chunk_size; // start with smallest chunk
//char* myclass::pbuf = (char*)malloc(sizeof(char)*myclass::length);
char* myclass::pbuf = (char*)myclass::malloc_buf(sizeof(char)*myclass::length);
void* myclass::malloc_buf(unsigned int N) {
void* buf = malloc(N);
if (!buf) exit(EXIT_FAILURE);
return buf;
}
int main() {
// write to buffer (0 to 63 on 64bit machine)
for (int i = 0; i < myclass::length; i++) {
*(myclass::pbuf+i) = i;
}
// read from buffer (print the numbers 0 to 63)
for (int i = 0; i < myclass::length; i++) {
printf("%d\n", *(myclass::pbuf+i));
}
free(myclass::pbuf); // last line of program
}
It's just doing static initialization (initialization before main is called). Static initializers are allowed to call functions.
main() is just another function - which is why it has such specific requirements placed on it to allow it to be called properly.
Other things can and do happen before it gets called. Static initialization among them.
The class corresponding to this crash is:
#ifndef IMAGE_DATA_
#define IMAGE_DATA_
#include <stdexcept>
template <typename data_type>
class ImageData
{
public:
ImageData(unsigned long width, unsigned long height);
~ImageData();
data_type **&get_data();
unsigned long int get_width() const
{
return _m_Width;
}
unsigned long int get_height() const
{
return _m_Height;
}
protected:
ImageData(ImageData ©);
ImageData& operator= (ImageData ©);
private:
data_type **_m_rData;
unsigned long _m_Width;
unsigned long _m_Height;
};
template <typename data_type>
ImageData<data_type>::ImageData(unsigned long width, unsigned long height) :
_m_rData(NULL),
_m_Width(width),
_m_Height(height)
{
if (width == 0 || height == 0)
throw std::runtime_error("Invalid width or height");
try {
_m_rData = new data_type*[_m_Height]();
for (unsigned long int i = 0; i < _m_Height; ++i) {
_m_rData[i] = NULL;
}
for (unsigned long int i = 0; i < _m_Height; ++i) {
_m_rData[i] = new data_type[_m_Width];
}
}
catch (std::bad_alloc e) {
throw std::runtime_error("Failure to create space for Image");
}
}
template <typename data_type>
ImageData<data_type>::~ImageData()
{
for (unsigned long i = 0; i < _m_Height; ++i) {
delete [] _m_rData[i];
_m_rData[i] = NULL;
}
delete [] _m_rData;
_m_rData = NULL;
}
template <typename data_type>
data_type **&ImageData<data_type>::get_data()
{
return _m_rData;
}
#endif
And it is used in the following manner:
PNGFileReader::PNGFileReader(const std::string &path) :
_m_Image(NULL),
_m_pPNG(NULL),
_m_pPNGInfo(NULL)
{
...
/*
* Read Image in all at once into users data
*/
_m_Image = new ImageData<unsigned char>(width, height);
png_read_image(_m_pPNG, _m_Image->get_data());
png_read_end(_m_pPNG, NULL);
fclose(_m_CFilePointer);
_m_CFilePointer = NULL;
}
PNGFileReader::~PNGFileReader()
{
if (_m_CFilePointer) {
fclose(_m_CFilePointer);
}
png_destroy_read_struct(&_m_pPNG, &_m_pPNGInfo, NULL);
delete _m_Image;
}
When stepping through with the debugger the _m_rData in the ImageData class is the same pointer as when I used new on it. I have even tried to wrap the delete statement inside ImageData destructor with if == NULL statments. However, I still get a sigabrt while running my code. The stack trace from gdb is:
0 __GI_raise raise.c 64 0x3512a36285
1 __GI_abort abort.c 91 0x3512a37b9b
2 __libc_message libc_fatal.c 198 0x3512a77a7e
3 malloc_printerr malloc.c 5021 0x3512a7dda6
4 _int_free malloc.c 3942 0x3512a7f08e
5 ImageData<unsigned char>::~ImageData imagedata.h 57 0x40236d
6 PNGFileReader::~PNGFileReader pngfilereader.cpp 59 0x401ed3
7 main main.cpp 8 0x40246a
UPDATE
For anyone that is curios the following now works. Apparently it is an issue with how png_alligns its data. This forces you I guess to use libpng's method calls which internally use free and malloc, not new. This is essentially the same things as calling free(data) where data was created with data = new type[N]. The code below depicts how to correctly use libpng.
#ifndef PNG_FILE_READER_H_
#define PNG_FILE_READER_H_
#include "imagedata.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <iostream>
#include <vector>
#include <string>
template <typename data_type>
class ImageData;
class PNGFileReader
{
public:
// Ctor and Dtor
PNGFileReader(const std::string &path);
~PNGFileReader();
// For testing purposes
friend std::ostream &operator<< (std::ostream &out,
PNGFileReader *object)
{
for (unsigned long i = 0; i < object->get_image_height(); ++i) {
for (unsigned long j = 0; j < object->get_image_width(); ++j) {
png_byte c = object->_m_ImageData[i][j];
out << c;
}
}
return out;
}
// Getters
long unsigned int get_image_width() const;
long unsigned int get_image_height() const;
private:
// Helper functions:
bool _create_png_structs();
// Member variables:
FILE *_m_CFilePointer;
unsigned long int _m_ImageWidth;
unsigned long int _m_ImageHeight;
png_bytepp _m_ImageData;
png_structp _m_pPNG;
png_infop _m_pPNGInfo;
// Enums
enum PNGBOOL {NOT_PNG, PNG};
enum PNGERRORS {ERROR, SUCCESS};
};
#endif /* PNG_FILE_READER_H_ */
#include "pngfilereader.h"
#include "filereader.h"
#include <stdexcept>
PNGFileReader::PNGFileReader(const std::string &path) :
_m_ImageData(NULL),
_m_pPNG(NULL),
_m_pPNGInfo(NULL)
{
/*
* Check if first 8 bytes are the correct PNG header
*/
enum {BYTES_TO_READ = 8};
unsigned char sig[BYTES_TO_READ];
FileReader(path, sig, BYTES_TO_READ);
bool not_png = png_sig_cmp(sig, 0, BYTES_TO_READ);
if (not_png) {
throw std::runtime_error("Your file is not of PNG format");
}
/*
* Create the png structs using a FILE *. libpng requires
* this type and will not take a C++ stream
*/
_m_CFilePointer = fopen(path.c_str(), "rb");
if (!_m_CFilePointer) {
throw std::runtime_error("Failure to open PNG file");
}
if (!_create_png_structs()) {
throw std::runtime_error("Failure to create PNG structs");
}
/*
* Initialize PNG io and read data into PNG structs
*/
png_init_io(_m_pPNG, _m_CFilePointer);
png_read_info(_m_pPNG, _m_pPNGInfo);
_m_ImageHeight = png_get_image_height(_m_pPNG, _m_pPNGInfo);
_m_ImageWidth = png_get_rowbytes(_m_pPNG, _m_pPNGInfo);
/*
* Create sufficient PNG Space and Read Image in all at
* once into users data. Note that you have to use png's
* types to prevent sigabrt (6) while freeing memory.
*/
_m_ImageData = (png_bytepp)png_malloc(_m_pPNG,
sizeof(png_bytep)*_m_ImageHeight);
if (_m_ImageData == NULL) {
throw std::runtime_error("Memory allocation failure");
}
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
_m_ImageData[i] = NULL;
}
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
_m_ImageData[i] = (png_bytep)png_malloc(_m_pPNG,
sizeof(png_byte)*_m_ImageWidth);
if (_m_ImageData[i] == NULL) {
throw std::runtime_error("Memory allocation failure.");
}
}
png_read_image(_m_pPNG, _m_ImageData);
png_read_end(_m_pPNG, NULL);
fclose(_m_CFilePointer);
_m_CFilePointer = NULL;
}
PNGFileReader::~PNGFileReader()
{
if (_m_CFilePointer) {
fclose(_m_CFilePointer);
}
/*
* Free all resources (-1)
*/
png_free_data(_m_pPNG, _m_pPNGInfo, PNG_FREE_ALL, -1);
for (unsigned long int i = 0; i < _m_ImageHeight; ++i) {
png_free(_m_pPNG, _m_ImageData[i]);
}
free(_m_ImageData);
png_destroy_read_struct(&_m_pPNG, &_m_pPNGInfo, NULL);
}
// Getters
long unsigned int PNGFileReader::get_image_width() const
{
return _m_ImageWidth;
}
long unsigned int PNGFileReader::get_image_height() const
{
return _m_ImageHeight;
}
// Private helper functions
bool PNGFileReader::_create_png_structs()
{
/*
* Create the pointer to main libpng struct, as well as
* two info structs to maintain information after, and
* prior to all operations on png m_Data. Only necessary
* to release resource after function succeeds.
*/
_m_pPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
NULL, NULL);
if (!_m_pPNG){
return PNGFileReader::ERROR;
}
_m_pPNGInfo = png_create_info_struct(_m_pPNG);
if (!_m_pPNGInfo) {
return PNGFileReader::ERROR;
}
return PNGFileReader::SUCCESS;
}
If you need a really 2D array to pass to a library, but want to have the flexibility of a jagged array, what you do is
Allocate the first level pointer block as usual
Instead of allocating m separate rows of n cells (one for each pointer in the first level block) you allocate a single set of n*m cells and then set the first level pointers to point at every nth location. This way the main allocation is sized and laid out in memory just as a 2D array, but you can still use the two-pointer-dereference [][] syntax to get to the cells.
Pass the start of the second level allocation to the library.
This works because there are strict requirements on who multidimensional arrays are laid out in memory (i.e. the must be contiguous at every level of interpretation).