2016-07-11 18 views
0

私は学習目的でC言語で汎用スタックを実装しています。これは、それのポップ機能である:関数のトップスタック実装C

void* StackPop(Stack *s) { 
    assert(s != NULL); 
    assert(s->logicalLen > 0); // there must be at least on element 
    void *object = (char*) s->elems + (s->logicalLen--) * s->elemSize; // decrement logical length 
                     // on the fly 
    return object; 
} 

この場合(StackPopは)私が呼び出し元に一番上にオブジェクトの所有権を移転しなければならないことを私には明らかです。したがって、呼び出し元がオブジェクトを使って何をすべきかを決めるため、汎用ポインタを返すのは問題ありません。 一方、先頭の要素を返すStackTop()関数を記述したいと思います。ここで私は不安を抱いています。私は、両方の関数が、クライアントの変更を望まないので、スタックのサイズを減らしたり、ポインタを返さないようにしてください。どのように上位要素のコピーのみを渡すのですか?引数としてジェネリックポインタを唯一のオプションとして受け取り、そのアドレスに深いコピーを作成しますか?

void StackPop(void *target) { 
    // make a deep copy into target address with memcopy or whatever? 
} 

もっと良いアプローチがありますか?

+0

無関係に、私は 'StackPop'を書いて、健全性と他のすべての体操の前に空のスタックをチェックしてみましょう。そして、言語を選んでください:適合と形はCを示唆します。 C++ではありません。 – WhozCraig

+0

@WhozCraig真実、私はそれをすぐに書きました。私は現時点でエラーチェックに多くの注意を払っていません。私はそれを修正します。 – blade

+1

あなたの問題を解決するための「適切な」方法は、ポップ関数が*何かを返さないようにすることです(エラー状態を除いて)。トップファンクションを介して "トップ"オブジェクト(ある場合)へのアクセスのみを許可します。呼び出し元がオブジェクトのコピーを望むなら、それもそうです。彼らはポップ前に1つを作ることができます。これは、偶然にもC++の標準ライブラリコンテナアダプタ 'std :: stack 'の動作とは異なります。そして、btw、 'assert'はリリースコードではオペレーションにはならないので、あなたが気づいていない場合に備えて、論理エラーチェックが必要です。 – WhozCraig

答えて

1

私はそれを言う誰

...両方の機能は非常に似ている必要があることを知っていますか?

あなたはスタックを設計しているので、スタックを使用するためのすべてのルールを自由に定義することができます。たとえば、NULLポインタのチェックをすべてスキップして、NULLポインタを使用して関数xxxを呼び出すと、定義されていない動作が発生することをドキュメントに記述することができます。最終的には、あなたのスタックがどんなものになっているかによって異なります。

StackTopの機能にも同じことが言えます。ルールは自由に設定できます。

私にとってあなたのStackPopは論理的に間違っているようです。 logicalLenをデクリメントして論理的に解放されたメモリ領域へのポインタを返すことは、私が期待することではありません。しかし、StackPopによって返されたポインタが次のStackPushで無効になることをドキュメントに書くことができます。 (C++では、いくつかのコンテナにイテレータ/ポインタの制限があります)。

StackTopでも同様です。先頭の要素へのポインタを返すだけで、次のStackPopまで有効です。

あなたのデザインはあなたのルールです。

私はむしろ、このように行うだろう:intは、エラー値を返すためにある3つのすべてのケースにおいて

int push(stack* s, void* o) 
{ 
    // memcpy contents of o to next free location 
    // increment number of elements held 
} 

int top(stack* s, void* o) 
{ 
    // memcpy top element to o 
} 

int pop(stack* s) 
{ 
    // decrement number of elements held 
} 

パフォーマンスを向上させるには、次のような関数を使用できます。 ptopは、先頭の要素へのポインタを返しました(有効な次のポップまで有効です)。 deep copyについて

あなたは、一般的なスタック内の深いコピーを行うことができます方法はありません。ユーザがポインタを持つスタックに何かを置く場合、ユーザはそれ自身で処理する必要があります。

+0

ユーザーがどのように行うべきかを指定する関数ポインタを指定した場合、ディープコピーを実行できます。 – Hurkyl

+0

@Hurkyl - そうですね。個人的に私はまだそれをユーザーに任せておきますが、それは設計上の問題です。すでに言及したように、デザイナーとしてルールを設定します。これには正義も間違いもありません。あなたの現在のニーズに最も適しているのは単なる質問です。 – 4386427