0

我正在编写一些具有 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. showSomeOtherMenu然后通过按 Enter 键调用。现在从showSomeOtherMenu他单击 Enter,这将再次调用showSomeMenu- 但请注意,第一次调用showSomeMenu从未有机会返回。

即使这种方法有效并且菜单将正确显示,我想知道这是否会以函数相互调用的无限循环结束。也许比我会有堆栈溢出问题或类似的问题。

我有理由担心吗?他们的示例中显示了这种方法。所以我认为这应该是正确的方法。

4

2 回答 2

1

是的,你担心是对的,这似乎是非常糟糕的设计。

一般来说,以数据驱动的方式设计这样的东西要好得多,即使用描述您想要的层次结构的被动数据结构,然后只是一个runMenu()解释数据并跟踪当前菜单的函数(或其他东西)以及允许哪些“移动”。

于 2013-10-31T13:43:55.043 回答
0

每次按 ENTER 时,您将深入堆栈 1 步,无法返回。这是没有基本情况的递归。不要做!

一个简单的解决方法是将代码修改showSomeOtherMenu()为“返回”而不是递归。

while(1) {
    key = getKey();
    if(key == KEY_ENTER) {
        return;
    }
    // handle other options here
}

更好的方法是保留一堆已访问过的菜单。当您进入一个菜单时,您将其压入堆栈,当您想返回时,您弹出堆栈并转到位于堆栈顶部的菜单。

例如:

> 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.

一个更好的选择是使用某种,这样您只需要一个功能来管理菜单。这有点复杂,但本质上每个菜单都有一个节点,每个菜单项都有该节点的子节点。节点必须具有指向其父节点的指针。

于 2013-10-31T13:46:50.360 回答