-1

文字列を複雑なクラスに変換するためにここにあるコード...

void StrtoComplex(char *temp)
    {
        int i;

        for(i = 0; i < strlen(temp); i++)
        {
            if(temp[i] == 'j' || temp[i] == 'i')
                break;
        }

        real = atof(temp);//takes till the last valid char so after + or whitespace it ignores
        imag = atof(temp + i + 1);

        sprintf(complexStr, "%f +j%f", real, imag);
    }

コンパイルされますが、実行するとすべてのステートメントが実行されます(適切な値で....complexStrにも正しい文字列があります...)が、sprintfステートメントに戻り、アクセスが拒否されたと言います

ここに残りのコードがあります....

#include <iostream>
#include <conio.h>
#include <string.h>

#include <cstdlib>
#include <cctype>
#include <cstring>

//Most string operations require the std namespace
using namespace std;


//namespace helps divide global access into subaccess blocks providing data encapsulation
//If required to use any defined within a namespace use scope resolution
namespace Complex
{
    /*This is the Complex class which is asscociated with its corresponding string holding
    the complex representation
    DATA MEMBERS:
    real --------- real part of the complex number
    imag --------- imaginary part of the complex number
    complexstr --- string stream which holds the complex representation
    MEMBER FUNCTIONS
    */
    class complex
    {
        double real;
        double imag;
        char complexStr[50];

    public:
        complex(double re = 0, double im = 0)
        {
            real = re;
            imag = im;
            sprintf(complexStr, "%f +j%f",real,imag);
        }

        complex(complex &t)
        {
            real = t.real;
            imag = t.imag;
        }

        void StrtoComplex(char *temp)
        {
            int i;

            for(i = 0; i < strlen(temp); i++)
            {
                if(temp[i] == 'j' || temp[i] == 'i')
                    break;
            }

            real = atof(temp);//takes till the last valid char so after + or whitespace it ignores
            imag = atof(temp + i + 1);

            sprintf(complexStr, "%f +j%f", real, imag);
        }

        friend complex operator+(complex &a, complex &b);
        friend complex operator-(complex &a, complex &b);
        friend complex operator-(complex &a);
        friend complex operator*(complex &a, complex &b);
        friend complex operator/(complex &a, complex &b);
        friend ostream &operator<<(ostream &s, complex &t);
        friend istream &operator>>(istream &s, complex &t);
    };

    //overloading + to add complex numbers
    complex operator +(complex &a, complex &b)
    {
        complex t;
        t.real = a.real + b.real;
        t.imag = a.imag + b.imag;
        sprintf(t.complexStr, "%f +j%f", t.real, t.imag);
        return(t);
    }
    //overaloading - to subtract 2 complex no's
    complex operator -(complex &a, complex &b)
    {
        complex t;
        t.real = a.real - b.real;
        t.imag = a.imag - b.imag;
        sprintf(t.complexStr, "%f +j%f", t.real, t.imag);
        return(t);
    }

    //overloading unary -
    complex operator -(complex &a)
    {
        complex t(-a.real, -a.imag);
        sprintf(t.complexStr, "%f +j%f", t.real, t.imag);
        return(t);
    }

    //overloading * to multiply 2 complex no's
    complex operator *(complex &a, complex &b)
    {
        complex t;
        t.real = (a.real*b.real) - (a.imag*b.imag);
        t.imag = (a.real*b.imag) + (a.imag*b.real);
        sprintf(t.complexStr, "%f +j%f", t.real, t.imag);
        return(t);
    }
    //overloading / to divide 2 complex no's
    complex operator /(complex &a, complex &b)
    {
        complex t;
        t.real = ((a.real*b.real) + (a.imag*b.imag))/(b.real*b.real + b.imag*b.imag);
        t.imag = ((a.real*b.imag) - (a.imag*b.real))/(b.real*b.real + b.imag*b.imag);
        sprintf(t.complexStr, "%f +j%f", t.real, t.imag);
        return(t);
    }

    ostream &operator<<(ostream &s, complex &t)
    {
        s<<t.complexStr;
        return s;
    }

    istream &operator>>(istream &s, complex &t)
    {
        char *temp;

        s>>temp;
        t.StrtoComplex(temp);
        return s;
    }
}

namespace Discrete
{
    using Complex::complex;
    class signal
    {
        complex *sig_Data;

        int range_start, range_end, zero_pt;

    public:
        signal()
        {
            sig_Data = NULL;
            range_start = range_end = zero_pt = 0;
        }

        signal(complex i)
        {
            sig_Data = new complex(i);
            range_start = range_end = zero_pt = 0;
        }

        signal(int r_start, int r_end, int z_pt)
        {
            range_start = r_start;
            range_end = r_end;
            zero_pt = z_pt;
            int arr_ind = r_end - r_start;

            sig_Data = new complex [arr_ind];
        }

