5

次のコードは、NCURSESメニュー ライブラリの例です。コードの何が問題なのかはわかりませんが、valgrind はいくつかの問題を報告しています。何か案は...

==4803== 1,049 (72 direct, 977 indirect) bytes in 1 blocks are definitely lost in loss record 25 of 36
==4803==    at 0x4C24477: calloc (vg_replace_malloc.c:418)
==4803==    by 0x400E93: main (in /home/gerardoj/a.out)
==4803== 
==4803== LEAK SUMMARY:
==4803==    definitely lost: 72 bytes in 1 blocks
==4803==    indirectly lost: 977 bytes in 10 blocks
==4803==      possibly lost: 0 bytes in 0 blocks
==4803==    still reachable: 64,942 bytes in 262 blocks

ソースコード:

#include <curses.h>
#include <menu.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD   4

char *choices[] = {
    "Choice 1",
    "Choice 2",
    "Choice 3",
    "Choice 4",
    "Choice 5",
    "Choice 6",
    "Choice 7",
    "Exit",
}
;

int main()
{
    ITEM **my_items;
    int c;
    MENU *my_menu;
    int n_choices, i;
    ITEM *cur_item;

    /* Initialize curses */
    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    /* Initialize items */
    n_choices = ARRAY_SIZE(choices);
    my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
    for (i = 0; i < n_choices; ++i) {
        my_items[i] = new_item(choices[i], choices[i]);
    }
    my_items[n_choices] = (ITEM *)NULL;

    my_menu = new_menu((ITEM **)my_items);

    /* Make the menu multi valued */
    menu_opts_off(my_menu, O_ONEVALUE);

    mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item.");
    mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)");
    post_menu(my_menu);
    refresh();

    while ((c = getch()) != KEY_F(1)) {
        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 ' ':
            menu_driver(my_menu, REQ_TOGGLE_ITEM);
            break;
        case 10:
            {
                char temp[200];
                ITEM **items;

                items = menu_items(my_menu);
                temp[0] = '\0';
                for (i = 0; i < item_count(my_menu); ++i)
                if(item_value(items[i]) == TRUE) {
                    strcat(temp, item_name(items[i]));
                    strcat(temp, " ");
                }
                move(20, 0);
                clrtoeol();
                mvprintw(20, 0, temp);
                refresh();
            }
            break;
        }
    }
    unpost_menu(menu);
    free_item(my_items[0]);
    free_item(my_items[1]);
    free_item(my_items[2]);
    free_item(my_items[3]);
    free_item(my_items[4]);
    free_item(my_items[5]);
    free_item(my_items[6]);
    free_item(my_items[7]);
    free_menu(my_menu);
    endwin();
}
4

4 に答える 4

4

NCURSES Programming Howtoによると、メニュー ライブラリを使用するには、次の手順が必要です。

  • 呪いを初期化する
  • new_item() を使用してアイテムを作成します。アイテムの名前と説明を指定できます。
  • 添付するアイテムを指定して、new_menu() でメニューを作成します。
  • menu_post() でメニューを投稿し、画面を更新します。
  • ユーザー要求をループで処理し、menu_driver でメニューに必要な更新を行います。
  • menu_unpost() でメニューをアンポストする
  • free_menu() によってメニューに割り当てられたメモリを解放します
  • free_item() でアイテムに割り当てられたメモリを解放します
  • 呪いを終わらせる
  • あなたのコードから私が言えることから:

    • メニューの投稿を取り消さないでください (これにより、リークが発生したり、画面が文字化けするリスクが生じる可能性があります)。
    • メニューは、アイテムが解放された後に解放されます (ncurses の実装方法によっては、問題になる場合とそうでない場合があると思います)。
    • 項目の 8 要素配列の項目 0 と 1 のみが解放されます。これはおそらく漏れです。
    • ポインターのmy_items配列は決して解放されません。これは確かに漏れです。

    @lh3 が言ったように、-gオプションを指定してコンパイルすると、Valgrind は失われたメモリの行番号を取得できます。

    編集(コメントに応じて):my_items動的に作成されたメニュー項目へのポインタの動的に割り当てられた配列です。つまり、動的メモリの 1 つのブロックがあり、動的に割り当てられた一連の ncurses 構造体 (メニュー項目) への一連のポインターが含まれています。したがって、完了後にクリーンアップするには、動的に割り当てられた ncurses 構造体をそれぞれ解放する必要があります。次に、それらの構造体へのポインターを保持していたメモリ ブロックを解放する必要があります。

    つまり、すべてのcallocまたmallocはは を必要としfree、すべてnew_itemは を必要free_itemとします。

    for (i = 0; i < n_choices; ++i) {
        free_item(my_items[i]);
    }
    free(my_items);
    
    于 2010-05-27T01:22:00.703 に答える
    1

    Valgrind に関する注意事項 (これは、Valgrind ユーザーのメーリング リストでよく取り上げられます):

    still reachable: 64,942 bytes in 262 blocks
    

    これは、終了時にまだ到達可能なブロックを参照しているだけmain()であり、(最新のカーネルでは) とにかく OS によって回収されます。

    free()exit が呼び出される前に割り当てられたすべてのブロックを明示的に実行することをお勧めしますが、これはtechnicallyメモリ リークではありません。終了時に到達する可能性があるからです。

    Josh Kellyが提案したように、直接的、間接的、そして失われた可能性のあるブロックに注目してください。これは、リークの可能性のある原因をすでに指摘した回答の補足にすぎません。

    于 2010-05-27T01:30:01.237 に答える
    0
    free_item(my_items[7]);
    free(my_items);
    
    于 2010-05-27T02:32:46.513 に答える
    0

    --leak-check=full で valgrind を実行してみてください。

    于 2010-05-27T01:23:24.683 に答える