C++ - Delete std::string*; heap corruption - c++

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.

Related

Exception thrown at 0x0037A5C2 project.exe: 0xC0000005: Access violation writing location 0xDDDDDDDD at the end of the program

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.

C++ error on delete[] after iterating through pointer

Environment: Windows 7 pro x64, Microsoft Visual Studio 2015 Enterprise, Version 14.0.25424.00 Update 3
int testFunction()
{
std::string _orig = "[188 80% (1/2)O:152]";
std::string _orig2 = "[999 99% (1/1)O:999]";
char *orig = NULL;
char *orig2 = NULL;
orig = new char[_orig.length() + 1];
strcpy(orig, _orig.c_str());
orig2 = new char[_orig2.length() + 1];
strcpy(orig2, _orig2.c_str());
*orig++;
*orig2++;
int a = atoi(orig);
int b = atoi(orig2);
delete[] orig;
delete[] orig2;
return 0;
}
Running the above code crashes with the "_CrtIsValidHeapPointer(block)" error.
If I don't iterate (*orig++ and *orig2++), then no issues.
So my question is, how can I iterate through the pointers and then when I'm done doing what I need to do with them, delete[] them correctly?
You did not delete the pointers you allocated!
delete must be called on the original memory address returned by new. Since you did orig++, you cant delete the address being pointed at!
Iterating can be done with an index, and using array subscription to dereference:
orig[i] = 'a';
Which is the same as doing this:
*(orig+i) = 'a';
Or you can get another pointer onto the same data, and modify this one.
char* pOrig = orig;
++pOrig;
Why did you write
*orig++; // why dereferencing?
Just ++ by itself would do the iteration.
Avoid to use raw pointers. Your code can be simpler:
std::string orig = "[188 80% (1/2)O:152]";
std::string orig2 = "[999 99% (1/1)O:999]";
int a = atoi(orig.c_str() + 1);
int b = atoi(orig2.c_str() + 1);
Your mistake is that you try to delete the shifted pointers instead of the original pointers. As the result heap manager gets wrong allocated block information usually put before the allocated pointer and you got heap corruption.
how can I iterate through the pointers and then when I'm done doing what I need to do with them, delete[] them correctly?
Create a copy of the pointer:
char* orig = new char[size];
char* i = orig;
*i++ = 'a';
delete orig;
A perhaps more common idiom is to dereference a temporary:
for(int i = 0; i < size - 1; i++)
orig[i] = 'a';
I would love to [use std::string], but I need to use atoi(), which won't work on std::string
You are mistaken. atoi works with std::string just fine. Simply use std::string::c_str() just like you did with strcpy. There is absolutely no reason to allocate a block of memory with new.
int testFunction()
{
std::string _orig = "[188 80% (1/2)O:152]";
int a = 0;
for (std::string::iterator it = _orig.begin(); it != _orig.end(); ++it)
{
if (isdigit((char)*it))
a = (atoi(it._Ptr));
}
return 0;
}
I got it. Thanks for everyone who helped me come to this conclusion. Staying with std::string was in fact the best approach.

Asisgn LPCWSTR array from std::wstring

I am creating a dynamic array of LPCWSTR, and want to assign values at run time.
I have following code :
cin>>count
LPCWSTR * lpwcstrArray = new LPCWSTR[count]();
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
wstring tempWString = L"somerandomstuff";
lpwcstrArray[i] = reinterpret_cast<LPSWSTR>tempWString.c_str();
}
Now if i access lpwcstrArray - all the indexs point at data of last string that was assigned.
I know this is not correct way to assign values, but i do not know the correct way.
wstring tempWString is created and destroyed with each iteration of the loop.
You have dangling pointers in your lpwcstrArray and are experiencing undefined behaviour when you access one of them.
You need to allocate the space yourself or use a std::wstring as the array type instead of a LPCWSTR.
You are storing pointers that point at the internals of temporary std::wstring objects. When those objects are destroyed on each loop iteration, your array is left with danging pointers. You need to dynamically allocate the individual strings instead, eg:
std::cin >> count
LPWSTR *lpwstrArray = new LPWSTR[count];
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
std::wstring tempWString = L"somerandomstuff";
LPWSTR str = new WCHAR[tempWString.length()+1];
const wchar_t *p = tempWString.c_str();
std::copy(p, p+tempWString.length(), str);
lpwstrArray[i] = str;
}
// use lpwstrArray as needed...
// don't forget to free the memory when you are done using it...
for (int i = 0; i < count; i++)
delete[] lpwstrArray[i];
delete[] lpwstrArray;
Depending on what you are really trying to accomplish, something more like the following would be safer, at least if you just need read-only access to the strings (which you likely do, as the C in LPCWSTR stands for const, so the user of the array is not going to be modifying them):
std::cin >> count
std::vector<std::wstring> wstrArray(count);
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
wstrArray[i] = L"somerandomstuff";
}
std::vector<LPWSTR> lpwstrArray(count);
for (int i = 0; i < count; i++)
lpwstrArray[i] = const_cast<wchar_t*>(wstrArray[i].c_str());
// use lpwstrArray as needed. if you need to pass it where an
// LPWSTR* is expected, you can use &lpwstrArray[0] for that...
// lpwstrArray and wstrArray will be freed automatically
// when they go out of scope...
Try the approach
std::wstring ws(_T("Hello"));
LPCTSTR lps= (LPCTSTR)(ws.c_str());
TRACE(lps);
Notes:
You should not use the W types directly (ex: LPCWSTR). Use the T types instead (ex: LPCTSTR). Why? Because they will automatically translate to the version they should be (LPCSTR for non-Unicode / ASCII; LPCWSTR for Unicode), depending on your project.
For the same reason you should surround your strings with _T() or precede them with an L.
Try to dive deep using "Go To Definition" successively beginning on LPCTSTR
See also the _tcscpy_s function documentation

