Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм. / 12 сообщений из 12, страница 1 из 1
28.02.2014, 04:31
    #38574891
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Здравствуйте.

K&RУпражнение 5-7.
Напишите программу ADD, вычисляющую обратное польское выражение из
командной строки. Например,
ADD 2 3 4 + *
вычисляет 2*(3+4).

Код написал ещё вчера на листочке. Сегодня проверял, возникло несколько вопросов. Программа не дописана до конца. Ещё разбираюсь.
Сам код:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
//Операция ли я на входе ? 
bool isOperation(char* start)//принимает указатель на начало строки
//1.1 1.2
{
	switch (*start)
	{
	case '*':
		return true;
	case '/':
		return true;
	case '-':
		return true;
	case '+':
		return true;
	default:
		return false;
	} 
}

//выполнение 1 бинарной операции над 2 числами float
float operation_by_2f(float a, float b, char* operation)//принимает 2 числа и указатель на операцию над ними
{
	//2.1 2.2 2.3
	//2.4
	switch (*operation)
	{
	case '*':
		return a*b;;
	case '/':
		return a/b;
	case '-':
		return a-b;
	case '+':
		return a+b;
	default:
		return 0;
	}
}


int main(int argc, char* argv[]) //_TCHAR  _tmain
{
		
	char** end_numbers = argv-1;//элемент до '\0' в argv
	argv--;//сдвигаю с null так как сейчас argv на последней позиции
	//3
	while (argc>1 && isOperation(*argv--))//иду с конца массива. Пока операции над числами
	{
		printf("%i", isOperation(*(argv+1)));
		--end_numbers;
		--argc;//может и не надо. Пока пусть будет дополнительная проверка
	}
	char** start_operations = end_numbers + 1;//начиная с этого адреса, до argv+argc-1 
					       //в закрытом промежутке хранятся операции над числами 
	
	//float result = operation_by_2f(**end_numbers, **(end_numbers - 1), *start_operations);
	float result = operation_by_2f((float)**end_numbers, 3, *start_operations);//проверяю что не так выше
	//4
	//**end_numbers = -2;
	//**start_operations = +1;
	/*
	while (end_numbers>argv)//этот цикл я называю "цветок одна сторона которого обращена к солнцу"
	{
		result = operation_by_2f(result, **(end_numbers - 1), *start_operations);
		**end_numbers = -2;
		**start_operations = +1;
	}*/
	printf("\n%f", result);

	return 0;
}



У меня возникли следующие вопросы:

1.1 Не нравится алгоритм. Как бы сделали вы ?
1.2 Не нравится реализация. Как бы сделали вы ?

2.1 Как бы её назвать лучше?
2.2 Существует ли другой алгоритм ? Как бы мне вставить в код значение char, или так лучше не делать ?
Но в любом случае, как это сделать ?
2.3 Обратите внимание что в функциях 1 и 2 основная часть кода повторяется, как бы от этого избавить, да и
проверка на то какой символ на входе происходит дважды. Мне это не нравится.
2.4 Если на входе int то нужно ли явное преобразование к float ?

3. Час потратил пытаясь понять почему argv+argc-1 не указывает на предпоследний элемент (если посл '\0')
! Почему ? .

4. А вот тут начались проблемы с преобразованием, я понял что прибавляю код числа из ASCII. Читать K&R дальше ?
...
Рейтинг: 0 / 0
28.02.2014, 05:35
    #38574896
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
SashaMercury,

1. У вас алгоритм неверный.
Вычислить польскую запись можно двумя способами.
1) Слева направо с использованием явного стека.
2) Справа налево с использованием рекурсии.

Вы пытались реализовать второй, но без рекурсии. Это не работает.

Алгоритм для 1)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
цикл
   читаем следующий арг слева направо
   если число то 
      вставляем его на вершину стека
   если операция то 
      извлекаем из вершины стека 2 числа (или одно, смотря какая операция), 
      вычисляем операцию, 
      вставляем результат на вершину стека
конец цикла
результат  - число на вершине стека
(если стек пустой или там больше одного значения, значит выражение было некорректным)



Алгоритм для 2)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
функция eval (массив)
  извлечь последний элем-т массива (с укорочением массива)
  если это число то
     вернуть его
  если операция то
     вычислить арг2 = eval(массив)
     вычислить арг1 = eval(массив)
     вычислить операцию с арг1 и арг2
     вернуть результат вычисления  
конец функции



3.
Код: plaintext
1.
2.
	char** end_numbers = argv-1;//элемент до '\0' в argv
	argv--;//сдвигаю с null так как сейчас argv на последней позиции


Это ересь. Нелья уменьшать argv. Это выход за границы массива (перед началом).
Изначально argv указывает на 0-й аргумент, которым является имя программы.
Обычно это имя никому не нужно, поэтому чтобы не путаться первым действием можно выполнить
Код: plaintext
1.
2.
argv++;
argc--;


После этого argv будет указывать на реальный первый арг, а argc содержать кол-во арг-ов.

Если вы идете с конца массива аргументов то, делайте так
Код: plaintext
1.
2.
argv[argc - 1] // обращение к последнему элементу
argc--  // удаление последнего элемента




4. Чтобы из строки char* получить float используйте ф-ю atof()
...
Рейтинг: 0 / 0
28.02.2014, 08:14
    #38574923
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
SashaMercury4. А вот тут начались проблемы с преобразованием, я понял что прибавляю код числа из ASCII. Читать K&R дальше ?
Тут почитай про преобразования http://www.sql.ru/forum/1077384/kak-pravilno-privesti-tip-v-funkcii-konvertacii-sistemy-ischisleniya

