0

以下は、字句解析器のコードでヘルパー関数として使用する小さなラムダ関数です。

auto buildnumber = [&line, &i] () -> Token* {
    Token* new_number = new Token(nullptr, number, line);

    char** after_number = nullptr;
    double* value = new double(std::strtod(i, after_number));

    printf("Value got: %f\n", *value);
    printf("Comparing it to 0\n");
    if (*value == 0.0) {
        printf("value was 0, comparing position to after number\n");
        if (i == *after_number) {
            printf("No number detected\n");
            delete value;
            delete new_number;
            return nullptr;
        }
    }

    printf("Value was different from 0, storing it in Token\n");
    new_number->value = (void*) value;
    printf("Advancing position\n");
    i = *after_number;
    printf("Returning\n");

    return new_number;
};

ここに少し背景があります: typeの属性、 typeの属性、およびカスタム enum の属性をToken持つクラスです。最初の行では、値の null ポインター (まだ作成する必要があるため)、列挙型の値(このトークンはその型であるため)、およびキャプチャした現在の行をコンストラクターに渡す新しいものを初期化します。ラムダで。valuevoidlineinttypetoken_typetoken_typenumber

iconst char*調べている現在の文字を指す型のポインタです。このラムダ関数を呼び出すと、印刷可能な文字を指すことが保証されます。

printfデバッグ用です。

だから私がやろうとしているのはToken、内部型の新しいものを作成することnumberです。strtod現在の位置から数を構築できるかどうかを尋ねます。次に、strtodゼロ以外の値が返されたかどうかを確認します。その場合、その値を new に格納し、Token指している文字の位置を数値の直後の文字に進め、 を返しますToken

strtod代わりにゼロ値が返された場合、ゼロが実際の 0 が見つかったためなのか、それとも数値を構築できなかったのかを再確認する必要があります。そのため、数字の後の文字へのポインターが現在の位置と同じ文字を指しているかどうかを確認します。真の場合、strtokそのポインターが進められなかったことを意味し、数字がまったく見つからなかったことを意味します (そして、割り当てられた文字を削除します)。値を返し、それを通知するために null ポインターを返します)。それ以外の場合は、0 が見つかったことを意味するので、それを保存し、進めて、戻ります。

問題は、私が deferenceしようとするたびに文字どおり Segfault エラーが発生するafter_numberことです。またはのような文字列を指しているときにそれを呼び出すと、出力後に segfault が発生します。buildnumberi"111""Advancing position"i"+0.0""abc()""Value was 0, comparing position to after number"

それはなぜです?が指しているポインタはどうなりますafter_numberか? 私は何を間違っていますか?

4

1 に答える 1

6

after_number文字ポインターへのポインターとして定義し、それが実際には有用なものを指していないときに、それを直接使用しました。

それに関する問題は、基本的にエンドポインターstrtodを実際に保存nullptrしないように指示していることです(それを保存するアドレスとして提供したため)、とにかくそれを逆参照しようとします-それはまだnullptrありますしたがって、未定義の動作になります。

正しい方法は次のとおりです。

char *after_number;
double *value = new double(std::strtod(i, &after_number));

これにより、実際には、エンド ポインターを配置できる変数が作成され、そのアドレスが に渡されます。終了時に、数値評価を停止した終了文字へのポインタを保持します (うまくいけば、それは提供された実際の文字列の末尾へのポインタになります.char *strtodstrtodafter_number*after_number == '\0'

于 2016-09-18T08:53:13.830 に答える