The variable timeOld is being used without being initialized in c++

char* timeNew = _com_util::ConvertBSTRToString(cpi->getTime());
if(timeFirst == true)
{
strcpy(timeOld,timeNew);
timeFirst = false;
}
how can I initiliase timeold if I dont know what the size of character array returned by cpi->getTime is?
Allocate memory for it based on length of timeNew:
delete[] timeOld;
timeOld = new char[strlen(timeNew) + 1];
or you could make timeOld a std::string and let it manage memory for you:
std::string timeOld;
timeOld = timeNew; // If timeNew is dynamically allocated you must still
// delete[] it when no longer required, as timeOld
// takes a copy of timeNew, not ownership of timeNew.
You can access the const char* using std::string::c_str() if really required.
Use strings where possible:
char *t= _com_util::ConvertBSTRToString(cpi->getTime());
std::string timeNew(t);
delete[] t;
if(timeFirst == true)
{
timeOld=timeNew;
timeFirst = false;
}
if you don't have to manage the memory returned by teh function simply:
std::string timeNew(_com_util::ConvertBSTRToString(cpi->getTime()));
if(timeFirst == true)
{
timeOld=timeNew;
timeFirst = false;
}
If you have to use ConvertBSTRToString then use boost::scoped_array<char> or boost::shared_array<char> to ensure you get clean-up.
boost::shared_array<char> time;
time.reset( _com_util::ConvertBSTRtoString( cpi->getTime() );
automatically reallocates. No calls to delete or delete[] necessary.

glibc detected - double free or corruption

I get the following error messages when I submit the code (pasted below) to an online gcc compiler.
* glibc detected /run-1326102706-2046832693/solution: double free or corruption (!prev): 0x091901a8 ** =======
The code is as follows:
# include <iostream>
# include <string>
# include <list>
# include <cstring>
using namespace std;
int main()
{
int test_cases, i, score, str_len;
string str;
char first_char, current_char;
list <int> strlist;
list <int> :: iterator it;
cin>>test_cases;
char *cstr[test_cases]; //Creating an array of cstr pointers (test_cases number of pointers)
while(test_cases > 0)
{
cin>>str;
first_char = str.at(0);
str_len = str.length();
score = str_len;
strlist.clear();
cstr[test_cases-1] = new char[str_len];
strcpy(cstr[test_cases-1],str.c_str()); //copying the input str into cstr. This is done to minimize the complexity of std::string's at function.
for(i=1;i<str_len; i++)
{
current_char = *(cstr[test_cases-1]+i);
if (current_char == first_char)
{
score++; strlist.push_front(1);
it = strlist.begin();
if (it != strlist.end())
it++;
}
while (!strlist.empty() && it != strlist.end())
{
if (current_char == *(cstr[test_cases-1] + *(it)))
{
(*it)++;it++;score++;
}
else
it = strlist.erase(it);
}
if (!strlist.empty())
it = strlist.begin();
}
cout<<score<<endl;
delete(cstr[test_cases-1]);
test_cases--;
}
return 0;
}
As mentioned in the code itself, I initially used std::string, but found that the std::string.at function was quite slow (esepcially since this problem has really large input strings). So I decided to store the string input in a character array, so that direct indexing to a particular position would be possible.
Appreciate any help.
There are two problems that I can see:
cstr[test_cases-1] = new char[str_len]; // Not allocating space for terminating NULL.
delete(cstr[test_cases-1]); // Incorrect delete, should be delete[]
// As already pointed out by mooware
Change these two lines to:
cstr[test_cases-1] = new char[str_len + 1];
delete[] cstr[test_cases-1];
You are using array-new ("new char[str_len]") to allocate the strings, but scalar-delete ("delete(cstr[test_cases-1])") to delete them. You should always match the new- and delete-operators, so when you use array-new, also use array-delete ("delete[] cstr[test_cases-1]").
You have two bugs. One is here:
cstr[test_cases-1] = new char[str_len];
strcpy(cstr[test_cases-1],str.c_str());
You allocate one byte too few. That should be new char[str_len+1] since strcpy copies the terminator.
The other is here:
delete(cstr[test_cases-1]);
You cannot allocate with new[] and deallocate with delete. If you allocate with new[], you must deallocate with delete[].