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.
Related
How do I delete the memory that have been allocated for array models, names? I tried every method but it always crashes when I run it.
int main()
{
vector<Person*> people;
const int PERSON_SZ = 4;
char * names[] = {"Jim", "Fred", "Harry", "Linda"};
int ages[] = { 23, 35, 52, 59 };
for (int i = 0; i < PERSON_SZ; i++)
{
Person * temp = new Person(names[i], ages[i]);
people.push_back(temp);
}
// A vector of Car pointers
vector<Car*> cars;
const int CAR_SZ = 3;
char * models[] = { "Festiva", "Ferrarri", "Prius" };
srand(time(0));
for (int i = 0; i < CAR_SZ; i++)
{
Car * temp = new Car(models[i]);
temp->set_driver(people[rand() % (people.size())]);
temp->set_owner(people[rand() % (people.size())]);
cars.push_back(temp);
}
for (int p = 0; p < people.size(); p++)
{
people[p]->increment_age();
}
for (int c = 0; c < cars.size(); c++)
{
cars[c]->print();
}
delete [] names;
for ( int r = 0; r < CAR_SZ; ++r )
{
delete [] models[r];
}
return 0;
}
You didn't allocate models and names using new, so you cannot delete them.
Both arrays are allocated on the stack and are automatically deleted, when the function returns.
The contents of the (string) arrays (i.e. the strings itselves) are stored in the global data segment and cannot be freed at all. This would also be dangerous because the compiler might use the same string constant at different places in the program.
The models array and the names array are both statically allocated. You didn't use new to create them, you don't need to delete them. You should, however, change their types as follows:
const char * names[] = {"Jim", "Fred", "Harry", "Linda"};
const char * models[] = { "Festiva", "Ferrarri", "Prius" };
because they are pointers to string literals, which are read-only.
The variable names and models are not dynamically allocated, and neither is the data in those arrays. So no need to free them or their contents.
The two vector contains data that need to be free'd on the other hand.
You did not allocate names, and models. You don't need to free or delete them from memory.
As others have answered, this is neither required nor legal...
delete [] names;
Since you didn't new names.
Neither is this...
for ( int r = 0; r < CAR_SZ; ++r )
{
delete [] models[r];
}
Since you didn't new any of the models.
But you do still have some memory leaks!
For each car instance you newed and stored in the cars vector, you need to call delete. Here is one way:
for (std::vector<Car*>::iterator car = cars.begin(), done = cars.end(); car != done; ++car)
{
delete *car;
}
Note that the * there dereferences the iterator, yielding the raw pointer you newed.
The problem with this approach is that it leaves you with a vector full of dangling pointers. You could either reset them in the loop or clear() the vector after the loop has terminated. Perhaps a better approach would be:
while (not cars.empty())
{
delete cars.back();
cars.pop_back();
}
Which deletes each car, then removes its pointer from the vector.
Similarly for each person you newed and stored in people:
while (not people.empty())
{
delete people.back();
people.pop_back();
}
As a rule of thumb, there should be one delete for every new and one delete[] for every new ... []. But you'll do well to learn about smart pointers.
names and models are not pointing heap-allocated area. Don't delete it.
Your code is incomplete. It does not compile. Please enable all warnings and debugging for your compiler, e.g. with g++ -Wall -g if using GCC and improve your code till you get no warning
char * names[] = {"Jim", "Fred", "Harry", "Linda"};
delete [] names;
This is incorrect. You can only delete something that you obtained thru new.
I got following problem.
I want to resize my array of pointers on structure ( car ) . I got following code.
Class Car{
...
char * Owner_Name;
char * carID
};
Class Register {
...
int CarCNT;
int car_num_default;
Car ** dataBase;
Register ()
{ //constructor
car_num_default = 5 ; //for example;
dataBase = new Car * [car_num_default];
}
};
Now when I add 6th. car I need to resize my array of pointer to car. How should I do that without create any memory leak ? Or memory error ? :)
I tried folowing code but it makes some memory leaks..
void Register:: Add ( const char * carID, const char * owner)
{
if (carCNT == car_num_default) // now it's full array need resize
{
car ** tmp = new car * [carCNT]; //create new array ;
for(int i = 0 ; i < carCNT;i++)
tmp[i] = new car(databaze[i]->car_ID,databaze[i]->owner_name);
free(database); //free memory and than alloc new bigger
database = new car * [car_num_default * 5];
for(int i = 0; i < carCNT; i++)
data_by_RZ[i] = tmp [i];
free(tmp);
car_num_def = car_num_def * 5;
}
databaze[carCNT] = new car(....);
carCNT++;
}
Thanks for any help!
Here's a list of obvious bugs in your memory management:
You allocate with new[] but deallocate with free. See Is there any danger in calling free() or delete instead of delete[]?
On reallocation, you create new car instances and copy the data of existing car objects instead of copying the pointers to the existing car obejcts. This causes all the previous cars objects to leak. This bug is only when copying database to the tmp table. The copy from tmp to the new database would be correct if tmp contained the pointers to the old car objects.
You needlessly create a tmp array and copy the database to it. You should simply create the new, bigger array, copy, deallocate the old and then set the database pointer. This bug does not cause a leak, but is entirely pointless and does waste memory bandwidth.*
* Here's the code as requested:
Car** tmp = new Car*[car_num_default * 5];
for(int i = 0; i < CarCNT; i++)
tmp[i] = database[i];
delete[] database;
database = tmp;
Remember that functions destroy their parameters after the function finishes its execution.
Since you are passing carID and owner as pointers and inserting them into the array, the values are destructed after execution and the pointers placed inside the array become invalid causing the leak. Use pointers only when you want to make a change to the pointer itself but never store it as it will soon be destructed.
It seems that you are using pointers in places you shouldnt or where you don't have to. Here is a simpler version of your code that does the same:
Class Car{
...
char Owner_Name;
char carID;
};
Class Register {
...
int CarCNT;
int car_num_default;
Car * dataBase;
Register ()
{ //constructor
car_num_default = 5 ; //for example;
dataBase = new Car [car_num_default];
}
};
void Register:: Add ( const char carID, const char owner)
{
if (CarCNT == car_num_default) // now it's full array need resize
{
car * tmp = new car [carCNT]; //create new array ;
for(int i = 0 ; i < carCNT;i++)
tmp[i] = new car(dataBase[i].car_ID,dataBase[i].owner_name);
free(dataBase); //free memory and than alloc new bigger
dataBase = new car [car_num_default * 5];
for(int i = 0; i < carCNT; i++)
data_by_RZ[i] = tmp [i];
free(tmp);
car_num_def = car_num_def * 5;
}
Car x(...);
dataBase[CarCNT] = x;
carCNT++;
}
Finally, I have four points to make:
1) This doesnt seem like C++ or you are not using proper naming
2) I am not sure how this code complied since most variable names are incorrect (i tried to fix what i came across).
3) Excessive use of pointers (memory locations in other words) is the main cause of memory leaks. Handle them with care and only use them when you have to.
4) IFFF you have to use pointers that much then add destructors (Anti-constructor) like this ~Car or ~Register on any class that is used as a pointer to signal when the element is destroyed. That way you know where the leak is taking place by writing to the console or handle the destruction gracefully.
Hope that helped
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.
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[].
How do I delete the memory that have been allocated for array models, names? I tried every method but it always crashes when I run it.
int main()
{
vector<Person*> people;
const int PERSON_SZ = 4;
char * names[] = {"Jim", "Fred", "Harry", "Linda"};
int ages[] = { 23, 35, 52, 59 };
for (int i = 0; i < PERSON_SZ; i++)
{
Person * temp = new Person(names[i], ages[i]);
people.push_back(temp);
}
// A vector of Car pointers
vector<Car*> cars;
const int CAR_SZ = 3;
char * models[] = { "Festiva", "Ferrarri", "Prius" };
srand(time(0));
for (int i = 0; i < CAR_SZ; i++)
{
Car * temp = new Car(models[i]);
temp->set_driver(people[rand() % (people.size())]);
temp->set_owner(people[rand() % (people.size())]);
cars.push_back(temp);
}
for (int p = 0; p < people.size(); p++)
{
people[p]->increment_age();
}
for (int c = 0; c < cars.size(); c++)
{
cars[c]->print();
}
delete [] names;
for ( int r = 0; r < CAR_SZ; ++r )
{
delete [] models[r];
}
return 0;
}
You didn't allocate models and names using new, so you cannot delete them.
Both arrays are allocated on the stack and are automatically deleted, when the function returns.
The contents of the (string) arrays (i.e. the strings itselves) are stored in the global data segment and cannot be freed at all. This would also be dangerous because the compiler might use the same string constant at different places in the program.
The models array and the names array are both statically allocated. You didn't use new to create them, you don't need to delete them. You should, however, change their types as follows:
const char * names[] = {"Jim", "Fred", "Harry", "Linda"};
const char * models[] = { "Festiva", "Ferrarri", "Prius" };
because they are pointers to string literals, which are read-only.
The variable names and models are not dynamically allocated, and neither is the data in those arrays. So no need to free them or their contents.
The two vector contains data that need to be free'd on the other hand.
You did not allocate names, and models. You don't need to free or delete them from memory.
As others have answered, this is neither required nor legal...
delete [] names;
Since you didn't new names.
Neither is this...
for ( int r = 0; r < CAR_SZ; ++r )
{
delete [] models[r];
}
Since you didn't new any of the models.
But you do still have some memory leaks!
For each car instance you newed and stored in the cars vector, you need to call delete. Here is one way:
for (std::vector<Car*>::iterator car = cars.begin(), done = cars.end(); car != done; ++car)
{
delete *car;
}
Note that the * there dereferences the iterator, yielding the raw pointer you newed.
The problem with this approach is that it leaves you with a vector full of dangling pointers. You could either reset them in the loop or clear() the vector after the loop has terminated. Perhaps a better approach would be:
while (not cars.empty())
{
delete cars.back();
cars.pop_back();
}
Which deletes each car, then removes its pointer from the vector.
Similarly for each person you newed and stored in people:
while (not people.empty())
{
delete people.back();
people.pop_back();
}
As a rule of thumb, there should be one delete for every new and one delete[] for every new ... []. But you'll do well to learn about smart pointers.
names and models are not pointing heap-allocated area. Don't delete it.
Your code is incomplete. It does not compile. Please enable all warnings and debugging for your compiler, e.g. with g++ -Wall -g if using GCC and improve your code till you get no warning
char * names[] = {"Jim", "Fred", "Harry", "Linda"};
delete [] names;
This is incorrect. You can only delete something that you obtained thru new.