        signal(signal &s)
        {
            sig_Data = s.sig_Data;
            range_start = s.range_start;
            range_end = s.range_end;
            zero_pt = s.zero_pt;
        }

        void StrtoSig(char *temp)
        {
            int arr_ind = 0;
            char *tok;

            if(!*temp) return;

            tok = temp;
            zero_pt = 0;
            //
            int flag;

            for(int i = 0; i < (flag = strlen(temp)); i++)
            {
                tok++;
                if(*tok == '^') zero_pt = arr_ind;
                if(*tok == ',') arr_ind++;
            }
            range_start = 0 - zero_pt;
            range_end = arr_ind - zero_pt;

            sig_Data = new complex [arr_ind];
            tok = temp+1;
            for(int i = 0; i <= arr_ind; i++)
            {
                if(*tok == '^') tok++;
                sig_Data[i].StrtoComplex(tok);
                while(*tok != ',' || *tok != '}'|| *tok != '\0') tok++;
            }
        }

        complex operator[](int i)
        {
            if(i >= range_start && i <= range_end) return sig_Data[zero_pt+i];
            else return complex(0);
        }

        void timeScale(float t)
        { 
            if(t!=0)
            {
                int range = abs((int)((range_end - range_start)/t));
                int flag = 0;
                complex *sig=new complex[range];
                for(int i = 0; i < range; i++)
                {   
                    if(((long)(range_start + i)/t) == (range_start + i)/t)
                        sig[flag++] = sig_Data[i];
                }
                sig_Data = sig;
                range_start = (range_start)/t;
                range_end = (range_end)/t;
                zero_pt = (zero_pt)/t;
            }
            else
            {
                cout<<"time scaling not possible. Scaling factor is invalid.";
                return;
            }
        }

        //time shifting function
        void timeShift(int i)
        {
            if(i != 0)
            { 
                range_start -= i; 
                range_end -= i;
                zero_pt += i;
            }
            return;
        }

        friend signal operator+(signal &a, signal &b);
        friend signal operator-(signal &a, signal &b);
        friend signal operator-(signal &a);
        friend signal operator*(signal &a, signal &b);

        friend ostream &operator<<(ostream &s, signal &t);
        friend istream &operator>>(istream &s, signal &t);
    };

    //Overloading + operator
    signal operator+(signal &a, signal &b)
    {
        int r_start = min(a.range_start, b.range_start);
        int r_end = max(a.range_end, b.range_end);
        int z_pt = max(a.zero_pt, b.zero_pt);
        signal temp(r_start, r_end, z_pt);
        for(int i = r_start; i < r_end; i++)
        {
            temp[i] = a[i] + b[i];
        }
        return temp;
    }

    //Overloading - operator
    signal operator-(signal &a, signal &b)
    {
        int r_start = min(a.range_start, b.range_start);
        int r_end = max(a.range_end, b.range_end);
        int z_pt = max(a.zero_pt, b.zero_pt);
        signal temp(r_start, r_end, z_pt);
        for(int i = r_start; i < r_end; i++)
        {
            temp[i] = a[i] - b[i];
        }
        return temp;
    }

    //Overloading unary- operator
    signal operator-(signal &a)
    {
        signal temp = a;
        for(int i = a.range_start; i < a.range_end; i++)
        {
            temp[i] = -a[i];
        }
        return temp;
    }

    //Overloading * operator
    signal operator*(signal &a, signal &b)
    {
        int r_start = min(a.range_start, b.range_start);
        int r_end = max(a.range_end, b.range_end);
        int z_pt = max(a.zero_pt, b.zero_pt);
        signal temp(r_start, r_end, z_pt);
        for(int i = r_start; i < r_end; i++)
        {
            temp[i] = a[i] * b[i];
        }
        return temp;
    }

    ostream &operator<<(ostream &s, signal &t)
    {
        int arr_ind = t.range_end - t.range_start;
        s<<"{";
        for(int i = 0; i < arr_ind; i++)
        {
            if(i == t.zero_pt)
                s<<" ^"<<t[i];
            else
                s<<" "<<t[i];
        }
        s<<"}";
        return s;
    }

    istream &operator>>(istream &s, signal &t)
    {
        char *ip;
        s>>ip;
        t.StrtoSig(ip);
        return s;
    }
}

namespace Parser
{
    using Discrete::signal;
    enum types { DELIMITER = 1, VARIABLE, NUMBER, SIGNAL };

    const int NUMVARS = 26; // No. of variable names .....the alphabet
    class parser
    {
        char *exp_ptr; //points to the expression
        char token[80]; //holds current token
        char tok_type; //holds token's type
        signal vars[NUMVARS]; //holds variable's values

