mvwprintw在for循环中意外动作

问题描述 投票:2回答:1

我目前正在编写一个函数,该函数创建一个菜单窗口,该菜单窗口的文本根据参数的不同放置方式。当水平打印数组的内容时,menu()的第一次调用按预期工作(单词以水平方式打印,单词之间带有空格)。但是,如果再次调用该函数,则printf的x位置不会改变,从而导致mvwprintw覆盖前一个字。这至少暗示了我的for循环出了点问题,但是创建垂直菜单的工作与预期的一样,每个单词都印在最后一个单词的下面。

nmenu.c

#include "nmenu.h"
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>

int menu(char title[], char description[], char *choices[], int choicesSize, bool vertical, bool centered)
{
    int menuXMax = 0;
    int highlight = 0;
    int menuHeight = 9;
    int menuWidth = 30;
    int choicesLength = 0;
    int yMax, xMax;

    getmaxyx(stdscr, yMax, xMax);

    for(int i; i < choicesSize; i++)
    {
        if(strlen(choices[i]) > choicesLength)
        {
            choicesLength = strlen(choices[i]);
        }
    }

    if(vertical)
    {
        menuHeight = choicesSize+8;
        menuWidth = choicesLength+4;
    } else
    {
        menuWidth = choicesLength*choicesSize+choicesSize;
    }

    if(strlen(description) > menuWidth)
    {
        menuWidth = strlen(description)+4;
    }

    WINDOW *menu = newwin(menuHeight, menuWidth, yMax/2-menuHeight/2, xMax/2-menuWidth/2);
    box(menu, 0, 0);
    refresh();
    wrefresh(menu);
    keypad(menu, true);

    wattron(menu, A_REVERSE);
    mvwprintw(menu, 0, 2, title);
    wattroff(menu, A_REVERSE);

    mvwprintw(menu, 2, menuWidth/2-strlen(description)/2, description);
    mvwprintw(menu, menuHeight-3, menuWidth/2-4, "[C]ancel");

    menuXMax = getmaxx(menu);

    while(true)
    {
        for(int i = 0; i < choicesSize; i++)
        {
            if(i == highlight)
            {
                wattron(menu, A_REVERSE);
            }

            if(vertical)
            {
                if(centered)
                {
                    mvwprintw(menu, i+4, menuXMax/2-strlen(choices[i])/2, choices[i]);
                } else
                {
                    mvwprintw(menu, i+4, 2, choices[i]);
                }
            } else
            {
                if(centered)
                {
                    mvwprintw(menu, 4, (menuXMax/2-choicesLength*choicesSize/2)+choicesLength*i, choices[i]);
                } else
                {
                    mvwprintw(menu, 4, 2+choicesLength*i, choices[i]);
                }
            }

            wattroff(menu, A_REVERSE);
        }

        switch(wgetch(menu))
        {
            ... // User input 
        }
    }

    MenuBreak: ;

    return 0;
}

test.c

#include "nmenu.h"
#include <ncurses.h>

char *choices[4] = {"Yes", "No", "Maybe", "Sometimes"};

int main()
{
    // Start ncurses
    initscr();
    noecho();
    cbreak();
    curs_set(0);

    menu("Ver 1", "Choices should be uncentered and presented vertically", choices, 4, true, false);
    menu("Ver 2", "Choices should be centered and presented vertically", choices, 4, true, true);

    // End ncurses
    getch();
    endwin();

    return 0;
}

test.c将正常输出第一个菜单,而第二个菜单具有重叠的文本。当呼叫顺序切换时,也会发生这种情况。我只是看不到为什么再次运行该函数时for循环无法正确迭代。

c linux loops ncurses
1个回答
0
投票

在下一行:

for(int i; i < choicesSize; i++)

变量i未初始化。应该将其设置为零,以使其看起来像:

for(int i = 0; i < choicesSize; i++)

然后将正确计算choicesLength,并且水平布局也适用。

Demo

结果的屏幕快照如下:

screenshot

未定义行为

未初始化的变量会导致C中的undefined behavior,因此应尽可能避免使用。

例如,打开编译器警告会很有帮助。使用

gcc -Wextra -Wall main.c nmenu.c -o tst -lncurses

显示此有用信息:

nmenu.c:16:16: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
for(int i; i < choicesSize; i++)
           ^
© www.soinside.com 2019 - 2024. All rights reserved.