0

私は現在、C に慣れるために小さなアプリケーションを作成しています (最後に何かを書いてからしばらく経ちました)。ほとんどの人がそうであるように、メモリ割り当ての問題に遭遇しましたが、これは理解できません。

コードは、さまざまなパネル、ウィンドウ、および関連するタイトルの設定を中心に展開します。正確には、私が問題を抱えているタイトル文字列のメモリ割り当てです。

ベースは、以下を含む構造です。

struct TFB_PANEL
{
    WINDOW *window;
    char *title;
};

これは、ヘッダー ファイルで次のように typedef されます。

typedef struct TFB_PANEL TfbPanel;

関連する C ファイルにはTFB、固定サイズの配列を初期化する次のメソッドがあります。

int tfb_init()
{
    if (!_initialised) {
        return -1;
    }

    int i;
    for (i = 0; i < TYPE_MAX; i++) {
        TFB[i] = malloc(sizeof(TfbPanel*));
        TFB[i]->title = calloc((strlen(TYPES[i]) + 18), sizeof(char*));
        switch(i)
        {
            case A:
                sprintf(TFB[i]->title, " %s | r | h | s | t ", TYPES[i]);
                break;
            case B:
                sprintf(TFB[i]->title, " f | %s | h | s | t ", TYPES[i]);
                break;
            case C:
                sprintf(TFB[i]->title, " f | r | %s | s | t ", TYPES[i]);
                break;
            case D:
                sprintf(TFB[i]->title, " f | r | h | %s | t ", TYPES[i]);
                break;
            case E:
                sprintf(TFB[i]->title, " f | r | h | s | %s ", TYPES[i]);
                break;
        }

        TFB[i]->window = tfb_create_window(i);
    }
    return 0;
}

Cの初期化時にエラーが発生するようになりました。A と B は 25 文字の長さに正しく設定されます。一方、Cには初期化後に24文字が含まれている必要がありますが、代わりに(tfb_create_window内から)受信します

Program received signal EXC_BAD_ACCESS, Could not access memory
Reason: 13 at address 0x0000000000000000
0x00007fff930b9390 in strcmp()

スタックを調べると、TFB[C] が正しく初期化されていることがわかりますが、タイトル要素はそうではありません。calloc を呼び出したことがないかのように、これには null 要素が含まれています。

これでどこが間違っているのか、またはAとBが正しく初期化されるのにCがアプリを強制終了する理由を誰かが説明してください。今朝の午前 6 時頃まではすべてが順調に進んでいましたが、それ以降は下り坂になっています。

それが役立つ場合は、次のように への呼び出しとtfb_create_windowへの呼び出しで定義されます。_create_windowtfb_get_title

char *tfb_get_title(int type)
{
    if (type >= TFB_MAX) {
        return (char*)NULL;
    }
    return TFB[type]->title;
}

WINDOW *tfb_create_window(int type)
{
    int height = ((LINES - WIN_OFFSET_Y) / 3);
    char *title = tfb_get_title(type);
    return _create_window(height, WIN_SIDEBAR_X, WIN_OFFSET_Y, 0, COLOUR_MAIN, title);
}

WINDOW *_create_window(int height, int width, int starty, int startx, int color, const char *title)
{
    WINDOW *window;
    window = newwin(height, width, starty, startx);
    box(window, 0, 0);
    mvwprintw(window, 0, 2, title);
    wbkgd(window, COLOR_PAIR(color));
    return window;
}
4

2 に答える 2

1

このコードには多くのバグがありますが、最も深刻なのは、 のsizeof(Type*)代わりに使用するバグですsizeof(Type)。後者はオブジェクトの実際のサイズで、最初はそのオブジェクトへのポインターのサイズ (64 ビット マシンでは 8 バイト) です。

つまり、 にmalloc(sizeof(TfbPanel*))割り当てるメモリが少なすぎるTfbPanelため、残りのプログラムの動作は未定義です。

これcalloc()も同じように間違っていますが、重要ではありません。必要なメモリの 8 倍を割り当てるからです。

ただし、calloc()呼び出しには別のバグがあります。呼び出しstrlen()に追加するペイロード文字数である の結果に 18 を追加しますsprintf()strlen()の結果には null バイトが含まれていないため、これは少なすぎます。

POSIX-2008 準拠の libc (Linux システムの glibc など) を使用できる場合は、asprintf()代わりに を使用できますsprintf()。これにより、結果の文字列に十分なスペースが自動的に malloc され、起こりうるバッファー サイズ エラーが回避されます。その関数を使用できない場合は、少なくともsnprintf()未割り当てメモリへのアクセスを避けるために使用してください。

于 2013-09-14T10:27:56.700 に答える
0

gdb を使用して次の行に進むと、次のようになります。

sprintf(TFB[i]->title, " f | r | %s | s | t ", TYPES[i]);

TYPES[i] の値は?

于 2013-09-14T09:56:54.497 に答える