        void eval_exp1(signal &result);
        void eval_exp2(signal &result);
        void eval_exp3(signal &result);
        void eval_exp4(signal &result);
        void eval_exp5(signal &result);
        void eval_exp6(signal &result);
        void eval_time1(signal &result);
        void eval_time2(signal &result);

        void atom(signal &resutl);
        void get_token(), putback();
        void serror(int error);
        signal find_var(char *s);
        int isdelim(char c);

    public:
        parser();
        signal eval_exp(char *exp);
    };

    //Parser constructor
    parser::parser()
    {
        int i;

        exp_ptr = NULL;
        for(i = 0; i < NUMVARS; i++) vars[i] = (signal) 0;
    }

    //Parser entry point
    signal parser::eval_exp(char *exp)
    {
        signal result;

        exp_ptr = exp;

        get_token();
        if(!*token)
        {
            serror(2);//no expression present
            return (signal) 0;
        }

        eval_exp1(result);
        if(*token) serror(0); //last token must be null
        return result;
    }

    //Process an assignment
    void parser::eval_exp1(signal &result)
    {
        int slot;
        char ttok_type;
        char temp_token[80];

        if(tok_type == VARIABLE)
        {
            //save old token
            strcpy(temp_token, token);
            ttok_type = tok_type;
            //compute the index of the variable
            slot = toupper(*token) - 'A';

            get_token();
            if(*token != '=')
            {
                putback();//return curent token
                //restore old token - not assignment
                strcpy(token, temp_token);
                tok_type = ttok_type;
            }

            else
            {
                get_token(); //get the next part of the exp
                eval_exp2(result);
                vars[slot] = result;
                return;
            }
        }

        eval_exp2(result);
    }

    //Add or subtract two terms
    void parser::eval_exp2(signal &result)
    {
        register char op;
        signal temp;

        eval_exp3(result);
        while((op = *token) == '+' || op == '-')
        {
            get_token();
            eval_exp3(temp);
            switch (op)
            {
            case '-':
                result = result - temp;
                break;
            case '+':
                result = result + temp;
                break;
            }
        }
    }

    //Multiply or divide two factors
    void parser::eval_exp3(signal &result)
    {
        register char op;
        signal temp;

        eval_exp4(result);
        while((op = *token) == '*' || op == '&')
        {
            get_token();
            eval_exp4(temp);
            switch(op)
            {
            case '*':
                result = result * temp;
                break;
            case '&':
                //Convolution if possible
                break;
            }
        }
    }


    //Evaluate a unary + or -
    void parser::eval_exp4(signal &result)
    {
        register char op;

        op = 0;
        if((tok_type == DELIMITER) && *token == '+' || *token == '-')
        {
            op = *token;
            get_token();
        }

        eval_exp5(result);
        if(op == '-') result = -result;
    }

    //Process a parenthesized expression
    void parser::eval_exp5(signal &result)
    {
        if(*token == '(')
        {
            get_token();
            eval_exp2(result);
            if(*token != ')')
                serror(1);
            get_token();
        }
        else atom(result);
    }

    //Get the value of a number or a variable
    void parser::atom(signal &result)
    {
        switch(tok_type)
        {
        case VARIABLE:
            result = find_var(token);
            eval_time1(result);
            get_token();
            return;
        case NUMBER:
            result = (signal)atof(token);
            get_token();
            return;
        case SIGNAL:
            result.StrtoSig(token);
            get_token();
            return;
        default:
            serror(0);
        }
    }

    //Time scaling
    void parser::eval_time1(signal &result)
    {
        int i = 0;
        while(token[i] != '[' || token[i] != 0) i++;
        if(token[i] == '[')
        {
            eval_time2(result);
            i++;
            float x;
            if((x = atof(&token[i])) != 0)
                result.timeScale(x);//atoi takes care of the + and - if existing in the string
        }
    }

    //Time shifting
    void parser::eval_time2(signal &result)
    {
        int i = 0;
        while(token[i] != '[' || token[i] != 0) i++;
        if(token[i] == '[')
        {
            i++;
            while(token[i] != '+' || token[i] != '-' || ']') i++;
            result.timeShift(atoi(&token[i+1]));//atoi takes care of the + and - existing in the string
        }
    }

    //Return a token to the input stream
    void parser::putback()
    {
        char *t;

        t = token;
        for(; *t; t++) exp_ptr--;
    }

    //Display a syntax error
    void parser::serror(int error)
    {
        static char *e[] = {
            "Syntax Error",
            "Unbalanced Parenthesis",
            "No expression present"
        };
        cout<<e[error]<<endl;
    }

