-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

我认为问题出在函数的最后一个代码中StrToSig()

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

当然,*tok总是与其中之一不同(实际上,至少与其中两个不同)。这将永远运行,最终tok进入无法访问的内存。只需将其更正为:

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

然后你有第二个问题:复制构造函数 forcomplex很糟糕,因为它不 copy complexStr,所以你最终会得到一个未初始化的字符串。

使用 const 引用而不是值也可以改进您的程序,但这超出了您的问题范围。

于 2012-11-29T16:05:22.913 回答
1

你的问题在istream &operator>>(istream &s, complex &t).

您创建一个char*指向无处的对象,然后要求cin将数据弹出到其中。不幸的是cin,它没有为您分配内存,因此您将垃圾传递给您的StrtoComplex函数,导致它崩溃。

您真正想要做的是(以尽量减少代码更改)将输入输入到 a中std::string,然后从中提取.c_str()以传递给您的解析器。例如,有更多惯用的方式使用 through std::stringstd::find但这应该会让你走得更远。

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

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

最后请注意,我建议您使用std::string而不是char[50]您的 complexStr 表示,因为它将确保始终有足够的内存来满足您的需求。

最后,我想说“sprintf即使您知道不会溢出,也不要使用”,因为有时有人会对您的代码或输入进行无害的更改并溢出缓冲区。始终使用snprintf(或者_snprintf如果您的编译器决定不支持 C99)。

于 2012-11-29T15:45:40.793 回答