Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ Преобразование в постфикстую запись

Автор: Krjuger 28.11.2009 20:39

В общем надо разработать класс,который будет переводить из обычной записи в постфиксную.


#include<stdio.h>
#include<stdlib.h>
#pragma hdrstop
/* Описание Класса*/
class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};
public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
}

PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i;
/* Ввод аpифметического выpажения */
k=i=0;
/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
outstring[i++]=Del(&OPERS);
/* Удаляем из стека саму откpывающую скобку */
Del(&OPERS);
}
/* Если очеpедной символ - буква , то */
if(a[k]>='a'&&a[k]<='z')
/* пеpеписываем её в выходную стpоку */
outstring[i++]=a[k];
/* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if(a[k]=='+'||a[k]=='-'||a[k]=='/'||a[k]=='*')
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
outstring[i++]=Del(&OPERS);
/* записываем в стек поступившую опеpацию */
OPERS=push(OPERS, a[k]);
}
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
outstring[i++]=Del(&OPERS);
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s\n", outstring);
}
/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
struct stek *PTR;
/* Выделение памяти */
stek *PRT= new stek;
/* Инициализация созданной веpшины */
PTR->c=a;
/* и подключение её к стеку */
PTR->next=head;
/* PTR -новая веpшина стека */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}


В общем никак не могу понять,что ему не нравица...Точнее я понимаю что за ошибку он выдает,но не могу понять как ее исправить....(Error 1 error C2533: 'PostWrite::{ctor}' : constructors not allowed a return type 22)

Автор: volvo 28.11.2009 21:05

Ты для начала описание класса заверши (точку с запятой поставь), а потом описывай методы:

class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};

public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
}; // Вот тут !!
!

Добавлено через 16 мин.
P.S. Зачем своя реализация stek, если есть std::stack? Подключи: include <stack>, и используй...

Автор: Krjuger 28.11.2009 21:38

Мда ппц косяк,не заметил(((
Ладно исправил,потом кое что изменил.добавил возможный пример


#include<stdio.h>
#include<stdlib.h>
#pragma hdrstop
/* Описание Класса*/
class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};
char* output;
public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
};

PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i;
/* Ввод аpифметического выpажения */
k=i=0;
/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
outstring[i++]=Del(&OPERS);
/* Удаляем из стека саму откpывающую скобку */
Del(&OPERS);
}
/* Если очеpедной символ - буква , то */
if(a[k]>='a'&&a[k]<='z')
/* пеpеписываем её в выходную стpоку */
outstring[i++]=a[k];
/* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if(a[k]=='+'||a[k]=='-'||a[k]=='/'||a[k]=='*')
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
outstring[i++]=Del(&OPERS);
/* записываем в стек поступившую опеpацию */
OPERS=push(OPERS, a[k]);
}
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
outstring[i++]=Del(&OPERS);
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s\n", outstring);
output=outstring;
}

/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
struct stek *PTR;
/* Выделение памяти */
stek *PRT= new stek;
/* Инициализация созданной веpшины */
PTR->c=a;
/* и подключение её к стеку */
PTR->next=head;
/* PTR -новая веpшина стека */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}

void main()
{ char* str;
char str9[100];
str=gets(str9);
PostWrite str10(str);
}


ошибку выдает в PTR->c=a; в процедуре push(добавление элемента в стек).ошибка что то типа нет доступа для записи по какомото там адресу

Автор: volvo 28.11.2009 22:00

А ты что хотел, чтобы у тебя PTR сам инициализировался? Ты выделяешь память под PRT вообще-то... PTR остается неинициализированным, вот тебе и ошибка доступа.

Не торопись, когда программу пишешь, программирование - не Formula I.

Автор: Krjuger 28.11.2009 22:23

Мда моя безграмотность моя проблема.Ладно все эти ошибки я исправил,все стало нормально работать,вот только как лучше всего будет внести реализацию функций синуса косинуса и тд в эту программу?Я предполагаю создать какую нибудь буферную переменную и скидывать туда.

