2

明らかにポインターを使用して、別の関数内から構造体を割り当てる必要があります。私はこの問題を何時間も見つめ、何百万通りもの方法で解決しようとしました。

これはいくつかのサンプルコードです (非常に単純化されています):

...
some_struct s;
printf("Before: %d\n", &s);
allocate(&s);
printf("After: %d\n", &s);
...

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg);

return 0;
}

これにより、割り当て呼び出しの前後で同じアドレスが得られます。

Before: -1079752900
In function: -1079752928
After: -1079752900

おそらく関数内でコピーを作成するためだと思いますが、引数として指定したポインターを実際に操作する方法がわかりません。some_struct の代わりに some_struct * を定義しようとしましたが、うまくいきませんでした。私は試しました:

int allocate(some_struct **arg)

これは問題なく動作します(割り当て関数も変更する必要があります)が、割り当てに従って宣言を変更することはできず、* argである必要があります。宣言するだけでよい場合は、最も正しいでしょう。 some_struct s.. some_struct * ではありません。割り当て関数の目的は、構造体 (some_struct) を初期化することです。これには、割り当ても含まれます。

言い忘れたことをもう一つ。割り当て関数の戻り値 0 は、一部のステータス メッセージ用に予約されているため、これを使用してアドレスを返すことはできません。

4

6 に答える 6

4

通常、次のポインタを返しますallocate

void * allocate()
{
    void * retval = malloc(sizeof(some_struct));
    /* initialize *retval */
    return retval;
}

パラメータでそれを返したい場合は、パラメータへのポインタを渡す必要があります。これは some_struct へのポインターであるため、ポインターにポインターを渡す必要があります。

void allocate (some_struct ** ret)
{
    *ret = malloc(sizeof(some_struct));
    /* initialization of **ret */
    return;
}

と呼ばれる

some_struct *s;
allocate(&s);
于 2010-04-08T15:56:37.187 に答える
1

これがあなたの先生が考えていたことだとは思えませんが、一連の正当な型変換を使用してごまかすことができます。

   int allocate(some_struct *arg) 
   /* we're actually going to pass in a some_struct ** instead. 
      Our caller knows this, and allocate knows this.  */
   { 
      void *intermediate = arg;  /* strip away type information */
      some_struct **real_deal = intermediate;  /* the real type */
      *real_deal = malloc(sizeof *real_deal); /* store malloc's return in the 
                                                 object pointed to by real_deal */
      return *real_deal != 0;  /* return something more useful than always 0 */
   }

次に、呼び出し元も同じことを行います。

   {
      some_struct *s; 
      void *address_of_s = &s; 
      int success = allocate(address_of_s); 
      /* what malloc returned should now be what s points to */
      /* check whether success is non-zero before trying to use it */
   }

これは、オブジェクトへの任意のポインターが暗黙的に void ポインターに変換され、その逆も損失なしで行われるという C の規則に依存しています。

正式にはこれは定義されていませんが、ほぼ確実に機能することに注意してください。どのオブジェクト ポインタ値も損失なしで a に変換できる必要がありますが、 a が損失なしで aを格納できることvoid*を保証する言語はありません。しかし、問題なく動作する可能性は非常に高いです。 some_struct*some_struct**

あなたの先生は、正式に違法なコードを書く以外に選択肢を与えませんでした。このような「ごまかし」以外の選択肢はないと思います。

于 2010-04-08T16:13:25.273 に答える
1
int func(some_struct *arg) {
    arg = malloc(sizeof(some_struct));
    ... 
}

ここでは、malloc の結果をローカルarg変数に代入するだけです。ポインターは C では値によって渡され、ポインターのコピーが関数に渡されます。この方法で呼び出し元のポインターを変更することはできません。ポインタとそれが指すものの違いに注意してください。

さまざまなオプションがあります。

関数からポインターを返します。

 some_struct *func(void) {
    arg = malloc(sizeof(some_struct));
    ...
    return arg;
}
...
some_struct *a = func();

呼び出し元で構造体を割り当てます。

 int func(some_struct *arg) {
    ...
    arg->something = foo;

}
... 
some_struct a;
func(&a);

または動的に割り当てる

some_struct *a = malloc(sizeof *a);
func(a);

呼び出し元ポインターへのポインターを使用する:

 int func(some_struct **arg) {
    *arg = malloc(sizeof **arg);

}
... 
some_struct *a;
func(&a);

グローバル変数を使用する(醜い..)

 some_struct *global;
 int func(void) {
    global = malloc(sizeof *global);

}
 ... 
some_struct *a;
func();
a = global;
于 2010-04-08T16:00:37.237 に答える
0

このようにすることはできません。構造体を値で宣言してから、アドレスで変更することはできません。

于 2010-04-08T15:53:32.097 に答える
0
some_struct *s;
printf("Before: %d\n", s");
allocate(&s);
printf("After: %d\n", s");
...

/* The allocation function */
int allocate(some_struct **arg) {

*arg = malloc(sizeof(some_struct));
printf("In function: %d\n", *arg");

return 0;
}

構造体の指定された値を変更する必要があります。したがって、別のレベルの間接化が必要なため、ポインターを構造体ポインターに送信する必要があります。

于 2010-04-08T15:53:52.470 に答える
0

C は値渡しを使用します。つまり、関数は引数のコピーを取得し、それらのコピーに変更を加えても、呼び出し元の元のファイルには影響しません。

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg");

return 0;
}

ここで、 some_struct のアドレスを渡します。次に、そのアドレスを破棄し、malloc によって返されたものに置き換えます。その後、戻ると、malloc の戻り値が永久に失われ、メモリ リークが発生します。そしてあなたの some_struct sは変更されていません。初期化された乱数が残っており、それを印刷しました。

割り当て関数の署名を変更できない場合、それは決して役に立ちません。ポインターの値を変更できるようにポインターのアドレスを取得するか、呼び出し元が隠しておくことができるポインターを返す必要があります。

于 2010-04-08T15:59:52.433 に答える