6

私は(初心者として)Cでアプリケーションを作成していますが、可変長配列を含む構造体内で破損したデータを取得するのに苦労しています。cprogramming.comおよびcert.og/secure-codingのフォーラム投稿で説明されている同様の問題を見つけました。正しい解決策を見つけたと思いましたが、そうではないようです。

構造体は次のようになります。

typedef struct {
    int a;
    int b;
} pair;

typedef struct {
    CommandType name;
    pair class;
    pair instr;
    pair p1;
    pair p2;
    pair p3;
    CommandType expected_next;
    char* desc;
    int size;
    pair sw1;
    pair sw2;
    pair* data;
} command;

問題のあるものは「コマンド」です。「コマンド」の任意のインスタンス(または正しいフレーズ)に対して、異なるフィールドが設定されますが、ほとんどの場合、異なるインスタンスではありますが、同じフィールドが設定されます。

私が抱えている問題は、expected_next、name、sw1、sw2、size、およびdataフィールドを設定しようとしたときです。そして、破損しているのはデータフィールドです。このような構造体にメモリを割り当てています。

void *command_malloc(int desc_size,int data_size)
{
    return malloc(sizeof(command) +
                  desc_size*sizeof(char) +
                  data_size*sizeof(pair));
}

command *cmd;
cmd = command_malloc(0, file_size);

しかし、結果のcmdを(かなり)印刷すると、データフィールドの中央がランダムなゴミのように見えます。gdbを使用して手順を進めたところ、正しいデータがフィールドに読み込まれていることがわかります。コマンドが破損するのは、コマンドが別の関数に渡されたときだけのようです。このコードは、次のような関数内で呼び出されます。

command* parse(char *line, command *context)

そして、プリティプリントは別の機能で発生します。

void pretty_print(char* line, command* cmd)

私は物事を正しくやっていると思っていましたが、どうやらそうではありませんでした。私が知る限り、私は構造体の他のインスタンスを大丈夫に構築します(そして私はこれのためにそれらのアプローチを複製しました)が、それらには可変長配列が含まれておらず、それらのきれいなプリントはうまく見えます-それは彼らが私に関係しているからです破損している可能性もありますが、破損はそれほど明白ではありません。

私が書いているのは実際にはパーサーなので、コマンドは解析関数(現在の状態を記述し、パーサーに次に何を期待するかについてのヒントを与える)に渡され、次のコマンド(入力「行」から派生)は次のようになります。戻ってきた。「context」は、解析関数の最後でfree-dされ、新しいコマンドが返されます。これは、入力の次の「行」とともに「parse」に戻されます。

なぜこれが起こっているのかについて誰かが何か提案できますか?

どうもありがとう。

4

2 に答える 2

11

構造体にメモリを割り当てると、ポインタサイズのみが*descに割り当てられます。誰かがすでに指摘しているように、descが指すスペース(配列の内容)にメモリを割り当てる必要があります。私の答えの目的は、それを行うためのわずかに異なる方法を示すことです。ポインター*descを使用すると、構造体のサイズが1ワード(sizeofポインター)増加するため、構造体の可変長配列ハックを安全に実行して、構造体のサイズを小さくすることができます。

構造は次のようになります。desc[]が構造の最後までプルダウンされていることに注意してください。

typedef struct {
    CommandType name;
    pair class;
    pair instr;
    pair p1;
    pair p2;
    pair p3;
    CommandType expected_next;
    int size;
    pair sw1;
    pair sw2;
    pair* data;
    char desc[];
} command;

ここで、1.配列サイズも含むコマンドにメモリを割り当てます。

 command *cmd = malloc(sizeof(command) + desc_length);
  1. descを使用してください:

    cmd-> desc [desc_length -1] ='\ 0';

このハックは、メンバーが構造体の最後にある場合にのみ機能し、構造体のサイズを節約し、ポインターの間接参照を節約します。配列の長さが構造体インスタンス固有の場合に使用できます。

于 2014-05-02T04:24:46.690 に答える
9

descとdataを別々に割り当てる必要があります。

structコマンド*cmdを割り当てると、decsとdataのポインターにメモリーが割り当てられます。説明とデータは別々にマロックする必要があります。

だからあなたのコマンドを割り当てます

command *cmd =  malloc(sizeof(command));

次に、データ用のメモリまたはdesc
用のdescの例を割り当てます。

cmd->desc = malloc( sizeof(char )*100);
于 2013-03-04T21:40:10.930 に答える