Автор: Krjuger 30.11.2009 21:12

В общем попробовал добавить добавить поддержку функций,но моя попытка обернулась крахом,нужна помощ.


#pragma hdrstop
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include <string.h>

/* Описание Класса*/
class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};
char* output;
public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
};

PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i, j, p;
const char number[] = "0123456789";
const char liter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char znak[] = "-*/+";
const char *func[] = {" cos sin tg ctg ln log sign exp\0"};
char tmp[100]={0};
char tmp1[100]={0};
/* Ввод аpифметического выpажения */
k=i=j=0;
/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
outstring[i++]=Del(&OPERS);
/* Удаляем из стека саму откpывающую скобку */
Del(&OPERS);
}
/* Если очеpедной символ - буква , то */
if (strchr(liter, a[k]) != 0)
// /* пеpеписываем её в выходную стpоку */
// outstring[i++]=a[k];
{ while (strchr(liter, a[k]) != 0)
{
tmp[j++] = a[k];
k=k+1;
}
tmp[j++]='\0';
strcpy(tmp1, " ");
strcat(tmp1, tmp);
strcat(tmp1, " ");
if (strstr(*func,tmp1) != 0)
{
for (p=0; tmp1[p]!='\0'; p++)
{
OPERS=push(OPERS, tmp1[p]);
}
}
else
strcat(outstring, tmp);
}
/* Если очеpедной символ - цифра , то */
if (strchr(number, a[k]) != 0)
/* пеpеписываем её в выходную стpоку */
outstring[i++]=a[k];
/* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if (strchr(znak, a[k]) != 0)
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
outstring[i++]=Del(&OPERS);
/* записываем в стек поступившую опеpацию */
OPERS=push(OPERS, a[k]);
}
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
outstring[i++]=Del(&OPERS);
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s\n", outstring);
output=outstring;
}

/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
// struct stek *PTR;

stek *PTR = new stek;
/* Инициализация созданной веpшины */
PTR->next=head;
/* PTR -новая веpшина стека */
PTR->c=a;
/* и подключение её к стеку */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}

void main()
{ char* str;
char str9[100];
str=gets(str9);
PostWrite str10(str);
getch();
}


По задумке,я создал буферную переменную и если литера,то идет проверка и накапливание до тех пор пока в алфавите,а потом происходит сравнивание с множестов функций,если функция то записывается в стек ,как операция,если переменная то записывается в выходную строку.Но я не могу понять почему у мен ошибка.
Для примера бралось a + (sin (b + c)).Происходила ошибка записи на моменте когда первый знак "+" должен был быть помещен в стек.

Автор: volvo 1.12.2009 16:23

Цитата
Происходила ошибка записи на моменте когда первый знак "+" должен был быть помещен в стек.
Ошибка у тебя происходит, когда ты пытаешься сделать:
		  else
strcat(outstring, tmp);
с неинициализированнй outstring. Тут программа вылетает. Это первое. Второе: если даже инициализировать строку:
char  outstring[80] = {0};
, то программа правильно работать не станет. Она, конечно, теперь не вылетает, но результат выдает бредовый. Ищи ошибку в алгоритме.

Третье: посмотри внимательно на свою строку func, и подумай, почему exp не будет определена как функция, даже если она присутствует во введенной пользователем строке?

Автор: Krjuger 1.12.2009 18:04

Насчет экспоненты,да действительно она не будет присутстовавать,потому что для проверки на принадлежность в моем варианте необходимы пробелы с двух сторон а для экспоненты пробела после функции попросту нет,исправил.Над остальным пока думаю.

Автор: volvo 1.12.2009 18:15

Чего думать? Ты в одном месте заполняешь строку outstring через strcat (естественно, i при этом не изменяется), а в другом - через прямую запись: outstring[ i ] = ..., при этом то, что раньше было записано через strcat - перезаписывается. Вот тебе и источник проблем.

