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);