1

ポインターが参照によって関数に渡される方法に少し混乱していますか?

たとえば、ここに私が書いたコードがあります(関数全体をコピーしたのではなく、関連する部分だけをコピーしました)

  metadata * removeBlock(metadata *first)
{

    metadata *temp = first;
    if(first == NULL || first -> prev == NULL)
        {
            first -> in_use = 1;
            first = NULL;
            return temp;
        }
}

私が欲しいのは、関数が戻るときに、渡された元の値を NULL に設定する必要があるということです。関数を呼び出す方法は次のとおりです (このコード行は、ヒープ内の領域からメタデータ構造をプルします。正しく動作します。デバッグして、この後、構造体が実際に有効なメタデータ構造体を指していることを確認しました)

metadata *strct = ((metadata *)ptr - sizeof(metadata));
removeBlock(strct);

ただし、このメソッドが戻った後も、strct は関数に渡す前と同じ値のままです。&strct を渡そうとしましたが、無効なキャスト例外がスローされました。構造体を引数として渡す最良の方法は何ですか?

ありがとうございました。

4

5 に答える 5

2

あなたが望むのは良い設計だとは思いません-関数のユーザーがポインターをnullに設定したい場合(なぜですか?)、関数からの戻り値を使用して値をリセットすることは理にかなっています。

とにかく、次のように、ポインターからポインターへのポインターが必要になります。

metadata* removeBlock(metadata** first) {

    metadata* temp = *first;
    if( temp == NULL ) return temp;

    if( temp->prev == NULL ) {
        temp->in_use = true;
        *first = NULL;
    }
    return temp;
}

metadata* strct = ((metadata*)ptr - sizeof(metadata));
removeBlock(&strct);
于 2013-04-26T01:27:15.953 に答える
1

@SheerFish が言ったように、C にあるのは値渡しだけです。ただし、ポインターを使用して参照渡しをシミュレートすることはできます。

void func(struct foo **fooptr) { *fooptr = 0; }
int main(int argc, char **argv) { struct foo *fooptr; func(&fooptr); }

これは、変数の値へのポインターを渡していptrます (その値がポインターであったかどうかは気にしないでください) *ptr。この手法はアドレス渡しと呼ばれることもあり、参照渡しに最も近い C 言語です。

于 2013-04-26T01:27:45.560 に答える
1

「C の参照」で渡す場合は、->/** と * による参照と逆参照に注意する必要があります。私が書いたこのコードは少し役立つかもしれません

    int delete_node(struct node** head, int target)
    {

        if(*head == NULL)
            return 0;                                                    
    if((*head)->data == target)
        {
            temp = *head;
            *head = (*head)->next;
            free(temp);
            return 1;
        }                                                    
} 

関数呼び出し:

 delete_node(&head, data)

直接メモリ ポインター操作を行っています。メモリ内の構造体の場所を投げて、それを逆参照してから、そのメモリの場所の値を変更しています。

于 2013-04-26T01:29:00.543 に答える
1

詳細をすべて読んだわけではありませんが、この部分は間違っていると飛び出しました。

(metadata *)ptr - sizeof(metadata)

ポインター演算は型の単位で行われsizeofますが、測定値はバイト単位で得られます。

したがって、あなたが言おうとしているのは次のことだと思います。

(metadata *)(((char*)ptr) - sizeof(metadata))

これはまた、実行しているマシンについていくつかの仮定を立てています。つまりmetadata、この使用のためにフィールドが適切に整列されるようにするために、パディングが必要になる場合があります。がワード サイズの倍数でない場合sizeof(metadata)、これは多くのアーキテクチャで失敗します。(ただし、x86 では、パフォーマンス コストや、アトミック操作がフィールドで機能しないなどの影響はありますが、スライドさせます。)

于 2013-04-26T01:31:53.207 に答える
1

ポインタは値で渡されます。c の中のものはすべて値渡しです。そのため、関数に渡されるポインターを変更するには、 を受け取る必要がありますmetadata **first

さらに、使用する必要があります

metadata *strct = ((metadata *)ptr - 1);

ポインター演算は sizeof(*p) の倍数で行われるためです。したがって、これは

metadata *strct = ((metadata *)((char*)ptr - sizeof(metadata)));
于 2013-04-26T01:33:08.023 に答える