Теперь о функциях: нельзя так делать, как ты делаешь. Что у тебя происходит? Ты ПОБУКВЕННО запихиваешь название функции в стек, но он предназначен не для этого. Либо ставь каждой функции в соответствие какой-то номер (индекс, как угодно), и заталкивай его в стек, либо переписывай struct stek так, чтобы там хранился не один символ, а столько, сколько может понадобится для названия самой длинной функции. Но это потребует переделок программы.

Еще раз: программа СИЛЬНО упростится, если вместо твоего самописного стека использовать std::stack<std::string>, подумай над этим...

Автор: Krjuger 1.12.2009 18:23

Я бы с радостью,но со структурой и возможностями std::stack<std::string> я не знаком напроч,тогда раз лучше будет пойду ка я почитаю)

Автор: Krjuger 1.12.2009 19:55

В общем я решил доделать то что есть,я прекрасно поимаю,что то, что я пишу далеко от вершины грамотности и ужасно с точки зрения оптимизации,но других вариантов я пока что не вижу,потому что реализовывать через std по программе меня будут учить только в следующем семестре.В общем получилось что то в этом духе.


#pragma hdrstop
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include <string.h>

/* Описание Класса*/
class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};
char* output;
public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
int SetFunc(char* a);
};

PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i, j, p;
const char number[] = "0123456789";
const char liter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char znak[] = "-*/+";
const char *func[] = {" cos sin tg ctg ln log sign exp \0"};
char tmp[100]={0};
char tmp1[100]={0};
/* Ввод аpифметического выpажения */
k=i=j=0;
strcpy(outstring,"\0");
/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - буква , то */
if (strchr(liter, a[k]) != 0)
// /* пеpеписываем её в выходную стpоку */
// outstring[i++]=a[k];
{ while (strchr(liter, a[k]) != 0)
{
tmp[j++] = a[k];
k=k+1;
}
tmp[j++]='\0';
strcpy(tmp1, " ");
strcat(tmp1, tmp);
strcat(tmp1, " ");
if (strstr(*func,tmp1) != 0)
{
OPERS=push(OPERS,SetFunc(tmp));
j=0;
}
else
{
strcat(outstring, tmp);
*tmp=NULL;
i=i+j-1;
j=0;
}
}
/* Если очеpедной символ - цифра , то */
if (strchr(number, a[k]) != 0)
/* пеpеписываем её в выходную стpоку */
outstring[i++]=a[k];
/* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if (strchr(znak, a[k]) != 0)
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
outstring[i++]=Del(&OPERS);
/* записываем в стек поступившую опеpацию */
OPERS=push(OPERS, a[k]);
}
}
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
outstring[i++]=Del(&OPERS);
/* Удаляем из стека саму откpывающую скобку */
Del(&OPERS);
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
outstring[i++]=Del(&OPERS);
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s\n", outstring);
output=outstring;
}

/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
// struct stek *PTR;

stek *PTR = new stek;
/* Инициализация созданной веpшины */
PTR->next=head;
/* PTR -новая веpшина стека */
PTR->c=a;
/* и подключение её к стеку */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}