Хотя тебе вполне хватит функции strtol()
...
Рейтинг: 0 / 0
28.02.2014, 09:27
    #38574949
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
оййй. указатель на argv был на конце, тк я выше оставил код для вывода массива аргументов на экран, а в нём argv++ была запись
...
Рейтинг: 0 / 0
28.02.2014, 09:31
    #38574951
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Код: plaintext
1.
2.
3.
4.
5.
while (end_numbers>argv)//этот цикл я называю "цветок одна сторона которого обращена к солнцу"
	{
		result = operation_by_2f(result, **(end_numbers - 1), *start_operations);
		**end_numbers = -2;
		**start_operations = +1;




вообще бред написал
...
Рейтинг: 0 / 0
28.02.2014, 09:42
    #38574955
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Написал ! Алгоритм не переделывал, всё работает вроде-бы. Проверьте пожалуйста.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
//Операция ли я на входе ? 
bool isOperation(char* start)//принимает указатель на начало строки
//1.1 1.2
{
	switch (*start)
	{
	case '*':
		return true;
	case '/':
		return true;
	case '-':
		return true;
	case '+':
		return true;
	default:
		return false;
	} 
}

//выполнение 1 бинарной операции над 2 числами float
float operation_by_2f(float a, float b, char* operation)//принимает 2 числа и указатель на операцию над ними
{
	//2.1 2.2 2.3
	//2.4
	switch (*operation)
	{
	case '*':
		return a*b;;
	case '/':
		return a/b;
	case '-':
		return a-b;
	case '+':
		return a+b;
	default:
		return 0;
	}
}

//обратное польское выражение
int main(int argc, char* argv[]) //_TCHAR  _tmain
{
	char** end_numbers = argv+argc-1;//элемент до '\0' в argv
	printf("%s", *argv);
	while (argc>1 && isOperation(*(argv+argc-1)))//иду с конца массива. Пока операции над числами
	{
		printf(" %i", isOperation(*(argv + argc - 1)));//вывод на экран,для себя
		--end_numbers;
		--argc;//иду к следующему элементу
	}
	char** start_operations = end_numbers + 1;//начиная с этого адреса, до argv+argc-1 
										     //в закрытом промежутке хранятся операции над числами 
	
	float result = operation_by_2f(atof(*end_numbers), atof(*(end_numbers - 1)), *start_operations);
	//4
	end_numbers -= 2;
	start_operations += 1;
	printf("%s %s", *end_numbers, *start_operations);
	while (end_numbers>argv)//этот цикл я называю "цветок одна сторона которого обращена к солнцу"
	{
		result = operation_by_2f(result, atof(*(end_numbers)), *start_operations);
		end_numbers -= 2;
		start_operations += 1;
	}
	printf("\n%f", result); 

	return 0;
}
...
Рейтинг: 0 / 0
28.02.2014, 09:53
    #38574964
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Anatoly Moskovsky 1. У вас алгоритм неверный.

фраза "вроде-бы работает", мне не нравится. Вы имели ввиду что он неоптимальный ?

Dima T, спасибо. я про них почитаю конечно, но мне хочется сначала понять как бы я сам написал такую функцию, потому пока не буду читать как они уже работают. В том числе и atof, на выходных буду думать
...
Рейтинг: 0 / 0
28.02.2014, 10:04
    #38574975
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Только вот так должно быть

Код: plaintext
1.
2.
3.
4.
5.
6.
while (end_numbers>argv)//этот цикл я называю "цветок одна сторона которого обращена к солнцу"
	{
		result = operation_by_2f(result, atof(*(end_numbers)), *start_operations);
		[color=red] end_numbers -= 1; [/color]
		start_operations += 1;
	}



не окрашивается код (
...
Рейтинг: 0 / 0
28.02.2014, 14:16
    #38575288
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
SashaMercuryфраза "вроде-бы работает", мне не нравится. Вы имели ввиду что он неоптимальный ?
Нет, я имел в виду что он вообще неверный. (Хотя в вашем случае работает, но только потому что числа у вас в примере все слева от операций)
А например, попробуйте вычислить вашим алго. такое выражение:
3 4 + 2 *
по нашему (3+4)*2

SashaMercuryне окрашивается код (
В теге SRC используйте пару >>> <<< для выделения текста.
...
Рейтинг: 0 / 0
01.03.2014, 02:25
    #38575877
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
Согласен, не получится. Но и те алгоритмы выше, не вычислят то выражение что я подаю на вход. Разве нет ? Это просто немного разные задачи. Классический задача, и задача в K&R ?
...
Рейтинг: 0 / 0
01.03.2014, 03:38
    #38575891
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
SashaMercuryСогласен, не получится. Но и те алгоритмы выше, не вычислят то выражение что я подаю на вход. Разве нет ? Это просто немного разные задачи. Классический задача, и задача в K&R ?Алгоритмы которые показал Анатолий - вычислят.
Реализуй первый (он проще) и сам увидишь. Заодно со стеком разберешься.
...
Рейтинг: 0 / 0
03.03.2014, 09:13
    #38576525
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм.
White OwlАлгоритмы которые показал Анатолий - вычислят.
Реализуй первый (он проще) и сам увидишь. Заодно со стеком разберешься.

Уезжаю в конце недели на месяц, приеду, изучу структуры и реализую на стеке.
Спасибо.

Я писал

SS
Код: plaintext
1.
char** end_numbers = argv+argc-1;//элемент до '\0' в argv



Справа у меня указатель на указатель, потому слева тип переменной имеет такой тип данных. Но по факту я храню адрес памяти размером в 4 байта. Можно ли объявить какой-нибудь указатель общего вида в этом случае, а при использовании сделать приведение типов ?
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / K&R 5.11 ex 5.7 Обратное польское выражение. Преобразование типов. Алгоритм. / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]