我正在编写一些有SDK的设备。
说我要显示一些菜单。你通常这样做:
void showSomeMenu()
{
...
drawItem(0, "menu option1");
drawItem(1, "menu option2");
while(1)
{
key = getKey();
if(key == KEY_ENTER)
{
showSomeOtherMenu();
return; // or break
}
}
...
}
您可以看到,如果用户点击上面的输入,则可以打开someOtherMenu
。现在说someOtherMenu
用户希望回去。然后你实现它:
void showSomeOtherMenu()
{
...
// add menu items
while(1)
{
key = getKey();
if(key == KEY_ENTER)
{
showSomeMenu(); // Will open previous menu (implemented in the first snippet)
return;
}
}
...
}
我觉得这种方法很奇怪:有人叫showSomeMenu
。
然后按Enter键从showSomeOtherMenu
调用。现在从showSomeOtherMenu
他点击了
输入,再次拨打showSomeMenu
- 但通知,第一次拨打showSomeMenu
从未有机会返回。
即使这种方法有效并且菜单会正确显示,但我想知道这是否会以无限循环的函数相互呼叫结束。也许我会遇到堆栈溢出问题或类似的问题。
我有权担心吗?他们的样本中显示了这样做的方法。所以我认为它应该是正确的方法。
答案 0 :(得分:1)
是的,你是对的,这似乎是非常糟糕的设计。
一般来说,以数据驱动的方式设计这样的事情要好得多,即使用描述所需层次结构的被动数据结构,然后只需一个函数({{1}解释数据并跟踪当前菜单以及允许“移动”的内容。
答案 1 :(得分:0)
每次按下ENTER键,你都会深入到堆栈中一步,没有办法返回。这是recursion,没有基本情况。不要这样做!
一个简单的解决方法是将showSomeOtherMenu()
中的代码修改为“返回”而不是递归。
while(1) {
key = getKey();
if(key == KEY_ENTER) {
return;
}
// handle other options here
}
更好的方法是保留已访问过的stack个菜单。当你进入一个菜单时,你将它推到堆栈上,当你想要返回时,你弹出堆栈并转到当时位于堆栈顶部的菜单。
e.g:
> Enter menu1 // stack is now [ menu1 ]<- head
> Enter menu2 // stack is now [ menu1, menu2 ]<- head
> Enter menu5 // stack is now [ menu1, menu2, menu5 ]<- head
> Back -> menu2 // stack is now [ menu1, menu2 ]<- head
> Enter menu4 // stack is now [ menu1, menu2, menu4 ]<- head
// etc.
更好的选择是使用某种tree,这样您只需要一个功能来管理菜单。这有点复杂,但实际上每个菜单都有一个节点,每个菜单项都有一个节点的子节点。节点必须有指向其父节点的指针。