int PostWrite::SetFunc(char* a)
{
switch(*a)
{
case 'cos': return 1;
case 'sin': return 2;
case 'tg': return 3;
case 'ctg': return 4;
case 'ln': return 5;
case 'lon': return 6;
case 'sign':return 7;
case 'exp': return 8;
}
}
void main()
{ char* str;
char str9[100];
str=gets(str9);
PostWrite str10(str);
getch();


Вроде как бы оно работает с функциями правильно,вот только я не могу понять почему когда я функцию заменяю числом и записываю его в стек,по идее вместо чесла туда должна будет записаться литера стоящая под соответствующим номером в аски коде,но почему при каждом вызове программы эта буква(символ) меняется

Автор: volvo 1.12.2009 22:22

  switch(*a)
{
case 'cos':
и так далее - это ты сам придумал? Так делать нельзя:
Цитата(Стандарт С++)
6.4.2 The switch statement [stmt.switch]
1 The switch statement causes control to be transferred to one of several statements depending on the value
of a condition.
2 The condition shall be of integral type, enumeration type, or of a class type for which a single conversion
function to integral or enumeration type exists
, у тебя под switch-ем выражение другого типа. Мало того, ты думаешь, что 'sin' = это то же самое что "sin"? Компилятор так не думает. Так что у тебя PostWrite::SetFunc() написана некорректно, и возвращает мусор. Переписывай через if-ы. И не забудь, что С-шные строки сравниваются не через ==, а через strcmp.

Автор: Krjuger 2.12.2009 21:28

В общем я исправил все что надо и теперь с функциями более менее работает.Вот код


#pragma hdrstop
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include <string.h>

/* Описание Класса*/
class PostWrite
{
private:
struct stek
{
char c;
struct stek *next;
};
char* output;
public:
/* Пpототипы функций */
PostWrite( char* a);
struct stek *push(struct stek *, char);
char Del( struct stek **);
int Prior(char a);
char SetFunc(char* a);
char* TakeFunc(char a);
};

PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i, j, p;
const char number[] = "0123456789";
const char liter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char znak[] = "-*/+";
const char *func[] = {" cos sin tg ctg ln log sign exp \0"};
char tmp[100]={0};
char tmp1[100]={0};
char* tmp2;
/* Ввод аpифметического выpажения */
k=i=j=0;
strcpy(outstring,"\0");
/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - буква , то */
if (strchr(liter, a[k]) != 0)
// /* пеpеписываем её в выходную стpоку */
// outstring[i++]=a[k];
{ while (strchr(liter, a[k]) != 0)
{
tmp[j++] = a[k];
k=k+1;
}
tmp[j++]='\0';
strcpy(tmp1, " ");
strcat(tmp1, tmp);
strcat(tmp1, " ");
if (strstr(*func,tmp1) != 0)
{
OPERS=push(OPERS,SetFunc(tmp));
j=0;
}
else
{
strcat(outstring, tmp);
// *tmp=NULL;
i=i+j-1;
j=0;
}
}
/* Если очеpедной символ - цифра , то */
if (strchr(number, a[k]) != 0)
/* пеpеписываем её в выходную стpоку */
outstring[i++]=a[k];
/* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if (strchr(znak, a[k]) != 0)
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
{
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
Del(&OPERS);
}
else
outstring[i++]=Del(&OPERS);
/* записываем в стек поступившую опеpацию */
}
OPERS=push(OPERS, a[k]);
}
}
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
Del(&OPERS);
}
else
{
outstring[i++]=Del(&OPERS);
/* Удаляем из стека саму откpывающую скобку */
}
Del(&OPERS);
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
Del(&OPERS);
}
else
outstring[i++]=Del(&OPERS);
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s \n", outstring);
output=outstring;
}

/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
// struct stek *PTR;

stek *PTR = new stek;
/* Инициализация созданной веpшины */
PTR->next=head;
/* PTR -новая веpшина стека */
PTR->c=a;
/* и подключение её к стеку */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}

char PostWrite::SetFunc(char* a)
{
if (strcmp(a,"cos")==0)
{
return '1';
}
else
if (strcmp(a,"sin")==0)
{
return '2';
}
else
if (strcmp(a,"tg")==0)
{
return '3';
}
else
if (strcmp(a,"ctg")==0)
{
return '4';
}
else
if (strcmp(a,"ln")==0)
{
return '5';
}
else
if (strcmp(a,"lon")==0)
{
return '6';
}
else
if (strcmp(a,"sign")==0)
{
return '7';
}
else
if (strcmp(a,"exp")==0)
{
return '8';
}
}

char* PostWrite::TakeFunc(char a)
{
if (a=='1')
{
return "cos\0";
}
else
if (a=='2')
{
return "sin\0";
}
else
if (a=='3')
{
return "tg\0";
}
else
if (a=='4')
{
return "ctg\0";
}
else
if (a=='5')
{
return "ln\0";
}
else
if (a=='6')
{
return "lon\0";
}
else
if (a=='7')
{
return "sign\0";
}
else
if (a=='8')
{
return "exp\0";
}
}
void main()
{ char* str;
char str9[100];
str=gets(str9);
PostWrite str10(str);
getch();
}