    //Obtain next token
    void parser::get_token()
    {
        register char *temp;

        tok_type = 0;
        temp = token;
        *temp = '\0';

        if(!*exp_ptr) return; //at end of expression

        while(isspace(*exp_ptr)) ++exp_ptr; //skip over the white spaces

        if(strchr("+-*&=()", *exp_ptr))
        {
            tok_type = DELIMITER;
            //advance to the next char
            *temp++ = *exp_ptr++;
        }

        else if(isalpha(*exp_ptr))
        {
            while(!isdelim(*exp_ptr))
            {
                *temp++ = *exp_ptr++;
                if(*exp_ptr == '[')
                {
                    do
                    {
                        *temp++ = *exp_ptr++;
                    } while(*exp_ptr != ']');
                }
            }
            tok_type = VARIABLE;
        }

        else if(isdigit(*exp_ptr))
        {
            while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;
            tok_type = NUMBER;
        }

        else if(*exp_ptr == '{') 
        {
            do
            {
                *temp++ = *exp_ptr++;
            } while(*exp_ptr != '}');
            tok_type = SIGNAL;
        }
        *temp = '\0';
    }

    //Return true if c is delimiter
    int parser::isdelim(char c)
    {
        if(strchr("+-*&=()", c) || c == 9 || c == '\r' || c == 0)
            return 1;
        return 0;
    }

    //return value of a variable
    signal parser::find_var(char *s)
    {
        if(!isalpha(*s))
        {
            serror(1);
            return signal(0);
        }
        return vars[toupper(*token) - 'A'];
    }
}


void main()
{
    using Parser::parser;

    parser eQuation;
    char expression[100];

    cout<<"Basic Signal Arithmetic Calculator"<<endl;
    cout<<"Use this program to perform basic addition, subtraction and multiplication of signals with time scaling and time shifting"<<endl;
    cout<<endl<<"Instructions:"<<endl<<"1. Use assignment operation to give values to variables. Enter signals within '{' and '}' and elements seperaed by ','";
    cout<<endl<<"\tExample: x = {12+i6, 13+i5}";
    cout<<endl<<"2. Use '^' before an element to indicate zero position. By default the 1st element is assumed to be at zero position";
    cout<<endl<<"3. You can include time scaling and shifting within the equation by using the '[' and ']'";
    cout<<endl<<"\tExample: x[2n+3] = y + z[n+5] +{2+i3, ^4+i1}";
    cout<<endl<<"4. Type 'exit' to exit the program";
    cout<<endl<<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"<<endl;

    do
    {
        cout<<"Enter your equation:"<<endl;
        cin.get(expression, 100);

        if(!strcmp(expression, "exit"))
            break;

        cout<<endl<<"ans: ";
        cout<<endl<<eQuation.eval_exp(expression);
    }while(1);


    getch();
}

助けてください

4

2 に答える 2

2

問題は function の最後のコードにあると思いますStrToSig():

while(*tok != ',' || *tok != '}'|| *tok != '\0') tok++;

もちろん、常に*tokこれらの 1 つとは異なります (実際には、少なくとも 2 つとは異なります)。これは永久に実行され、最終的にはアクセスできないメモリになります。次のように修正してください。tok

while(*tok != ',' && *tok != '}'&& *tok != '\0') tok++;

次に、2 番目の問題があります。 のコピー コンストラクターは、 をコピーcomplexしないためcomplexStr、不適切です。そのため、初期化されていない文字列が作成されます。

値の代わりに定数参照を使用すると、プログラムも改善されますが、これは質問の範囲外です。

于 2012-11-29T16:05:22.913 に答える
1

あなたの問題は にありistream &operator>>(istream &s, complex &t)ます。

char*どこも指していない を作成し、そこcinにデータをポップするように要求します。残念ながらcin、メモリを割り当てないため、StrtoComplex関数にガベージを渡してクラッシュさせます。

あなたが本当にやりたいことは、(コードの変更を最小限に抑えるために) 入力を astd::stringに行い、それ.c_str()から取り出してパーサーに渡すことです。std::stringたとえばと組み合わせて全体を使用するより慣用的な方法がありますstd::findが、これはあなたをさらに遠ざけるはずです。

istream &operator>>(istream &s, complex &t)
{
    std::string temp;

    std::getline(s, temp);
    t.StrtoComplex(temp.c_str());
    return s;
}

最後に、複雑なStr表現std::stringの代わりに使用することをお勧めします。これにより、ニーズに十分なメモリが常に確保されるためです。char[50]

最後に、「オーバーフローしないことがわかっていても、絶対に使用しないでください」と言いたいsprintfです。これは、誰かがコードや入力に無害な変更を加えてバッファをオーバーフローさせることがあるためです。常に使用しますsnprintf(または_snprintf、コンパイラが C99 をサポートしないと決定した場合)。

于 2012-11-29T15:45:40.793 に答える