1

Herbert Schildt の C++ リファレンスという本を読んでいますが、この本の c セクションに次のようなスタックの例があります。

#include <stdio.h>
#include <stdlib.h>

#define SIZE 50

void push(int i);
int pop(void);

int *tos, *p, stack[SIZE];

int main(void) {
    tos = stack;
    p = stack;
    // push, pop, etc
    return 0;
}
void push(int i) {
    p++;
    if (p==(tos+SIZE)) {
        printf("Stack overflow");
        exit(1);
    }
    *p = i; 
}
int pop(void) {
    if (p==tos) {
        printf("Stack Underflow");
        exit(1);
    }
    p--;
    return *(p+1);
}

上記のスタック実装は、値を格納するために TOS を使用しません。最初の値は TOS+1 に格納されます。メモリ空間を浪費しているように見えるので、なぜそうするのかわかりませんでした。

スペースを無駄にしない以下の例に書き直しました(編集:選択した回答を読んでください-以下のコードは疑わしいです!):

#include <stdio.h>
#include <stdlib.h>

#define SIZE 5

void push(int i);
int pop(void);

int *tos, *p, stack[SIZE];

int main(void) {
    tos = stack;
    p = stack;
    // push, pop, etc
    return 0;
}
void push(int i) {
    if (p==(tos+SIZE)) {
        printf("Stack overflow");
        exit(1);
    }
    *p = i; 
    p++;
}
int pop(void) {
    p--;
    if (p<tos) {
        printf("Stack Underflow");
        exit(1);
    }
    return *p;
}

Schildt の実装が TOS の位置を使用しない理由はありますか?

どうもありがとう。

4

2 に答える 2

6

元のコードはスタイルが悪いものの、動作が明確に定義されています。変更されたコードの動作は未定義です。

スタックが空かどうかをテストするには、ポインターを変更する前にポインターの比較を行う必要があります。比較の結果、スタックが空であることが示された場合は、ポインターをデクリメントしないでください。

pを指している場合stack[0]、その後p--;逆参照しない場合でも、未定義の動作がありますp。配列の先頭より前を指すポインター、または配列の末尾を超えた複数の要素を指すポインターを合法的に形成することはできません。(配列の終わりのすぐ後ろにポインターを合法的に形成することはできますが、逆参照することはできません。)

ほとんどのスタックベースの実装で「機能する」可能性があります。これは、これがテストで見つけるのが難しいバグであることを意味します。

元のコードの問題:tos最初は の要素 0 を指しており、または()stackによって変更されていません。なぜそれが宣言されていないのか、なぜ呼び出されているのか (「スタックのトップ」を意味する名前ですが、それが使用されている)、なぜその変数を持っているのか、それとも同じ値を与えるのですか? これらの質問に対する良い答えがあるとは思えません。push()popconsttospstack&stack[0]

また、元のコードでexit(1);は、失敗を通知する移植可能な方法ではありません (成功を通知するシステムがあります)。exit(EXIT_FAILURE);故意に移植性のないコードを書いている場合を除き、これは正しい方法です。(これは、Unix ライクなシステムでのみ使用されるプログラムを作成している場合には意味がありますが、言語チュートリアルの例を作成している場合には意味がありません)。

私のアドバイス: Google で "Schildt" を検索して、C および C++ の本の著者としての著者の評判が非常に悪いことを知り、その言語を実際に理解している人が書いた本を見つけてください。

(この回答の以前のバージョンでは、Schildt のものではないいくつかのエラーを誤って非難していました。それについてはお詫びします。それでも、彼の本を避けることをお勧めします。)

于 2013-05-28T20:03:57.537 に答える
1

あなたのようにスタックの前にメモリ内のランダムな場所を指すのではなく、 p を常にスタック内のどこかに向けようとしているようです。無効な p がどこにも逆参照されていない限り (つまり、間違っている場合に exit を呼び出しているため)、大きな違いはないはずです。

于 2013-05-28T19:40:49.293 に答える