Появилась новая проблема,если попробовать пример (a * (b + c) + d) / 2 то программа правильно работает вплоть до момента когда доходит до d,содержание стека в момент обрабатывания операции + перед d,но когда переходит на обработку самой d, strcat(outstring, tmp);во первых сама переменная d туда уже не записывается в выходную строку и по неведомой причине портится стек.

Автор: volvo 2.12.2009 22:02

Раз:

		{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
{
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
Del(&OPERS);
}
else
{
outstring[i++]=Del(&OPERS);
outstring[i] = '\0'; // !!! Вот этого у тебя не было !!!
}
/* записываем в стек поступившую опеpацию */
}
OPERS=push(OPERS, a[k]);
}
, два:
	  {
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
Del(&OPERS);
}
else
{
outstring[i++]=Del(&OPERS);
outstring[i] = '\0'; // !!! Этого - тоже не было !!!
/* Удаляем из стека саму откpывающую скобку */
}
Del(&OPERS);
}
/* Пеpеход к следующему символу входной стpоки */
k++;
. Понимаешь в чем дело? Ты дописываешь символ в строку outstring, так ее после этого надо закрыть нулевым символом? Надо. Вот и закрываем. Теперь ошибки исчезли... Может, где еще проявятся, пройди по всей программе, там где ты делаешь outstring[i++] = чему_то, добавляй outstring[ i ] = '\0';

Если же строку нулем не закрыть, то добавляться tmp будет не к тому, что ты думаешь, а сначала strcat пробежит до первого попавшегося нуля, и только с того места пойдет добавление. А если ноль будет дальше, чем в 80 позиции? Вылет за границы строки.

Автор: Krjuger 2.12.2009 22:47

Тогда чисто теоретический вопрос почему появились то проблемы со стеком,если бы я просто переменную d не смог бы записать,ну или коряво записывал бы, это понятно,тут то,что ты написал абсолютно верно,но почему же в момент записи моего значения в выходную строку портился стек.

Автор: Krjuger 2.12.2009 23:13

С большими выражениями теперь более менее нормально, но ошибка появилась там,где ее не ждали.при варианте a+b*c получается ошибка в том что основной цикл переходит на 7 элемент,который забит мусором в результате цикл не прерывается ,а зацикливается.

Автор: volvo 2.12.2009 23:17

Цитата
но почему же в момент записи моего значения в выходную строку портился стек.
А этого я тебе не говорил. Вот Билдер 2009, например, говорит:
Прикрепленное изображение
Где здесь видно порчу стека? Другой компилятор по-другому отреагирует на выполнение этой программы. Ты чем пользуешься?

Добавлено через 6 мин.
Цитата
при варианте a+b*c получается ошибка в том что основной цикл переходит на 7 элемент,который забит мусором в результате цикл не прерывается ,а зацикливается.
Ничего не зациклилось, только что проверил, выдает ответ:
a+b*c=

abc*+


Автор: Krjuger 2.12.2009 23:28

У меня MVS 2008,а увидел что портится просто в дебагере пошагово просматривая вкладку Locals.Если ввести = то у меня тоже нормально,зато вот если просто ввести выражение то почему то не получается

Добавлено через 11 мин.
Вот что именно происходит:
До
Изображение
После
Изображение
Красный свидетельствует о том что на данной операции с "красными" переменными произведены изменения.

Автор: volvo 3.12.2009 1:00

Так. Проблема - в том, что strchr ищет (и находит) символ '\0' в строке liter, и в любой другой строке тоже (ибо строка заканчивается этим символом, компилятор сам добавляет его к строковым литералам). Значит, надо проверять еще, что собственно символ, который проверяется - не NULL:

	/* Повтоpяем , пока не дойдем до '=' */
