I'm having trouble with menus in ncurses. I'm trying to set up a menu, have the user select an option, and set an int called num_players depending upon their selection.
I do this with boost::lexical_cast and item_name(current_item(my_menu)) but every time I call current_item(my_menu) I'm just getting NULL.
Here's a sample of the code in question:
char *choices[] = {"1", "2", "3", "4", "5", "6"};
//create the dynamic array for the items and their description
ITEM** my_items;
MENU *my_menu;
int num_choices = 6;
my_items = new ITEM*;
for (int x = 0; x < num_choices; x++)
{
my_items[x] = new_item(choices[x], choices[x]);
}
my_items[6] = (ITEM*)NULL;
my_menu = new_menu((ITEM**)my_items);
set_menu_mark(my_menu, " * ");
set_current_item(my_menu, my_items[0]);
post_menu(my_menu);
wrefresh(scr);
int c;
while((c = wgetch(scr)) != '\n')
{ switch(c)
{ case KEY_DOWN:
menu_driver(my_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(my_menu, REQ_UP_ITEM);
break;
}
}
//right here, calling current_item just gives me null
//am I supposed to unpost the menu first?
//what am I doing wrong? this is frustrating
ITEM* cur = current_item(my_menu);
setNumPlayers((char*) item_name(cur));
unpost_menu(my_menu);
free_item(my_items[0]);
free_item(my_items[1]);
free_item(my_items[2]);
//etc etc
This statement:
my_items = new ITEM*;
allocates enough space for a single ITEM* and assigns the pointer to that space to my_items. Subsequently attempting to write to my_items[i] for any value of i other than 0 will overwrite random memory, which is -- to say the least -- undefined behaviour. Whatever other problems your code might have, you need to fix that before proceeding.
It's clear from the code that you expect to be able to store num_choices + 1 ITEM*s in the array, so you need to allocate an array of at least that size.
my_items = new ITEM*[num_choices + 1];
(Really, you should replace the 6 in my_items[6] = NULL; with num_choices; otherwise, you have a bug waiting to bite you.)
Don't forget to use delete[] instead of delete, when you are done.
But since you are using C++, you might as well make use of it:
std::vector<ITEM*> my_items;
for (int x = 0; x < num_choices; x++) {
my_items.emplace_back(new_item(choices[x], choices[x]));
}
my_items.emplace_back(nullptr);
/* Unfortunately, new_menu requires a non-const ITEM**,
* even though it should not modify the array. */
my_menu = new_menu(const_cast<ITEM**>(my_items.data()));
At the end, you still have to call free_item on each ITEM* before letting the std::vector destruct:
for (auto& item : my_items) free_item(item);
Related
I have read some old questions and tested some ideas, but my issue still exists, so here is what I want:
I need a function that returns a simple array with a fixed size of 181 integer values.
After some tests I have this function:
int *Sonar::scan(int *distances) {
// Scanning
for (int i = 0; i <= 180; i++) {
// Rotates sonar
//this->rotate(i);
// Gets the distance
//distances[i] = this->getDistance();
distances[i] = i;
}
// Returns
return distances;
}
And call it this way:
// Sonar
case 's':
int distances[181];
*distances = sonar.scan(distances);
for (int i = 0; i <= 180; i++) {
Serial.println(String(i) + ": " + String(distances[i]));
}
break;
But I get this result:
0: 1898
1: 1
2: 2
3: 3
4: 4
...
The value of index 0 is corrupted all the time. So what mistake do I make?
The first element of the array is being overwritten with the pointer to the array when you do:
*distances = sonar.scan(distances);
That is because you dereference the array with *distances giving a reference to the first element. You then assign to that with what you return from the scan method (the pointer to the array).
Just doing:
sonar.scan(distances);
would give the result you expect.
There is no need to return from the method as you are passing the array by a form of reference (a pointer) and that means the array is being changed in place.
I'm Java guy trying to solve discrete knapsack problem in c++. However, I'm having trouble with pointers. I have an object with a field
Item ** items;
representing array of items to choose from. I also created a method to add an item which works like insertion sort (at least I hope so).
void Knapsack::addItem(Item item) {
int k = itemCount - 1;
if (this->items[k] != NULL) {
return;
}
while (k > 0 && this->items[k - 1] == NULL) {
k--;
}
if (k == 0) {
this->items[0] = &item;
} else {
int i = 0;
while (i < k && item < *(this->items[i])) {
i++;
}
for (int n = k; n > i; n--) {
this->items[n] = this->items[n - 1];
}
this->items[i] = &item;
}
}
Later, in my main I invoke the method by
knapsack->addItem(*(new Item(values.at(0), values.at(1))));
values being a vector of ints. The method itself seems to work fine, however, debugger shows that everytime I invoke the method with new Item, the previous values already put in my array are set to the same values as the new item.
(ex. if items[0] has value of 5, and I invoke the method with an item valued as 10, the items[0] instantly is set to 10).
Why are the values overwritten? I am creating a new object everytime I invoke the method.
EDIT:
Problem was fixed by replacing
this->items[0] = &item;
this->items[i] = &item;
with
this->items[0] = new Item(item.getWeight(), item.getValue());
this->items[i] = new Item(item.getWeight(), item.getValue());
SECOND EDIT:
The answer shows better (and probably correct) way to do this. Now the function takes a pointer instead of an object.
void Knapsack::addItem(Item * item);
this->item[i] = item;
knapsack->addItem(new Item(values.at(0), values.at(1)));
You are storing a pointer to a temporary copy of an Item object in the array in your addItem function, once the function returns the temporary object will be destroyed and you will be left with an invalid pointer. Make sure to allocate an Item object on the heap and passing a pointer to your addItem function or just use a vector of type std::vector<Item> and save your objects in there.
I'm having a weird behaviour with my C++ code. Here it is.
OI_Id * Reqlist = 0;
int * Idlist = 0;
int Reqsize = listcount; // we calculate listcount somehow earlier.
Idlist = new int [Reqsize];
if (Idlist == 0)
{
return;
}
printf ("Idlist = %0x",Idlist);
Reqlist = new OI_Id [Reqsize]; // OI_Id is a 3rd party lib simple struct.
if (Reqlist == 0)
{
return;
}
printf ("Reqlist = %0x",Reqlist);
So the problem is that in both cases it prints the same value - the same pointer is returned by the new operator. BUT! If we change the length of second allocated array to another value (Reqsize+ 1, for example), everything is OK.
Did anybody meet any similar behaviour? I have no idea what's the reason of the problem.
I need some assistance with a C++ project. What I have to do is remove the given element from an array of pointers. The technique taught to me is to create a new array with one less element and copy everything from the old array into the new one except for the specified element. After that I have to point the old array towards the new one.
Here's some code of what I have already:
I'm working with custom structs by the way...
Data **values = null; // values is initialized in my insert function so it is
// populated
int count; // this keeps track of values' length
bool remove(Data * x) {
Data **newArray = new Data *[count - 1];
for (int i = 0; i < count; i++) {
while (x != values[i]) {
newArray[i] = values[i];
}
count -= 1;
return true;
}
values = newArray;
return false;
}
So far the insert function works and outputs the populated array, but when I run remove all it does is make the array smaller, but doesn't remove the desired element. I'm using the 0th element every time as a control.
This is the output I've been getting:
count=3 values=[5,6,7] // initial insertion of 5, 6, 7
five is a member of collection? 0
count=3 values=[5,6] // removal of 0th element aka 5, but doesn't work
five is a member of collection? 0
count=4 values=[5,6,5] // re-insertion of 0th element (which is stored in
five is a member of collection? 0 // my v0 variable)
Could anyone nudge me in the right direction towards completing this?
First of all, your code is leaking memory like no good! Next you only copy the first element and not even that if the first element happens to be the one you want to remove. Also, when you return from your function, you haven't changed your internal state at all. You definitely want to do something along the lines of
Data** it = std::find(values, values + count, x);
if (it != values + count) {
std::copy(it + 1, values + count, it);
--count;
return true;
}
return false;
That said, if anybody taught you to implement something like std::vector<T> involving reallocations on every operation, it is time to change schools! Memory allocations are relatively expensive and you want to avoid them. That is, when implementing something like a std::vector<T> you, indeed, want to implement it like a std::vector<T>! That is you keep an internal buffer of potentially more element than there are and remember how many elements you are using. When inserting a new element, you only allocate a new array if there is no space in the current array (not doing so would easily result in quadratic complexity even when always adding elements at the end). When removing an element, you just move all the trailing objects one up and remember that there is one less object in the array.
Try this:
bool remove(Data * x)
{
bool found = false;
// See if x is in the array.
for (int i = 0; i < count; i++) {
if (x != values[i]) {
found = true;
break;
}
}
if (!found)
{
return false;
}
// Only need to create the array if the item to be removed is present
Data **newArray = new Data *[count - 1];
// Copy the content to the new array
int newIndex = 0;
for (int i = 0; i < count; i++)
{
if (x != values[i])
newArray[newIndex++] = values[i];
}
// Now change the pointers.
delete[] values;
count--;
values = newArray;
return true;
}
Note that there's an underlying assumption that if x is present in the array then it's there only once! The code will not work for multiple occurrences, that's left to you, seeing as how this is a school exercise.
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.