Я новичок в C и пытаюсь разработать небольшое программное обеспечение для ncurses с интерфейсом на основе меню.У меня есть этот код, который http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/menus.html.
Я не понимаю, почему, если я инициализирую массив выбора из 3 или 7 элементов, программа переходит на segfault, но хорошо, если массив любого другого размера.
Вот код.Если добавить 1 к вызову n_choices или calloc (), то ошибки сегментации не произойдет.то есть
my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
Почему 3 и 7 "особенные" ???
#include <ncurses.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <menu.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
WINDOW *mywin;
int rows, cols, h, w, starty, startx;
int wybeg, wxbeg, wymax, wxmax;
// choices
char *choices[] = {
"Choice 1",
"Choice 2",
"Choice 3",
"Choice 4",
"Choice 5",
"Choice 6",
"Choice 7",
};
void func(char*);
int main(int argc, char** argv)
{
ITEM **my_items;
int c;
MENU *my_menu;
int n_choices, i;
ITEM *cur_item;
initscr(); //creates stdscr
cbreak();
noecho();
curs_set(0);
keypad(stdscr, TRUE);
if(has_colors() == TRUE){
start_color();
init_pair(1,COLOR_YELLOW,COLOR_BLUE);
}
getmaxyx(stdscr, rows, cols);
h = rows-4;
w = cols;
starty = 1;
startx = 0;
char quitHint[] = "<Press q to exit>";
move(0,0);
mvprintw(LINES-1, COLS-1-strlen(quitHint), "%s", quitHint);
refresh();
mywin = newwin(h,w,starty,startx);
keypad(mywin,TRUE);
box(mywin,0,0);
wbkgd(mywin,COLOR_PAIR(1));
wrefresh(mywin);
// MENU
/* Create items */
/**************************/
/* FROM HERE IS THE POINT */
/**************************/
// if choices is 3 or 7 elements, segfault occurs! If adding +1 n_choices segfault doesn't occur
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices; ++i){
my_items[i] = new_item(choices[i], choices[i]);
/* Set the user pointer */
set_item_userptr(my_items[i], func);
}
mvprintw(LINES-2,2,"sizeof(choices) = %3d | sizeof(*choices) = %3d | n_choices = %3d", sizeof(choices), sizeof(*choices), n_choices);
/* Create menu */
my_menu = new_menu((ITEM **)my_items);
/* Set main window and sub window */
set_menu_win(my_menu, mywin);
set_menu_sub(my_menu, derwin(mywin, n_choices, 38, 2, 2));
/* Set menu mark to the string " * " */
set_menu_mark(my_menu, " * ");
refresh();
set_menu_fore(my_menu, COLOR_PAIR(1) | A_REVERSE); // selected
set_menu_back(my_menu, COLOR_PAIR(1)); // unselected
/* Post the menu */
post_menu(my_menu);
wrefresh(mywin);
while((c = wgetch(mywin)) != 'q')
{
switch(c)
{ case KEY_DOWN:
menu_driver(my_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(my_menu, REQ_UP_ITEM);
break;
case 10: /* enter */
{
/* execute func() from item pointer */
ITEM *cur;
void (*p) (char *);
cur = current_item(my_menu);
p = item_userptr(cur);
p((char *)item_name(cur));
pos_menu_cursor(my_menu);
break;
}
}
wrefresh(mywin);
}
/* Unpost and free all the memory taken up */
unpost_menu(my_menu);
free_menu(my_menu);
for(i = 0; i < n_choices; ++i){
free_item(my_items[i]);
}
endwin();
return EXIT_SUCCESS;
}
void func(char *local_choice){
mvwprintw(mywin,h-2, 2, "Item selected is : %s", local_choice);
wclrtoeol(mywin);
box(mywin,0,0);
wrefresh(mywin);
}
Скомпилировано с gcc -lmenu -lncurses
Запуск Debian Buster 4.19.0-2-686 #1 SMP Debian 4.19.16-1 (2019-01-17) i686 GNU/Linux