while(a[k]!='\0')
{
/* Если очеpедной символ - буква , то */
if (strchr(liter, a[k]) != 0)
{
while (strchr(liter, a[k]) != 0 && a[k] != '\0') // <--- Условие изменилось !!!
{
tmp[j++] = a[k];
k=k+1;
}
tmp[j++]='\0';
strcpy(tmp1, " ");
strcat(tmp1, tmp);
strcat(tmp1, " ");
if (strstr(*func,tmp1) != 0)
{
OPERS=push(OPERS,SetFunc(tmp));
j=0;
}
else
{
strcat(outstring, tmp);
i=i+j-1;
j=0;
}
}
if (a[k] == '\0') continue; // <--- Вот эту строку добавь !!! Дальше нет смысла, уже конец строки

/* Если очеpедной символ - цифра , то */
if (strchr(number, a[k]) != 0)


Теперь корректно отрабатывает и со знаком =, и без него... Тестируй

Автор: Krjuger 20.12.2009 3:06

Я уже затюкал наверно с этой задачей,но опять нашлась ошибка.Припроходе по строке,если последнее действие умножение или деление,то происходит вылет за пределы строки и я из цикла не выхожу.


PostWrite::PostWrite(char* a)
{
/* Стек опеpаций пуст */
struct stek *OPERS=NULL;
char outstring[80];
int k, i, j, p;
const char number[] = "0123456789";
const char liter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char znak[] = "-*/+";
const char *func[] = {" cos sin tg ctg ln log sign exp \0"};
char tmp[100]={0};
char tmp1[100]={0};
char* tmp2;
/* Ввод аpифметического выpажения */
k=i=j=0;
strcpy(outstring,"\0");
/* Повтоpяем , пока не дойдем до '=' */
while(strchr("\0", a[k]) == 0)
{
/* Если очеpедной символ - буква , то */
if (strchr(liter, a[k]) != 0 )
// /* пеpеписываем её в выходную стpоку */
{
while (strchr(liter, a[k]) != 0 && a[k] != '\0')
{
tmp[j++] = a[k];
k=k+1;
}
tmp[j++]='\0';
strcpy(tmp1, " ");
strcat(tmp1, tmp);
strcat(tmp1, " ");
if (strstr(*func,tmp1) != 0)
{
OPERS=push(OPERS,SetFunc(tmp));
j=0;
}
else
{ outstring[i]='\0';
strcat(outstring, tmp);
i=i+j-1;
outstring[i++]=' ';
j=0;
}
}
if (a[k] == '\0') continue;
/* Если очеpедной символ - цифра , то */
if (strchr(number, a[k]) != 0)
/* пеpеписываем её в выходную стpоку */
{
while (strchr(number, a[k]) != 0 && a[k] != '\0')
{
outstring[i++]=a[k];
k=k+1;
}
outstring[i++]=' ';
} /* Если очеpедной символ - '(' , то */
if(a[k]=='(')
/* заталкиваем её в стек */
OPERS=push(OPERS, '(');
if (strchr(znak, a[k]) != 0)
/* Если следующий символ - знак опеpации , то: */
{
/* если стек пуст */
if(OPERS==NULL)
/* записываем в него опеpацию */
OPERS=push(OPERS, a[k]);
/* если не пуст */
else
/* если пpиоpитет поступившей опеpации больше
пpиоpитета опеpации на веpшине стека */
if(Prior(OPERS->c)<Prior(a[k]))
/* заталкиваем поступившую опеpацию на стек */
OPERS=push(OPERS, a[k]);
/* если пpиоpитет меньше */
else
{
while((OPERS!=NULL)&&(Prior(OPERS->c)>=Prior(a[k])))
/* пеpеписываем в выходную стpоку все опеpации
с большим или pавным пpиоpитетом */
{
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
outstring[i++]=' ';
Del(&OPERS);
}
else
outstring[i++]=Del(&OPERS);
outstring[i++]=' ';
outstring[i] = '\0';
/* записываем в стек поступившую опеpацию */
}
OPERS=push(OPERS, a[k]);
}
}
/* Если очеpедной символ - ')' */
if(a[k]==')')
/* то выталкиваем из стека в выходную стpоку */
{
/* все знаки опеpаций до ближайшей */
while((OPERS->c)!='(')
/* откpывающей скобки */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
outstring[i++]=' ';
Del(&OPERS);
}
else
{
outstring[i++]=Del(&OPERS);
outstring[i++]=' ';
outstring[i] = '\0';
/* Удаляем из стека саму откpывающую скобку */
}
Del(&OPERS);
}
/* Пеpеход к следующему символу входной стpоки */
k++;
}
/* после pассмотpения всего выpажения */
while(OPERS!=NULL)
/* Пеpеписываем все опеpации из */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
outstring[i++]=' ';
Del(&OPERS);
}
else
outstring[i++]=Del(&OPERS);
outstring[i++]=' ';
/* стека в выходную стpоку */
outstring[i]='\0';
/* и печатаем её */
printf("\n %s \n", outstring);
Output=outstring;
}

