Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am doing my c++ homework on an online judge. There are m strings with a length of n. I need to find the minimal expression of a new string, and then insert it in an trie tree. For each string, I need to return the "positon number" of the first identical string.
Following is my code:
#include <cstdio>
using namespace std;
struct trie_node
{
trie_node * firstSon;
trie_node * nextBro;
char value;
bool isKey;
int firstPos;
trie_node(char value):firstSon(NULL), nextBro(NULL), value(value), isKey(false), firstPos(-1){}
};
class trie_Tree
{
public:
trie_Tree();
int searchStr(char* desStr, int len, int selfPos);
private:
trie_node* searchChar(trie_node* fatherNode, char desChar);
trie_node* root;
};
trie_Tree::trie_Tree()
{
root = new trie_node('0');
}
int trie_Tree::searchStr(char * desStr, int len, int selfPos)
{
trie_node* fatherNode = root;
for (int i=0; i<len; i++)
{
fatherNode = searchChar(fatherNode, desStr[i]);
}
if (!fatherNode->isKey)
{
fatherNode->isKey=true;
fatherNode->firstPos=selfPos;
}
return fatherNode->firstPos;
}
trie_node* trie_Tree::searchChar(trie_node* fatherNode, char desChar)
{
if (fatherNode->firstSon==NULL)
{
fatherNode->firstSon = new trie_node(desChar);
return fatherNode->firstSon;
}
trie_node* travNode = fatherNode->firstSon;
while (travNode->nextBro!=NULL)
{
if (travNode->value==desChar) return travNode;
travNode=travNode->nextBro;
}
if (travNode->value==desChar) return travNode;
else
{
travNode->nextBro = new trie_node(desChar);
return travNode->nextBro;
}
}
char* getMinPre(char *s, int _size)
{
int min=0, trav=1;
while (trav<_size && min<_size)
{
int i;
for (i=0; i<_size; i++)
{
if (s[(min+i)%_size]<s[(trav+i)%_size])
{
trav=trav+i+1;
break;
}
else if (s[(min+i)%_size]>s[(trav+i)%_size])
{
min=trav;
trav=trav+1;
break;
}
}
if (i==_size) break;
}
char * result=new char[_size];
for (int i=0; i<_size; i++)
{
result[i]=s[(min+i)%_size];
}
return result;
}
int main()
{
int m, n, result=0;
scanf("%d %d", &m, &n);
trie_Tree tt=trie_Tree();
char* s=new char[n+1];
for (int i=0; i<m; i++)
{
scanf("%s", s);
s=getMinPre(s, n);
result = tt.searchStr(s, n, i);
printf("%d\n", result);
}
delete[] s;
return 0;
}
I compiled my code with VS and g++, and runned my program lots of times for testing. It worked perfectly.
But when the online judge system returned runtime error(exitcode 6).
I googled "exit code 6". It is raised by the program itself, e.g. by making the abort() system call. It can be caused by new and delete operation. But I still cannot debug my code.
Anyone can help me?
That's a lot of code, but some things to look into:
Inside your main function you allocate s: char* s=new char[n+1];.
You pass s into char* getMinPre(char *s, int _size).
getMinPre allocates another buffer, and returns it, overwriting s: s=getMinPre(s, n); (memory leak of initial s buffer).
This potentially happens a lot in the main function's loop, hence you may run out of memory. (getMinPre allocating and overwriting the pointer to allocated buffer).
Since this is an online judge platform, I'd recommend coming up with extreme test cases (min, max elements, tons of iterations) and running them locally.
Also: add some debug information. You can even encapsulate them within #ifdef so you won't have to remove them.
In your trie_Tree constructor, you use new to allocate dynamic memory, but I don't find you delete that object anywhere. Similarly, in searchChar, you allocate a lot of son nodes but never delete them. Also in getMinPre. All of them will lead to memory leak. The only memory you freed is the result in main().
In C++, dynamic memory management is a really complex topic and error prone, every time you allocate some memory with new, you need to keep in mind deallocate them with delete somewhere. Like in C, every time you use malloc(), you need free().
There are a lot of libraries you can use instead of managing the memory yourself. For a linked list, you may consider std::vector in header<vector>.
BTW, I think this code looks like C with Class, not C++.
Related
I am practicing memory allocation and disk management with C++. I just all of the work.. it just looks and seem's a little too easy. I am not sure if my pointer and my allocation and deallocations are correct. My Total FreeSpace looks like it will work, but it looks too basic. I just need someone's programming experience. When I try to run this code it gives me some kind of Error.
Bug Error
Please DO NOT ADD any new Global Variable.
const int MMSIZE = 60136;
char MM[MMIZE];
//** Initialize set up any data needed to manage the memory
void initializeMemory(void)
{
//**increments through the POOL_SIZE
for (int a = 0; a < MMSIZE; a++) {
MM[a] = 'NULL';
}
}
// return a pointer inside the memory
// If no chunk can accommodate aSize call onOutOfMemory()
void* allocate(int size)
{
//******NOT SURE*******
int *p = new int;
*p = 5;
return ((void*) 0);
}
// Free up a chunk previously allocated
void deallocate(void* mPointer)
{
//******NOT SURE*******
int *p = new int;
delete p;
p = 0;
p = new int(10);
}
//Scan the memory and return the total free space remaining
int remaining(void)
{
//******NOT SURE*******
int free = 0;
for (int a = 0; a < MMSIZE; a++)
{
if (MM[a] < MMSIZE)
{
free += a;
}
}
int free2 = free - MMSIZE;
return free2;
}
This code looks unfinished for even a sample but
//** Initialize set up any data needed to manage the memory
void initializeMemory(void)
{
//**increments through the POOL_SIZE
for (int a = 0; a < MMSIZE; a++) {
MM[a] = 'NULL';// <=== this should not even compile as the single quote should only take one character like '\x0' or 'N'
}
}
should not even compile as the single quote should only take one character like '\x0' or 'N'
but post the complete module and i can help you more and maybe explain a few things.
Without discussing other aspects of your code (such as memory leaking etc), the specific error you are getting most likely comes from *int_pointer = 0xDEADBEEF; line. int_pointer is equal to 0, because int_pointer = (long *)allocate(sizeof(long)); and your void* allocate(int size) with its return ((void*) 0); always returns 0. So you are getting exactly that exception: attempting to write 0xDEADBEEF at address 0x00000000, which is a forbidden operation (there is some OS specific stuff at low addresses).
I am getting error of "Double free or corruption(out)" after I print my output. But this error is only coming for small inputs. For bigger inputs program doesn't throw that error. When I create the multidimensional arrays inside the main and delete them, I do not get the error. I have only posted the part of the code which is relevant to this issue here. Please kindly explain how to resolve the issue.
#include<iostream>
#include<vector>
using namespace std;
class Knapsack{
public:
int noItems, capacity, value, weight;
int *weightArray, *valueArray;
int **ValueMatrix, **BacktrackMatrix;
vector<int> itemsChosen;
~Knapsack();
void getInputs(); // reads in data
void findItems(); // calculates best value of items
void backTrack(int row, int col); // backtracks items selected
void print(); //prints out data
};
Knapsack::~Knapsack()
{
delete[] weightArray;
delete[] valueArray;
for(int i=1;i<=noItems;i++)
{
delete[] ValueMatrix[i];
}
delete[] ValueMatrix;
for(int i=1;i<=noItems;i++)
{
delete[] BacktrackMatrix[i];
}
delete[] BacktrackMatrix;
}
void Knapsack::getInputs()
{
cin>>noItems;
cin>>capacity;
weightArray=new int[noItems];
valueArray=new int[value];
for(int i=1;i<=noItems;i++)
{
cin>>value;
valueArray[i]=value;
}
for(int i=1;i<=noItems;i++)
{
cin>>weight;
weightArray[i]=weight;
}
ValueMatrix=new int*[noItems];
for(int i=1;i<=noItems;i++)
{
ValueMatrix[i]=new int[capacity+1];
}
BacktrackMatrix=new int*[noItems];
for(int i=1;i<=noItems;i++)
{
BacktrackMatrix[i]=new int[capacity+1];
}
}
int main()
{
Knapsack *knap=new Knapsack();
knap->getInputs();
knap->findItems();
knap->print();
delete knap;
return 0;
}
I believe the root of your issue is caused by the allocation of valueArray, and the fact that you are iterating out of bounds.
The line valueArray=new int[value]; initializes valueArray with an array of size value which is an uninitialized variable. Perhaps you meant to use noItems?
Also, as songyuanyao pointed out in the comments, your for loops look like for(int i=1;i<=noItems;i++) which starts the counter at 1 and finishes with the counter at noItems, which is erroneous. In a lot of languages, C++ included, arrays start at index 0 (meaning the first item is array[0], not array[1]) and the last item is one minus the size of the array (so the last item of an array with 5 elements is array[4]).
If you change your for loop to start at 0 and end one element before noItems you should be golden. That would be for(int i = 0; i < noItems; i++ )
What's probably happening with smaller allocations is the different chunks of memory are arranged sequentially in the same area of the memory heap, so when you overrun the buffer with data, you're smashing new's bookkeeping data.
When you have larger allocations, the new memory can't fit as cleanly into the free space of the heap, so the allocator ends up leaving some slack space between the allocations. Thus, a small overrun doesn't destroy heap information.
I'm new to C++ and I am working on a function to shuffle strings
It takes an array of strings, shuffles them, and returns them back to the main.
I am returning a pointer to an array of strings called shuffled. The problem I have is that when I try to save that new pointer to the array to another pointer in the main, I start getting weird values that either reference to a file location in my computer or a bunch of numbers.
I'll post the entire code here but really what you want to look at is the return types, how I return it and how I save it in main. Please tell me why my pointer is not referencing the working array that is created in the function. Here's the code:
#include <cstdio>
#include <string>
#include <ctime>
#include <new>
#include <cstdlib>
using namespace std;
const char * getString(const char * theStrings[], unsigned int stringNum)
{
return theStrings[stringNum];
}
string * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
int randList[sz];
for(int p = 0; p < sz; p++)
{
randList[p] = sz;
}
srand(time(0));//seed randomizer to current time in seconds
bool ordered = true;
while(ordered)
{
int countNumberInRandList = 0;//avoid having a sz-1 member list length (weird error I was getting)
for(int i = 0; i < sz; i++)
{
int count = 0;
int randNum = rand()%(sz+1);//get random mod-based on size
for(int u = 0; u < sz; u++)
{
if(randList[u] != randNum)
{
count++;
}
}
if(count == sz)
{
randList[i] = randNum;
countNumberInRandList++;
}
else
i--;
}
//check to see if order is same
int count2 = 0;
for(int p = 0; p < sz; p++)
{
if(randList[p] == p)
{
count2++;
}
}
if(count2 < sz-(sz/2) && countNumberInRandList == sz)
{
ordered = false;
}
}
string * shuffled[sz];
for(int r = 0; r < sz; r++) //getting random num, and str list pointer from passed in stringlist and setting that value at shuffled [ random ].
{
int randVal = randList[r];
string * strListPointer = &theStrings[r];
shuffled[randVal] = strListPointer;
}
for(int i = 0; i < sz; i++)
{
printf("element %d is %s\n", i, shuffled[i]->c_str());//correct values in a random order.
}
return *shuffled;
}
int main()
{
string theSt[] = {"a", "b", "pocahontas","cashee","rawr", "okc", "mexican", "alfredo"};
string * shuff = shuffleStrings(theSt);//if looped, you will get wrong values
return 0;
}
Strings allocate their own memory, no need to give them the "length" like you would have to do for char arrays. There are several issues with your code - without going into the details, here are a few working/non-working examples that will hopefully help you:
using std::string;
// Returns a string by value
string s1() {
return "hello"; // This implicitly creates a std::string
}
// Also returns a string by value
string s2() {
string s = "how are you";
return s;
}
// Returns a pointer to a string - the caller is responsible for deleting
string* s3() {
string* s = new string;
*s = "this is a string";
return s;
}
// Does not work - do not use!
string* this_does_not_work() {
string s = "i am another string";
// Here we are returning a pointer to a locally allocated string.
// The string will be destroyed when this function returns, and the
// pointer will point at some random memory, not a string!
// Do not do this!
return &s;
}
int main() {
string v1 = s1();
// ...do things with v1...
string v2 = s2();
// ...do things with v2...
string* v3 = s3();
// ...do things with v3...
// We now own v3 and have to deallocate it!
delete v3;
}
There are a bunch of things wrong here -- don't panic, this is what happens to most people when they are first wrapping their brains around pointers and arrays in C and C++. But it means it's hard to put a finger on a single error and say "this is it". So I'll point out a few things.
(But advance warning: You ask about the pointer being returned to main, your code does indeed do something wrong with that, and I am about to say a bunch of things about what's wrong and how to do better. But that is not actually responsible for the errors you're seeing.)
So, in shuffleStrings you're making an array of pointers-to-string (string * shuffled[]). You're asking shuffleStrings to return a single pointer-to-string (string *). Can you see that these don't match?
In C and C++, you can't actually pass arrays around and return them from functions. The behaviour you get when you try tends to be confusing to newcomers. You'll need to understand it at some point, but for now I'll just say: you shouldn't actually be making shuffleStrings try to return an array.
There are two better approaches. The first is to use not an array but a vector, a container type that exists in C++ but not in C. You can pass arrays around by value, and they will get copied as required. If you made shuffleStrings return a vector<string*> (and made the other necessary changes in shuffleStrings and main to use vectors instead of arrays), that could work.
vector<string *> shuffleStrings(...) {
// ... (set things up) ...
vector<string *> shuffled(sz);
// ... (fill shuffled appropriately) ...
return shuffled;
}
But that is liable to be inefficient, because your program is then having to copy a load of stuff around. (It mightn't be so bad in this case, because a smallish array of pointers isn't very large and because C++ compilers are sometimes able to figure out what you're doing in cases like this and avoid the copying; the details aren't important right now.)
The other approach is to make the array not in shuffleStrings but in main; to pass a pointer to that array (or to its first element, which turns out to be kinda equivalent) into shuffleStrings; and to make shuffleStrings then modify the contents of the array.
void shuffleStrings(string * shuffled[], ...) {
// ... (set things up) ...
// ... (fill shuffled appropriately) ...
}
int main(...) {
// ...
string * shuffled[sz];
shuffleStrings(shuffled, theSt);
// output strings (main is probably a neater place for this
// than shuffleStrings)
}
Having said all this, the problems that are causing your symptoms lie elsewhere, inside shuffleStrings -- after all, main in your code never actually uses the pointer it gets back from shuffleStrings.
So what's actually wrong? I haven't figured out exactly what your shuffling code is trying to do, but that is where I bet the problem lies. You are making this array of pointers-to-string, and then you are filling in some of its elements -- the ones corresponding to numbers in randList. But if the numbers in randList don't cover the full range of valid indices in shuffled, you will leave some of those pointers uninitialized, and they might point absolutely anywhere, and then asking for their c_strs could give you all kinds of nonsense. I expect that's where the problem lies.
Your problem has nothing to do with any of the stuff you are saying. As you are a beginner I would suggest not presuming that your code is correct. Instead I would suggest removing parts that are not believed to be problematic until you have nothing left but the problem.
If you do this, you should quickly discover that you are writing to invalid memory.
part two : you can't seem to decide on the type of what you are returning. Are you building a pointer to an array to return or are you returning an array of pointers.... you seem to switch between these intermittently.
part three : read #Gareth's answer, he explains about passing parameters around nicely for your instance.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am trying to build a dynamic array of objects using pointers arithmetic. However, the compiler return the following error in this line in the main.cpp
(*(lista+n))(id1,seleccion1,edad1,camiseta1);
error: no match for call to '(jugador) (int &, int & short, short int &, short int &)'
any suggestion is welcome, thanks.
This is the class.
class jugador
{
private:
int id;
short seleccion;
short edad;
short camiseta;
public:
jugador();
jugador(int ID, short SELECCION, short EDAD, short CAMISETA);
int obtener_id();
short obtener_seleccion();
short obtener_edad();
short obtener_camiseta();
void cambiar_id(int nueva_id);
void cambiar_seleccion(short nueva_seleccion);
void cambiar_edad(short nueva_edad);
void cambiar_camiseta(short nueva_edad);
void cambiar_todo(int nueva_ID, short nueva_SELECCION, short nueva_EDAD, short nueva_CAMISETA);
void mostrar_jugador();
};
The constructors...
jugador::jugador()
{
id=999999;
seleccion=32;
edad=99;
camiseta=99;
}
jugador::jugador(int ID, short SELECCION, short EDAD, short CAMISETA)
{
id=ID;
seleccion=SELECCION;
edad=EDAD;
camiseta=CAMISETA;
}
Here is the full code.
Is there a special reason you are not using std::vector<jugador> Check this thread for the advantages of replacing realloc with vector
You have not given enough information so here is what I can tell from the looks of the error:
(*(lista+n))(id1,seleccion1,edad1,camiseta1);
that is NOT a function pointer, it's not even pointing to a function in the first place.
It seems like you are trying to construct an array of jugador by moving the lista pointer. If that is what you want to do then you can do late initialization.
jugador * lista; //< unitialized pointer
int n = 11; //< your number of players, lets suppose 11
lista = new jugador[11]; // now you have an array of jugadores
for(int i = 0; i != n; ++i)
{
lista[i] = jugador(id1,seleccion1,edad1,camiseta1);
}
// use your jugadores, let's suppose you want to use the tenth jugador
jugador *iterator = lista;
iterator+10;
use(*iterator); //*iterator variable holds your 10th jugador object
delete[] lista;
You are using realloc in your code, I suggest you try new and delete instead. Or else provide an explanation of why using realloc is a good choice.
Another thing I noticed in your code is that you don't free the memory you are using. Thus you have a memory leak.
If you need more jugador the use std::copy to achieve that
// let's say in this point you need 20 jugador more
jugador * newlista = new jugador[n+20];
std::copy(lista, lista+11, newlista);
delete[] lista; //you delete the old buffer
for(int i = 11; i != n+20; ++i)
{
newlista[i] = jugador(id1,seleccion1,edad1,camiseta1);
}
// and now newlista has your jugadores, you can even make a function that does that
delete[] newlista ; // delete your jugadores
I am completely agreed with Claudiordgz's response. However, if you want to call the constructor with parameters (without making extra copies) you will need to make an array of pointers instead of an array of objects. I am pasting a version of your code with that. However, I still think that a version using vectors is safer and superior.
Code:
int main()
{
int id1;
short seleccion1, edad1, camiseta1;
jugador arreglo[5];
int n = 0, i;
char opcion = 's';
jugador **lista=NULL;
while (opcion == 's')
{
lista = new jugador*[n];
cout<<"id: "<<endl;
cin>>id1;
cout<<"Seleccion: "<<endl;
cin>>seleccion1;
cout<<"Edad: "<<endl;
cin>>edad1;
cout<<"Camiseta: "<<endl;
cin>>camiseta1;
lista[n] = new jugador(id1,seleccion1,edad1,camiseta1);
n++;
cout << "Desea ingresar otro elemento? (s/n): ";
cin >> opcion;
}
cout << "\nArreglo completo\n";
for (i=0; i<n; i++)
{
lista[n].mostrar_jugador();
}
//deallocating memory
for (int i=0; i<n; i++)
{
delete jugador[i];
}
delete [] jugador;
return 0;
}
I have to create a class Histogram and make operations on this class. The input can be one dimensional array or a two dimensional array. The problem appears when i convert the array into a matrix. This what i have tried so far. The error is <Unable to read memory>
histrogram.h
#ifndef HISTOGRAM_H
#define HISTOGRAM_H
#include<iostream>
class Histogram
{
private:
int** matrix;
int lines;
void SortMatrix();
public:
Histogram(){ }
Histogram(int elements[], int elementsNr);
Histogram(int** m, int l);
void Print();
};
#endif
historgram.cpp
#include"histogram.h"
using namespace std;
Histogram::Histogram(int** m, int l)
{
matrix=m;
lines=l;
SortMatrix();
}
Histogram::Histogram(int elements[], int elementsNr)
{
lines=0;
//initialize matrix : elementrNr lines and 2 columns
int** matrix=new int*[elementsNr];
for(int i=0;i<elementsNr;i++)
{
matrix[i]=new int[2];
matrix[i][0]=INT_MIN;
matrix[i][1]=INT_MIN;
}
//search each element from the array in the matrix
bool found=false;
for(int i=0;i<elementsNr;i++)
{
found=false;
for(int j=0;j<elementsNr;j++)
{
//the element was found in the matrix ( on the first column )
if(matrix[j][0] == elements[i])
{
matrix[j][1]++;
found=true;
break;
}
}
if(!found)
{
matrix[lines][0]=elements[i];
matrix[lines][1]=1;
lines++;
}
}
SortMatrix();
}
void Histogram::SortMatrix()
{
bool flag=true;
int temp;
for(int i=0;(i<lines) && flag;i++)
{
flag=false;
if(matrix[i+1][0]>matrix[i][0])
{
temp=matrix[i][0];
matrix[i][0]=matrix[i+1][0];
matrix[i+1][0]=temp;
flag=true;
}
}
}
void Histogram::Print()
{
for(int i=0;i<lines;i++)
{
cout<<matrix[i][0]<<" : " <<matrix[i][1]<<endl;
}
}
main.cpp
#include"histogram.h"
#include<iostream>
using namespace std;
int main()
{
int arr[]={6,7,3,1,3,2,4,4,7,5,1,1,5,6,6,4,5};
Histogram h(arr,17);
h.Print();
}
Here
int** matrix=new int*[elementsNr];
replace with
matrix=new int*[elementsNr];
becausematrix is already a member variable. You are creating a new temporary variable double pointer named matrix and allocating memory to it rather than your member variable matrix
A couple of people have already given you advice about how to fix some of the problems with this code. I'll give slightly different advice that may initially seem a bit brutal by comparison, but I'll try to demonstrate how it's honestly useful rather than nasty.
I would throw out your existing code with the possible exception of what you have in main, and start over, using an std::map. What you're doing right now is basically trying to re-create the capabilities that std::map already provides (and even when your code is fixed, it's not doing the job as well as std::map does right out of the box).
Using map, your whole program comes out to something like this:
std::ostream &operator<<(std::ostream &os, std::pair<int, int> const &d) {
return os << d.first << " : " << d.second;
}
int main() {
std::map<int, int> h;
for (int i=0; i<17; i++)
++h[arr[i]];
std::copy(h.begin(), h.end(),
std::ostream_iterator<std::pair<int, int> >(std::cout, "\n"));
return 0;
}
If you want to maintain virtually the same interface as your histogram class provided, it's pretty easy to do that -- the for loop goes into the constructor, the copy into print (and SortMatrix disappears, because a map is always sorted).
By doing this, you change from an O(N2) algorithm to an O(N log N) algorithm. The bugs others have pointed out disappear completely, because the code that contained them is no longer needed. The only real disadvantage I can see is that the result will probably use a bit more memory -- it uses a balanced tree with individually allocated nodes, which is likely to introduce a fair amount of overhead for nodes that only contain 2 ints (and a bit for balancing). I can't quite imagine worrying about this though -- long before you have enough nodes for the memory usage to become significant, you have way too many to present to even consider presenting to the user.
#mathematician1975 already provided an answer for the main problem. There's another bug in SortMatrix(): you only swap the elements of the first column, therefore after sorting, the counts (in the second column) will not be correct anymore. You'll have to insert
temp=matrix[i][1];
matrix[i][1]=matrix[i+1][1];
matrix[i+1][1]=temp;
to get it working.