我在这里将代码转换为类复杂的代码......
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();
}
请帮忙
答案 0 :(得分:1)
您的问题出在istream &operator>>(istream &s, complex &t)
。
您创建了一个无处指向的char*
,然后让cin
将数据弹出到其中。遗憾的是cin
没有为您分配内存,因此您将垃圾传递到StrtoComplex
函数中,导致其崩溃。
您真正想要做的是(最小化代码更改)将输入转换为std::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;
}
最后请注意,我建议您使用std::string
而不是char[50]
来表示您的complexStr表示,因为它会确保始终有足够的内存满足您的需求。
最后,我想说“永远不要使用sprintf
,即使你知道你不会溢出”,因为有时某人会对你的代码或输入进行无害的更改并溢出缓冲区。 始终使用snprintf
(或_snprintf
如果您的编译器决定不支持C99。)
答案 1 :(得分:1)
我认为问题出在函数StrToSig()
的最后一个代码中:
while(*tok != ',' || *tok != '}'|| *tok != '\0') tok++;
当然,*tok
总是与其中一个不同(事实上,至少其中两个)。这将永远运行,最终使tok
进入无法访问的内存。只需更正它:
while(*tok != ',' && *tok != '}'&& *tok != '\0') tok++;
然后你有第二个问题:complex
的复制构造函数很糟糕,因为它没有复制complexStr
,所以你最终会得到一个未初始化的字符串。
使用const引用而不是值也可以改善您的程序,但这超出了您的问题的范围。