/* Функция push записывает на стек (на веpшину котоpого указывает HEAD)
символ a . Возвpащает указатель на новую веpшину стека */
PostWrite::stek *PostWrite::push(PostWrite::stek *head, char a )
{
// struct stek *PTR;

stek *PTR = new stek;
/* Инициализация созданной веpшины */
PTR->next=head;
/* PTR -новая веpшина стека */
PTR->c=a;
/* и подключение её к стеку */
return PTR;
}

/* Функция DEL удаляет символ с веpшины стека.
Возвpащает удаляемый символ.
Изменяет указатель на веpшину стека */
char PostWrite::Del(struct stek **head)
{
struct stek *PTR;
char a;
/* Если стек пуст, возвpащается '\0' */
if(*head==NULL) return '\0';
/* в PTR - адpес веpшины стека */
PTR=(*head);
a=PTR->c;
/* Изменяем адpес веpшины стека */
(*head)=PTR->next;
/* Освобождение памяти */
delete(PTR);
/* Возвpат символа с веpшины стека */
return a;
}

/* Функция PRIOR возвpащает пpиоpитет аpифм. опеpации */
int PostWrite::Prior(char a)
{
switch(a)
{
case '*':
case '/':
return 3;

case '-':
case '+':
return 2;

case '(':
return 1;
}
}

char PostWrite::SetFunc(char* a)
{
if (strcmp(a,"cos")==0)
{
return '1';
}
else
if (strcmp(a,"sin")==0)
{
return '2';
}
else
if (strcmp(a,"tg")==0)
{
return '3';
}
else
if (strcmp(a,"ctg")==0)
{
return '4';
}
else
if (strcmp(a,"ln")==0)
{
return '5';
}
else
if (strcmp(a,"lon")==0)
{
return '6';
}
else
if (strcmp(a,"sign")==0)
{
return '7';
}
else
if (strcmp(a,"exp")==0)
{
return '8';
}
}

char* PostWrite::TakeFunc(char a)
{
if (a=='1')
{
return "cos\0";
}
else
if (a=='2')
{
return "sin\0";
}
else
if (a=='3')
{
return "tg\0";
}
else
if (a=='4')
{
return "ctg\0";
}
else
if (a=='5')
{
return "ln\0";
}
else
if (a=='6')
{
return "lon\0";
}
else
if (a=='7')
{
return "sign\0";
}
else
if (a=='8')
{
return "exp\0";
}
}


Описание класса совершенно не изменилось.Для примера использовать можно 10*a-b/2 ну или любое другое подобное выражение.

Автор: volvo 20.12.2009 3:43

Очень похожая ошибка на то, что раньше описывалось в 19-м посте... Первое:

