質問
明らかにポインターを使用して、別の関数内から構造体を割り当てる必要があります。私はこの問題を何時間も見つめており、それを解決するために何百万もの異なる方法で試みました。
これはいくつかのサンプルコードです(非常に単純化されています):
...
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;
}
これにより、Alocate-Callの前後に同じアドレスが与えられます。
Before: -1079752900
In function: -1079752928
After: -1079752900
それはおそらくそれが関数にコピーを作っているからだと知っていますが、私は実際に私が議論として与えたポインターで作業する方法を知りません。 some_struct sの代わりにsome_struct *sを定義しようとしましたが、運はありませんでした。試してみました:
int allocate(some_struct **arg)
これは正常に機能します(割り当て機能も変更する必要があります)が、割り当てによると、宣言を変更することはできません。 some_struct s .. some_struct *sではありません。割り当て関数の目的は、それを割り当てることも含まれる構造体(some_struct)を初期化することです。
私が言及するのを忘れたもう一つのこと。割り当て関数のreturn0は一部のステータスメッセージ用に予約されているため、これを使用してアドレスを返すことはできません。
解決
これがあなたの先生が念頭に置いていたものであることを非常に疑っていますが、一連の合法的な変換を使用してチートすることができます。
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 */
}
これは、オブジェクトへのポインターがボイドポインターに暗黙的に変換される可能性があると言うCのルールに依存しています。
正式にはこれは未定義ですが、すべてが機能することはほとんどないことに注意してください。一方、オブジェクトのポインター値は、 void*
そして、紛失せずに戻って、言語にはそれを保証するものは何もありません some_struct*
保存できます some_struct**
喪失なし。しかし、それはうまく機能する可能性が非常に高いです。
あなたの先生はあなたに正式に違法なコードを書く以外に選択肢を与えませんでした。このような「不正行為」以外に他の選択肢があるとは思いません。
他のヒント
通常、ポインターを返します 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;
}
asと呼ばれる
some_struct *s;
allocate(&s);
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;
このようにすることはできません。値で構造体を宣言して、アドレスで変更することはできません。
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;
}
構造体の尖った値を変更する必要があります。したがって、別のレベルの間接が必要なため、structポインターにポインターを送信する必要があります。
まあ、Cは価値を使用します。つまり、関数が得られることを意味します コピー 彼らの議論のうち、それらのコピーに加えられた変更は、発信者のオリジナルに影響しません。
/* The allocation function */
int allocate(some_struct *arg) {
arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg");
return 0;
}
ここでは、some_struct sのアドレスを渡します。次に、そのアドレスを捨てて、Mallocによって返されたものに置き換えます。その後、戻ると、mallocの戻り値が永遠に失われ、メモリが漏れています。そして、あなたのsome_structは変更されていません。それはまだ初期化された乱数があり、それを印刷しました。
割り当て関数の署名を変更できない場合は、有用ではありません。そのポインターの値を変更できるように、ポインターのアドレスを取得するか、発信者が押し出すことができるポインターを返す必要があります。