Can someone explain why this code does not work? It keeps crashing when it asks for input in addCar().
I think something is wrong with copying an array, but I can't figure out what exactly. I also tried to use copy() but it didn't work either.
#include <iostream>
#include <string>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct Car{
string Brand;
string model;
long mileage;
};
void addCar(int *ptr, struct Car *arra){
*ptr=*ptr+1;
Car *newArr = new Car[*ptr];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
cout<<"Brand ";
getline(cin,newArr[*ptr].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr].model);
cout<<"mileage ";
cin>>newArr[*ptr].mileage;
arra=newArr;
};
int main(int argc, char** argv) {
int size=1;
int *ptr_size;
ptr_size=&size;
Car *tab=new Car[*ptr_size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
addCar(*ptr_size, tab);
return 0;
}
The fail is probably here:
getline(cin,newArr[*ptr].Brand);
A bit above, you did this: *ptr=*ptr+1; and made newArr an array of *ptr elements. Arrays are origin zero. That means the first item in the array is newArr[0]. The last will be at newArr[*ptr-1], so writing into newArr[*ptr] is writing over someone else's memory. Generally a bad thing to do.
But this is also not cool:
*ptr=*ptr+1;
Car *newArr = new Car[size+1];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
You increment the size of the array. That's OK.
You create a new array with the new size. That's OK.
You copy new size number of elements from the old array to the new array and over shoot the end of the old array. Not OK.
The best answer is given by Jerry Coffin and Paul McKenzie in the comments: use a std::vector. If this is not allowed... Ick.
But alrighty then.
First, memcpy literally copies a block of memory. It does not know or care what that block of memory is or what it contains. Never use memcpy unless you are copying something really, really simple like basic data type or a structure made up of nothing but basic data types. String is not basic. The data represented by a string might not be inside the string. In that case, you copy a pointer to the string and that pointer will not be valid after the death of the string. That's not a problem in your case because you don't kill the string. That leads to problem 2. Let's fix that before you get there. The easiest way (other than vector) is going to be:
for (int index = 0; index < *ptr-1; index++)
{
newArr[index] = arra[index];
}
An optimization note. You don't want to resize and copy the array every time you add to it. Consider having two integers, one size of array and the other index into array and double the size of the array every time the index is about to catch up with the size.
When you allocate any memory for data with new somebody has to clean up and put that memory back with delete. In C++ that somebody is you. so, before you arra=newArr; you need to delete[] arra;
Passing in the array index as a pointer overcomplicates. Use a reference or just pass by value and return the new index. Also, don't name a variable ptr. Use something descriptive.
void addCar(int &arrasize, struct Car *arra){
or
int addCar(int arrasize, struct Car *arra){
Next problem: int addCar(int arrasize, struct Car *arra){ passes in a pointer to arra. But you passed the pointer by value, made a copy of the pointer, so when you change the pointer inside the function, it's only the copy that got changed and the new array is not going to come back out again. So,
int addCar(int arrasize, struct Car * & arra){
Passes in a reference to the pointer and allows you to modify the pointer inside the function.
Putting all that together:
int addCar(int size, struct Car * & arra)
{
Car *newArr = new Car[size + 1];
for (int index = 0; index < size; index++)
{
newArr[index] = arra[index];
}
cout << "Brand ";
getline(cin, newArr[size].Brand);
cout << "Model ";
getline(cin, newArr[size].model);
cout << "mileage ";
cin >> newArr[size].mileage;
delete[] arra;
arra = newArr;
return size+1;
}
int main()
{
int size=1;
Car *tab=new Car[size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
size = addCar(size, tab);
// do more stuff;
// bit of test code here
for (int index = 0; index < size; index++)
{
cout << "Car " << index << " brand =" <<tab[index].Brand << " Model=" << tab[index].model << " mileage=" <<tab[index].mileage << endl;
}
delete[] tab;
return 0;
}
When you are copying the old array to the new one you are accessing invalid memory, remember that, in that point, arra has size *ptr-1 not *ptr, so the line should be
memcpy(newArr, arra, (*ptr-1)*sizeof(Car));
also in the other lines you should insert the new value in the *ptr-1 position because the indexes in newArr go from 0 to size-1 ie *ptr-1:
cout<<"Brand ";
getline(cin,newArr[*ptr-1].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr-1].model);
cout<<"mileage ";
cin>>newArr[*ptr-1].mileage;
Related
I have my class CompressionAlgorithm from which classes RLE and MTF inherits. I made an array to which I am trying to add these child classes but only first class gets added.
int const size = 2;
CompressionAlgorithm * CA[size];
CA[0] = new RLE();
CA[1] = new MTF();
Both RLE and MTF get initialized but when I am trying to print their name using printall method MTF doesn't get any info printed on console or I am getting an error saying std::bad_alloc.
Print p;
p.printall(*CA, (size));
void Print::printall(CompressionAlgorithm *ca, int size)
{
for (int i = 0; i < size; i++)
{
cout << i+1 << " for ";
cout << ca[i].GetName();
cout << "\n";
}
}
Where am I making a mistake?
You need make function to accept array of pointers not just a pointer:
void Print::printall(CompressionAlgorithm *ca[], int size)
and whil calling you need to call like this:
p.printall(CA, (size));
You don't need to dereference the pointer when passing it to the function; doing so only passes the first element. Additionally the function signature needs to accept an array of pointers, which is what you have.
instead of calling *ca in the printall() call only ca as calling *ca only accesses the first element of the array when not in a loop.
Im making a little project at home about genetic algorithm. But im trying to make it generic, so i use pointers to function and void pointers. but i think it might be making some problems.
The main goal of this section of the project is to get a pointer to a function, which return a certain struct. The struct containing a void pointer
and when im trying to view the value of where it points too it isn`t quite right.I suspect that maybe the interaction between these two might be causing me some problems.
details:
struct:
struct dna_s{
int size;
void *dna;
};
population is a class contaning all the population for the process. besides, it contains 2 functions as well, init_func and fitter_func which are both pointers to functions.
pointer to function definition:
typedef dna_s (*init_func_t)();
typedef int (*fitter_func_t)(dna_s);
population class:
class population{
private:
// Parameters
int population_size;
node *pop_nodes;
// Functions
init_func_t init_func;
fitter_func_t fitter_func;
public:
population(int pop_size,init_func_t initialization_func){
// Insert parameters into vars.
this->population_size = pop_size;
this->init_func = initialization_func;
// Create new node array.
this->pop_nodes = new node[this->population_size];
for(int i = 0;i < this->population_size; i++){
dna_s curr_dna = this->init_func();
char *s = static_cast<char*>(curr_dna.dna);
cout << s << endl;
this->pop_nodes[i].update_dna(curr_dna);
}
}
};
You can see that in the constructor im inserting a pointer to function, init_func. this function is generating random words.
init_func:
dna_s init_func(){
string alphanum = "0123456789!##$%^&*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char init_s[STRING_SIZE+1] = {};
dna_s dna;
// Generate String
for(int i = 0; i < STRING_SIZE; i++){
init_s[i] = alphanum[rand() % alphanum.size()];
}
cout << "-->" << init_s << endl;
// Insert into struct.
dna.size = STRING_SIZE;
dna.dna = static_cast<void*>(&init_s);
// Return it
return dna;
}
the main function is not so interesting but it might be connected:
int main(){
// Init srand
srand(time(0));
// Parameters
int population_size = 10;
population pop(population_size, init_func);
}
now for the interesting part, whats the problem?
in the init_func the cout prints:
-->e%wfF
which is all good
but in the population class the cout prints:
e%Ω²(
and the wierd thing is the first 2 characters will always be the same, but the other 3 will always be this string Ω²(.
example:
-->XaYN7
XaΩ²(
-->oBK9Q
oBΩ²(
-->lf!KF
lfΩ²(
-->RZqMm
RZΩ²(
-->oNhMC
oNΩ²(
-->EGB6m
EGΩ²(
-->osafQ
osΩ²(
-->3#NQt
3#Ω²(
-->D62l0
D6Ω²(
-->tV#mu
tVΩ²(
Your code has a few lifetime issues. In your dna_S struct:
void *dna;
This is a pointer, it points to an object that exists elsewhere. Then, in your init_func:
dna_s init_func(){
...
char init_s[STRING_SIZE+1] = {};
dna_s dna;
...
dna.dna = static_cast<void*>(&init_s);
...
return dna;
}
init_s is a variable that exists inside init_func, you make dna point to that variable and then leave the function. init_s ceases to exist at this point, dna is pointing nowhere useful when the population constructor gets it, causing undefined behavior.
You could work around that by allocating memory with new char[], like you did for pop_nodes, but you are responsible for deleting that memory when it is no longer used.
This is really weird. If I increase the value of asize just by one crashSystem() does what its name speaks. Second function returning an int pointer works ok with much bigger values. Those two functions just delete and allocate the same dynamic array with same size (I created it just for test purposes).
Note: I think it could have something to do with maximum stack capacity 1MB (130037 * 8 in bytes is near 1MB), but it's really strange 'cause allocating using new inside function should work the same as any other new.
Using Visual Studio 2015
#include <iostream>
void crashSystem(int * dynamicArray, int asize) {
delete[] dynamicArray;
//dynamicArray = nullptr; does not matter at all
dynamicArray = new int[asize];
std::cout << "mem allocated\n";
}
int * worksOk(int * dynamicArray, int asize) {
int * newDynamicArray = new int[asize];
delete[] dynamicArray;
std::cout << "mem allocated\n";
return newDynamicArray;
}
int main()
{
int asize = 130037; // dynamic array size
//asize = 12330037; // for testing second function that works
int * dynamicArray;
dynamicArray = new int[asize];
for (int i = 0; i < 100; i++)
{
std::cout << "iteration " << i << " ";
crashSystem(dynamicArray, asize);
//dynamicArray = worksOk(dynamicArray, asize);
}
std::cout << "\n";
system("PAUSE");
}
Note 2: Crashing app this way in Release mode tends to block executable by creating non existent process (checked with Process Hacker 2)
The problem is that you're passing pointer by value, so it still points to the new int[asize]; allocated in main(), on which you then call multiple delete [].
It becomes a dangling pointer after the first delete [] call.
Even assigning nullptr won't help you if the pointer is not being passed by reference.
worksOk works, because you're returning the pointer pointing to the newly allocated space and assigning it, so it's valid every time.
Just change the signature so it uses reference:
void crashSystem(int *&dynamicArray, int asize)
and it should work fine.
I am writing a script which must copy some names into a multidimensional array, print the contents of the array and then deallocate the memory and terminate. The problem I am having is that when I run the script it only prints out the last name entered. Here is what I have done. Any help would be great! Thanks in advance!
#include <iostream>
#include <string.h>
using namespace std;
void createArray(int n);
void addDetail(char*& name, char*& surname);
void printArray();
void clear();
char ***details;
int used;
int size;
int main()
{
createArray(3);
char* tmpName = new char[20];
char* tmpSurName = new char[120];
strcpy(tmpName, "nameA");
strcpy(tmpSurName, "surnameA");
addDetail(tmpName,tmpSurName);
strcpy(tmpName, "nameB");
strcpy(tmpSurName, "surnameB");
addDetail(tmpName,tmpSurName);
strcpy(tmpName, "nameC");
strcpy(tmpSurName, "surnameC");
addDetail(tmpName,tmpSurName);
clear();
return 0;
}
void createArray(int n)
{
details= new char**[n];
for(int i=0; i<n; i++)
details[i] = new char*[2];
size = n;
used = 0;
}
void addDetail(char*& name, char*& surname)
{
if(occupation < size)
{
details[used][0] = name;
details[used][1] = surname;
used++;
}else{
cout << "Array Full " << endl;
}
}
void printArray()
{
for(int i=0; i<used; i++)
cout << details[i][0] << " " << details[i][1] << endl;
}
void clear()
{
for(int i=0; i<size; i++)
{
delete [] details[i];
details[i] = 0;
}
delete [] details;
details=0;
}
You didn't allocate memory for details[used][0] and details[used][1] so it's using whatever random address was in those locations.
Since this is C++ you can use string instead perhaps? std::string **details;. This should work with your existing code, except that it will leak memory.
Better still is to use a vector of vectors.
Something like:
std::vector<std::vector<std::string> > details;
Then the createArray function can go away completely and addDetail becomes simpler:
std::vector<string> newName;
newName.push_back(name);
newName.push_back(surname);
details.push_back(newName);
It is because each time, you are effectively storing the pointer tmpName and tmpSurName in the array details. Then in the next iteration, you overwrite the contents of the memory where tmpName and tmpSurName point to, so at the end you'll have a list that contains the last name/surname n times.
To solve it, you need to re-allocate tmpName and tmpSurName before each call to addDetail.
Btw, why do you need to use an (ewww) char***, and can't use e.g. the STL?
What it looks like is happening is that you are not adding the string to the array, you are adding a pointer to name and surname. Every instance is pointing at that variable, so when you ask the array what it contains it goes and asks name and surname, which will only contain the last value.
Also that array, are you sure its working how you want it to work? Arrays are... concrete things. Your essentially saying "I want 5 of these, they will be this big (based on the type you put in)" and the computer quietly goes "well I'll set aside space for those here and you can put them in when your ready". When your code puts those names in there, there really isn't any prep on where to store them. If you fill up that space and go beyond you go to bad places. So what you should do is have that last * of char*** be a pointer to a char[120] so that you know (for your purposes atleast) it never gets filled up. Do that in your createArray function after you have created the outer arrays.
You keep overwriting your temporary buffers rather than making new buffers for each entry in the array. As a result, only the last data written to the buffer survives.
Here's a rough guide on one way to fix it, though this sample may have some problems - I made no attempt to compile or test this.
This portion of main belongs in addDetail:
char* tmpName = new char[20];
char* tmpSurName = new char[120];
strcpy(tmpName, "nameA");
strcpy(tmpSurName, "surnameA");
So, your new addDetail would look something like:
void addDetail(char*& name, char*& surname)
{
if(occupation < size)
{
details[used][0] = new char[20];
details[used][1] = new char[120];
strcpy(details[used][0], name);
strcpy(details[used][1], surname);
used++;
}else{
cout << "Array Full " << endl;
}
}
And it would be called from main like:
addDetail("nameA", "surnameA");
You'd need to update clear to properly cleanup the allocations made in addDetail though.
I have started out to write a simple console Yahtzee game for practice. I just have a question regarding whether or not this function will leak memory. The roll function is called every time the dices need to be re-rolled.
What it does is to create a dynamic array. First time it is used it will store 5 random values. For the next run it will only re-roll all except for the dice you want to keep. I have another function for that, but since it isn't relevant for this question I left it out
Main function
int *kast = NULL; //rolled dice
int *keep_dice = NULL; //which dice to re-roll or keep
kast = roll(kast, keep_dice);
delete[] kast;
and here's the function
int *roll(int *dice, int *keep) {
srand((unsigned)time(0));
int *arr = new int[DICE];
if(!dice)
{
for(int i=0;i<DICE;i++)
{
arr[i] = (rand()%6)+1;
cout << arr[i] << " ";
}
}
else
{
for(int i=0;i<DICE;i++)
{
if(!keep[i])
{
dice[i] = (rand()%6)+1;
cout << "Change ";
}
else
{
keep[i] = 0;
cout << "Keep ";
}
}
cout << endl;
delete[] arr;
arr = NULL;
arr = dice;
}
return arr;
}
Yes, it can leak. Just for example, using cout can throw an exception, and if it does, your delete will never be called.
Instead of allocating a dynamic array yourself, you might want to consider returning an std::vector. Better still, turn your function into a proper algorithm, that takes an iterator (in this case, a back_insert_iterator) and writes its output there.
Edit: Looking at it more carefully, I feel obliged to point out that I really dislike the basic structure of this code completely. You have one function that's really doing two different kinds of things. You also have a pair of arrays that you're depending on addressing in parallel. I'd restructure it into two separate functions, a roll and a re_roll. I'd restructure the data as an array of structs:
struct die_roll {
int value;
bool keep;
die_roll() : value(0), keep(true) {}
};
To do an initial roll, you pass a vector (or array, if you truly insist) of these to the roll function, which fills in initial values. To do a re-roll, you pass the vector to re-roll which re-rolls to get a new value for any die_roll whose keep member has been set to false.
Use a (stack-allocated) std::vector instead of the array, and pass a reference to it to the function. That way, you'll be sure it doesn't leak.
The way you allocate memory is confusing: memory allocated inside the function must be freed by code outside the function.
Why not rewrite it something like this:
int *kast = new int[DICE]; //rolled dice
bool *keep_dice = new bool[DICE]; //which dice to re-roll or keep
for (int i = 0; i < DICE; ++i)
keep_dice[i] = false;
roll(kast, keep_dice);
delete[] kast;
delete[] keep_dice;
This matches your news and deletes up nicely. As to the function: because we set keep_dice all to false, neither argument is ever NULL, and it always modifies dice instead of returning a new array, it simplifies to:
void roll(int *dice, int *keep) {
for(int i=0;i<DICE;i++)
{
if(keep[i])
{
keep[i] = false;
cout << "Keep ";
}
else
{
dice[i] = (rand()%6)+1;
cout << "Change ";
}
}
cout << endl;
}
Also, you should move the srand call to the start of your program. Re-seeding is extremely bad for randomness.
My suggestion would be to take time out to buy/borrow and read Scott Meyers Effective C++ 3rd Edition. You will save yourselves months of pain in ramping up to become a productive C++ programmer. And I speak from personal, bitter experience.