int main() // Стандарт С++ не позволяет функции main иметь тип void.
{
char* str;
char str9[100] = {0}; // Второе - инициализируй массив нулями, этого за тебя делать не должен никто
str=gets(str9);

Третье:
	/* после pассмотpения всего выpажения */
while(OPERS != NULL)
/* Пеpеписываем все опеpации из */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2 && tmp2[p]!='\0';p++) // <--- !!! сначала надо убедиться, что tmp2 != NULL
{
outstring[i++]=tmp2[p];
}
outstring[i++]=' ';
Del(&OPERS);
}
и четвертое: компилятор был обязан предупредить тебя, что функция может НЕ возвращать значение. Меня компилятор предупредил ТРИЖДЫ (в трех разных функциях). Обращай внимание на эти предупреждения, иначе за их игнорирование можно очень дорого заплатить потом, при отладке и/или добавлении функционала.

Автор: Krjuger 20.12.2009 4:46

Мне компилятор не выдал ниодной ошибки, ниодного предупреждения вообще,если не повериш на слово, могу скрин выложить..по поводу первого...этот зверски корявый ввод был лиш для того чтобы отладить данную часть программы,для меня важным было лиш то чтобы класс выполнял свою задачу.

Цитата
сначала надо убедиться, что tmp2 != NULL

А не лучше ли сделать чтобы TakeFunc если функция не найдена просто бы возвращало значение (OPERS->c),тобиш изменить ее вот так

char* PostWrite::TakeFunc(char a)
{
if (a=='1')
{
return "cos\0";
}
else
if (a=='2')
{
return "sin\0";
}
else
if (a=='3')
{
return "tg\0";
}
else
if (a=='4')
{
return "ctg\0";
}
else
if (a=='5')
{
return "ln\0";
}
else
if (a=='6')
{
return "lon\0";
}
else
if (a=='7')
{
return "sign\0";
}
else
if (a=='8')
{
return "exp\0";
}
else
return &a;
}


Однако,Теперь там в конце появились доселе неизвестные элементы,хотя зацикливания уже нет,в результате спасло,как раз то что ты сделал ранее.

if (strchr(number, a[k]) != 0)
/* пеpеписываем её в выходную стpоку */
{
while (strchr(number, a[k]) != 0 && a[k] != '\0')
{
outstring[i++]=a[k];
k=k+1;
}
outstring[i++]=' ';
if (a[k] == '\0') continue;//<----вот длягодаря этому все нормально вроде стало)



Да,еще я не могу найти где надо поставить пробел,потому что при примере a*10-b/2 получается результат "a 10 * b 2 /-" между делить и минусом отсутствует пробел,хотя он там должен быть.

Автор: volvo 20.12.2009 7:35

Цитата
Мне компилятор не выдал ниодной ошибки, ниодного предупреждения вообще,если не повериш на слово, могу скрин выложить..
Скрин ничего не решает, все зависит от настроек среды и компилятора, я тоже могу отключить все предупреждения, и меня перестанут предупреждать... Однако я предпочитаю в опциях установить отображение всех Warning-ов, и пускай компилятор выявляет все подозрительные с его точки зрения места в программе.

Цитата
Да,еще я не могу найти где надо поставить пробел,потому что при примере a*10-b/2 получается результат "a 10 * b 2 /-" между делить и минусом отсутствует пробел,хотя он там должен быть.
Еще бы, с таким форматированием текста, ты что-нибудь мог найти...
	/* после pассмотpения всего выpажения */
while(OPERS != NULL)
/* Пеpеписываем все опеpации из */
if (strchr(number, OPERS->c) != 0)
{
tmp2=TakeFunc(OPERS->c);
for (p=0; tmp2 && tmp2[p]!='\0';p++)
{
outstring[i++]=tmp2[p];
}
outstring[i++]=' ';
Del(&OPERS);
}
else
{ // У тебя вот этих скобок не было, пробелы не ставились...
outstring[i++]=Del(&OPERS);
outstring[i++]=' ';
}
/* стека в выходную стpоку */
outstring[i]='\0';

/* и печатаем её */
printf("\n %s \n", outstring);