I'm trying to write a class in c++ that creates a dynamic array and I'm encountering this problem
malloc: Incorrect checksum for freed object 0x7f9ff3c05aa8: probably modified after being freed.
Corrupt value: 0x2000000000000
I implemented three constructors (default, parametrized and copy) and I think this is the one causing problem because the code breaks here
CTable::CTable(string sName, int iTableLen)
{
s_name = sName;
cout<<"parametr: "<<s_name<<endl;
c_table = new int[iTableLen];
i_table_lenghth=iTableLen;
}
I also have to write a method changing the size of the array and returning true in case of the success and false in case of the failure. Maybe this method is causing the problem so this is how I implemented it.
bool CTable :: bSetNewSize(int iTableLen)
{
int size;
if(iTableLen < 0)
return false;
else if(iTableLen>=i_table_length)
size = i_table_length;
if(iTableLen < i_table_length)
size = iTableLen;
int *cTable;
cTable = new int[iTableLen];
for (int ii = 0; ii < size; ii++)
{
cTable[ii] = c_table[ii];
}
delete [] c_table;
c_table = cTable;
return true;
}
edit: The problem wasn't in any of those parts of the code. The method that was supposed to clone the object was causing the error. It happened because I allocated the object statically instead of dynamically. Here is the fixed method:
CTable* CTable::pcClone()
{
CTable *obj_clone;
obj_clone = new CTable(*this);
return obj_clone;
}
The problem is that you deleted c_table in bSetNewSize() and didn't set a new value to it, but used it in a later call. I Think you meant to put a c_table = cTable; to the end of bSetNewSize() function, as 500 - Internal Server Erro commented.
Also it is faster if you take the string parameter as a const string& to the constructor.
Edit: are you sure abaut
if(iTableLen >= 0)
return false;
This means that you actually resize only if iTableLen is negative.
Didn't you mean
if(iTableLen < 0)
return false;
Related
I have encountered this runtime exception at the very end of the program by simply creating an instance of the specified class, so I presume the issue lies with either the constructor, copy constructor, copy assignment operator or destructor. I have read up on and followed the rule of three to the extent of my limited cpp knowledge.
Source.cpp
#include "Header.h"
#include <iostream>
using namespace std;
int main() {
string command = "CREATE TABLE table_name IF NOT EXISTS ((column_1_name,type,default_value), (column_2_name,type,default_value))";
string columns[20] = { "column_1_name,type,default_value", "column_1_name,type,default_value" };
string commandData[9] = { "table_name", "IF NOT EXISTS" };
CommCREATETABLE comm(command, columns, commandData, 2, 2);
}
Relevant code from Header.h
class CommCREATETABLE {
string fullCommand = "";
string* columns = nullptr;
string* commandData = nullptr;
string tableName = "";
int nrOfColumns = 0;
int nrOfElements = 0;
bool valid = false;
Constructor:
CommCREATETABLE(string command, string* columns, string* commandData, int nrOfRows, int nrOfElements) {
this->setNrOfColumns(nrOfRows);
this->setNrOfElements(nrOfElements);
this->setCommand(command);
this->setColumns(columns);
this->setCommandData(commandData);
this->valid = checkInput(this->commandData, this->columns);
this->setTableName(commandData[0]);
}
Copy constructor, copy assignment operator, destructor:
CommCREATETABLE(const CommCREATETABLE& comm) {
this->setNrOfColumns(comm.nrOfColumns);
this->setNrOfElements(comm.nrOfElements);
this->setCommand(comm.fullCommand);
this->setColumns(comm.columns);
this->setCommandData(comm.commandData);
this->setTableName(comm.tableName);
this->valid = comm.valid;
}
~CommCREATETABLE() {
if (this->columns != nullptr) {
delete[] this->columns;
}
if (this->commandData != nullptr) {
delete[] this->commandData;
}
}
CommCREATETABLE& operator=(const CommCREATETABLE& comm) {
this->setCommand(comm.fullCommand);
this->setColumns(comm.columns);
this->setCommandData(comm.commandData);
this->setTableName(comm.tableName);
this->setNrOfColumns(comm.nrOfColumns);
this->setNrOfElements(comm.nrOfElements);
this->valid = checkInput(this->commandData, this->columns);
return *this;
}
The only setters that deal with dynamic memory allocation are the following:
void setColumns(const string* columns) {
if (this->nrOfColumns >= 0) {
this->columns = new string[this->nrOfColumns];
memcpy(this->columns, columns, this->nrOfColumns * sizeof(string));
}
else throw EmptyCommandException();
}
void setCommandData(const string* commandData) {
if (this->nrOfElements >= 0) {
this->commandData = new string[this->nrOfElements];
memcpy(this->commandData, commandData, this->nrOfElements * sizeof(string));
}
else throw EmptyCommandException();
}
At a quick glance I would say the issue is in your setColumns and setCommandData functions. (I might of course be wrong, I did not try to run the code you presented nor the changes I made -- so there might also be a typo somewhere.)
There you use memcpy to copy the strings into your class. However, internally a C++ string holds a pointer to the actual string, so using memcpy actually only copies that pointer. As a result, once the original string gets deleted, the pointer you copied into your class is no longer valid (as the memory has already been freed). As a result, once your class also gets deleted it attempts to delete memory that has already been freed. That is probably where your error comes from.
In fact, if you added lines to your program where you tried to manipulate your class (after the original input strings have already been deleted), the problem would present itself even sooner, as you would be accessing memory that has already been freed. This would lead to undefined behaviour, which typically ends with a crash at some point.
A quick fix would be to change the way you copy the data, by using = for each string (in that way copying the actual strings into a new location in memory, rather than copying the pointer).
void setColumns(const string* columns) {
if (this->nrOfColumns > 0) { // Creating an array of size 0 is also not a good idea.
this->columns = new string[this->nrOfColumns];
for (int i = 0; i < nrOfColumns; i++) { // You don't need this everywhere.
this->columns[i] = columns[i];
// I don't think naming things the exact same way is good practice.
}
}
else throw EmptyCommandException();
}
void setCommandData(const string* commandData) {
if (this->nrOfElements > 0) { // Creating an array of size 0 is also not a good idea.
this->commandData = new string[this->nrOfElements];
for (int i = 0; i < nrOfElements; i++) { // You don't need this everywhere.
this->commandData[i] = commandData[i];
// I don't think naming things the exact same way is good practice.
}
}
else throw EmptyCommandException();
}
Alternatively, if you want to avoid making copies you should look into move, but I would suggest against this for the time being, if you are still learning. You'll get there soon enough.
I have struggled with it for a while but I really can't get it, I am just getting segfaults. I am trying to copy a class, the function I am writing to copy is also below. Crossed out are combinations that I have tried in vain, it's time to call for help
class Scene
{ private:
int max;
int* x_row, *y_col; // maximum and min coordinates of each image
Image**image_layers;
}
void Scene::_copy(const Scene &source)
{
max = source.max;
x_row = new int[source.x_row];
y_col = new int[source.y_col];
image_layers = new Image*[source.max];
for(int i = 0; i < source.max; i++)
{
if(source.image_layers[i] != NULL)
{
//image_layers[i] = new Image(*(source.image_layers[i]));
// image_layers[i] = new Image;
//*image_layers[i] = *source.image_layers[i];
// image_layers[i] = source.image_layers[i];
}
else
{
image_layers[i] = NULL;
}
x_row[i] = source.x_row[i];
y_col[i] = source.y_col[i];
}
EDIT:
I forgot to say that this function is called as " scene(*set) "
The segfault happens here or because of this:
x_row = new int[source.x_row];
y_col = new int[source.y_col];
On the right hand side, you use the address source.x_row as an array size. This is a very large number that most likely will cause the allocation to fail.
You need to keep a member for holding the size or better yet use a std::vector<int> object instead.
Copying C arrays are done faster with memcpy. With C++ vectors, you can just assign one to the other:
x_row = source.x_row
Nothing to do with the question, but this function should be named operator=, will make using the class easier by assigning one instance to another:
Scene & Scene::operator=(const Scene &source)
{
// copy elements
...
return *this;
}
x_row = new int[source.x_row];
y_col = new int[source.y_col];
Are you sure about above code?
source.x_row is pointer
I have the following method:
void ConnectionManager::SendAll()
{
for (int t = 0; t < (int)m_Connections.size(); ++t)
{
if (m_Connections[t].socket != INVALID_SOCKET)
{
// Create the object
MessageID message;
message.set_type(MessageID::Type::MessageID_Type_PLAYERDATA);
for (int i = 0; i < (int)m_Connections.size(); ++i)
{
if (m_Connections[i].playerData.username() != google::protobuf::internal::kEmptyString)
{
auto temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
}
}
if (message.playerdata_size() > 0)
{
// Serialize to byte array
int size = message.ByteSize();
void* buffer = malloc(size);
message.SerializeToArray(buffer, size);
Send(m_Connections[t].socket, buffer, size);
}
}
}
}
Now the problem lies at the end of this method, at the line:
int size = message.ByteSize();
I know that the data is loaded correctly (or it should be at least) but the size isn't right. It should be 30 and it returns 2. I have no idea what I'm doing wrong.
The data in m_Connections is available and should be reached by pointer temp. I think that, for some reason, the data is lost from the "message" object but I don't know how to solve it.
auto temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
These lines look wrong. add_playerdata() returns a pointer. That means that the second line is just setting temp to some other pointer, not doing anything to the message which temp points at. It's more obvious if you write out the type rather than use auto:
MessageID::PlayerData* temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
Maybe you wanted to do this instead:
*temp = m_Connections[i].playerData;
However, I do not see how this bug would lead to ByteSize() being 2. It looks like ByteSize() should only be 2 if you haven't added any players to the message, but then playerdata_size() would be zero, so you wouldn't get to the serialization step at all.
I'm relatively new to C++ memory management, and I'm getting this weird error of heap corruption (plus an automatic breakpoint in Visual Studio before it). Here is the offending code:
z_world::z_world(char* name)
{
unsigned int i, skip;
char tmp;
//Load data from file
std::string* data = loadString(name);
//Base case if there is no world data
tiles = NULL;
w = 0;
h = 0;
if(data->length() > 0) {
//Set up the 'tiles' array
for(i = 0; i < data->length(); i++) {
if(data->at(i) == '\n')
h++;
if(h == 0)
w++;
}
tiles = new int[data->length()-h];
//Load Data
skip = 0;
for(i = 0; i < data->length(); i++) {
if(data->at(i) == '\n') {
skip++;
printf("\n");
continue;
}
tmp = data->at(i);
tiles[i+skip] = atoi(&tmp);
printf("%i ",tiles[i+skip]);
}
}
delete data;
}
Here's where I load in the string:
std::string* loadString(char* name)
{
ifstream in(name);
std::string* input = new string();
while(in) {
std::string line;
getline(in,line);
input->append(line);
input->append("\n");
}
in.close();
return input;
}
I get the breakpoint and error inside of "delete data;", which makes me think that "data" gets deleted somewhere before that, but I can't find where it would. For reference, this method is to create an object that contains world data for a game in the form of a virtual 2D integer array (for the ID's of the tiles).
Youre problem is probably here:
tiles[i+skip] = atoi(&tmp);
Problem 1:
It should be -skip
tiles[i - skip] =
Problem 2:
The atoi() command is being used incorrectly (tmp does not contain a string). But also I don't think atoi() is the appropriate method. I think what you are looking for is simple assignment. The conversion from char to int is automatic:
tiles[i - skip] = tmp;
Problem 3:
You are not using objects correctly. In this situation there is no need to generate dynamic objects and create a mess with dynamic memory management. It would be simpler to just to create automatic objects and pass those back normally:
std::string* loadString(char* name)
// ^ Don't do this.
std::string loadString(std::string const& name)
// ^^^^^^^ return a string by value.
// The compiler will handle memory management very well.
In general you should not be passing pointers around. In the few situations where you do need pointers they should be held within a smart pointer object or containers (for multiple objects) so that their lifespan is correctly controlled.
atoi(&tmp);
atoi expects a pointer to a null terminated string - not a pointer to a char
There's no need to dynamically allocate the string in the code you've shown. Change the loadString function to
std::string loadString(char* name)
{
ifstream in(name);
std::string input;
// ...
return input;
}
In the caller
std::string data = loadString( name );
Now there's no need to delete the string after you're done.
Instead of
int *tiles = NULL;
tiles = new int[data->length()-h];
use
std::vector<int> tiles;
tiles.resize(data.length() - h);
Also, if you do need to dynamically allocate objects you should be using smart pointers (std::unique_ptr and std::shared_ptr) instead of raw pointers.
There is a bug in
tiles[i+skip] = atoi(&tmp);
For example, for a string
Hello\n
World\n
and for the loop iteration at the point of i == 10, skip is already 1 (since we have encountered the first \n before) and you are writing to tiles[10 + 1], but tiles only has been allocated as an array with 10 elements.
May be the variable input is local to this function. So after returning from this the memory is freed. So, calling later delete on this string tries to free already freed memory.
My program works but my professor says that my code is incorrect but stated that he will get to why in the fall term... What is he talking about?
perhaps something is improper? Even if you are incorrect I would appreciate picking your brain :)
void CResizableArray::SetSize( int intNewSize )
{
int intIndex = 0;
if( intNewSize < 0 ) intNewSize = 0;
if( intNewSize > intMAXIMUM_ARRAY_SIZE )
{
intNewSize = intMAXIMUM_ARRAY_SIZE;
}
//////////////////////////////////////
// ---> HUGE BUG HERE <--- //
// Code works but is WRONG //
// WHY IS THIS HELP ME FIND THE BUG //
//////////////////////////////////////
m_intArraySize = intNewSize;
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
}
Presumably before this line
m_paintValues = new int [m_intArraySize];
m_paintValues pointed to another array. That array has now been leaked -- you don't have a pointer to it, so it can never be freed. That memory can therefore never be reused. Write a program that does a lot of this, and it'll run out of memory before running very long.
When you're through with a block of memory, you need to free it. Here, the proper thing to do might look something like
delete[] m_paintValues;
m_paintValues = new int [m_intArraySize];
There are more issues, though. First of all, you can never use delete[] unless you know that m_paintValues definitely points to an array; you could ensure that in the constructor. More troubling is that fact that when you set a new size, any data previously in m_paintValues is discarded -- don't you want to copy the old values into the new array? Doing so would mean using a temporary variable to hold the new array when first allocated, copying the data, and then assigning the new array to the member variable.
He may mean that since it is a resize you should keep the old contents of the array and transfer them over to the new array, in your snippet you just throw away the old content creating a new empty array.
so instead of
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
do
int* newBiggerArray = new int[m_intArraySize];
for (intIndex = 0; intIndex < m_intArraySize; ++intSize)
{
if ( intIndex < oldMaxSize )
{
newBiggerArray[intIndex] = m_paintValues[intIndex];
}
else
{
newBiggerArray[intIndex] = 0;
}
}
delete [] m_paintValues;
m_paintValues = newBiggerArray;
I will leave the part to handle a resize to a smaller value than previous for you to figure out.