Перейти к содержанию

С++ задание


Antonshka

Рекомендуемые сообщения

Задание из книги Лафоре

Спойлер

При помощи цикла for изобразите на экране пирамиду из символов 'X'. Верхняя часть пирамиды должна выглядеть следующим образом:
                х
            ххх
        ххххх
    ххххххх
ххххххххх
Вся пирамида должна быть высотой не 5 линий, как изображено здесь, а 20 линий. Одним из способов ее построения может служить использование двух вложенных циклов, из которых внутренний будет заниматься печатанием символов 'X' и пробелов, а другой осуществлять переход на одну строку вниз.

Кто-нибудь пробовал его решить?

 

У меня заняло это несколько часов. Непросто мне она далась.

Скрипт

Спойлер

#include "pch.h" //precomile
#include <iostream> //cout, cin
using namespace std;

int main(){
	int level;
	char x,y;
	cout << "Enter char 1: "; cin >> x;
	cout << "Enter char 2: "; cin >> y;
	cout << "Enter level: "; cin >> level;
	for (int i = level; i < (level/2+1) * level; i++){
		if (i != level && i % level == 0) cout << endl;
		i % level >= level - (i / level + (i / level - 1)) ? cout << x : cout << y;}
	return 0;}

 

 

Если кто-то из вас решал эту задачу, я с удовольствием посмотрел бы на ваши методы.

  • Понравилось 1
Ссылка на комментарий
Поделиться на другие сайты

#include <string>
#include <iostream>

using namespace std;

void DrawLine(int tabs);

int main()
{
    int tabs = 20;
    DrawLine(tabs);
    return 0;
}

void DrawLine(int tabs) {
    if (tabs < 0) return;
    cout << string(tabs, ' ') << string(20 - tabs, 'x') << endl;
    DrawLine(--tabs);
}

Мой вариант. Затрачено где-то минуты три ))

 

image.png

 

image.png

Ссылка на комментарий
Поделиться на другие сайты

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

        х
    ххх
ххххх

Значит пока у вас нет решения.

 

Вот еще чуть более изощренный вариант решения с моей стороны

Скрипт

Спойлер

#include "pch.h" 
#include <iostream> 
using namespace std;

int main(){
	for (int l = 20 * 2, i = l; i < (l /2+1) * l; i++){
		if (i != l && !(i % l)) cout << endl;
		i % l >= l - (i / l + (i / l - 1)) ? cout << 'x' : cout << ' ';}cout << "\r\n";
return 0;}

 

 

 

Результат с пробелом

Спойлер

6551aae93ddf.jpg

Результат с '0' вместо пробела

Спойлер

bf9a32be96a1.jpg

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

'0' - здесь просто для наглядности что пирамида зеркальная и что начинается от левого края.

Ссылка на комментарий
Поделиться на другие сайты

Мне кажется, подобные задания бесполезные для практического применения. Не могу даже придумать, где бы подобный алгоритм/опыт пригодился. 

 

Спойлер

image.thumb.png.1928a077c075ae18e707126eb246dea4.png

image.png.7a9b8754abebe26045e2adff7052ab46.png

 

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, partoftheworlD сказал:

 

  Показать контент

image.thumb.png.1928a077c075ae18e707126eb246dea4.png

image.png.7a9b8754abebe26045e2adff7052ab46.png

 

Интересный вариант! Более простой чем у меня.

Наверно это от того, что я не использовал string(). Впрочем немудрено - ведь до string() я ещё не дошел.

 

1 час назад, partoftheworlD сказал:

Мне кажется, подобные задания бесполезные для практического применения. Не могу даже придумать, где бы подобный алгоритм/опыт пригодился.

Понял твою точку зрения. Возможно действительно так.

 

Мне думается это задание на запоминание правил написания кода, на запоминание употребляемых выражений, - словом для практики, также и на развитие мышления.

 

P.S. Написать без использования string() смог бы?

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

29 минут назад, Antonshka сказал:

P.S. Написать без использования string() смог бы?

Очень странно писать на C++ и не использовать std::string :) Это больше в алгоритмы тогда.

 

Очень советую начинать с вот этого прекрасного курса, ребята рассказывают вполне современный C++: https://www.coursera.org/specializations/c-plus-plus-modern-development

А дальше время и cppreference.com.

 

Ссылка на комментарий
Поделиться на другие сайты

3 минуты назад, srg91 сказал:

Очень странно писать на C++ и не использовать std::string :) Это больше в алгоритмы тогда.

 

Конечно странно.

Просто в книге Лафоре, это задание предваряет обьяснение std::string. Потому читающий не имеет возможности использовать такой метод. Отсюда и вопрос.

А курсы - по отзывам я понял, что они равносильны самостоятельному обучению. Разница лишь в том, что на курсах даётся материал более правильно последовательный. Но за совет спасибо.

Ссылка на комментарий
Поделиться на другие сайты

51 минуту назад, Antonshka сказал:

P.S. Написать без использования string() смог бы?

 

Конечно, но зачем лишние костыли, когда спецификация позволяет?

 

image.thumb.png.847140e5dd89db86488e5968254d2751.png

 

По мне, так это какие-то жесткие и не здоровые извращения.?

Ссылка на комментарий
Поделиться на другие сайты

40 минут назад, partoftheworlD сказал:

По мне, так это какие-то жесткие и не здоровые извращения.?

 

А давайте ещё в один цикл ? А, не увидел что подобное решение уже есть (но кажется у меня получилось чуть лаконичнее) :)

Спойлер

#include <iostream>

int main() {
    unsigned int height = 20, width = height * 2 - 1;
    unsigned char space = ' ', letter = 'X';
    for (unsigned int i = 1; i <= width * height; i++) {
        std::cout << ((i % width <= width - (i / width) * 2) ? space : letter); 
        if (!(i % width)) std::cout << std::endl;
    }
    return 0;
}

 

Спойлер


                                     X
                                   XXX
                                 XXXXX
                               XXXXXXX
                             XXXXXXXXX
                           XXXXXXXXXXX
                         XXXXXXXXXXXXX
                       XXXXXXXXXXXXXXX
                     XXXXXXXXXXXXXXXXX
                   XXXXXXXXXXXXXXXXXXX
                 XXXXXXXXXXXXXXXXXXXXX
               XXXXXXXXXXXXXXXXXXXXXXX
             XXXXXXXXXXXXXXXXXXXXXXXXX
           XXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

 

 

43 минуты назад, Antonshka сказал:

Но за совет спасибо.

 

После каждой темы ещё дополнительно тестовое задание с проверкой автоматической системой и в конце - курсовой.

 

  • Смешно 1
Ссылка на комментарий
Поделиться на другие сайты

8 минут назад, srg91 сказал:

 

А давайте ещё в один цикл ?

  Скрыть контент


#include <iostream>

int main() {
    unsigned int height = 20, width = height * 2 - 1;
    unsigned char space = ' ', letter = 'X';
    for (unsigned int i = 1; i <= width * height; i++) {
        std::cout << ((i % width <= width - (i / width) * 2) ? space : letter); 
        if (!(i % width)) std::cout << std::endl;
    }
    return 0;
}

 

 

 

Работает исправно, но печатает со второй строки. По задумке нужно с первой.

Ссылка на комментарий
Поделиться на другие сайты

26 минут назад, Antonshka сказал:

Работает исправно, но печатает со второй строки. По задумке нужно с первой.

 

Да, забавно, я и не заметил. Но похоже лучше уже не сделаю, я очень плох в алгоритмике )

 

 

Ссылка на комментарий
Поделиться на другие сайты

В 03.04.2019 в 23:58, Antonshka сказал:

несколько часов

В 04.04.2019 в 09:00, Xipho сказал:

где-то минуты три

В 04.04.2019 в 14:29, partoftheworlD сказал:

Конечно

В 04.04.2019 в 15:04, srg91 сказал:

А давайте ещё в один цикл

 

Кто-нибудь сможет решить задание вообще без использования for, while, do, recursive function, string(), но с тем же cout?

 

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

Сегодня начал читать главу "функции". Возник вопрос.

@Xipho , почему в твоём скрипте код имеет такой вид

Спойлер

void DrawLine(int tabs);

int main()
{
    int tabs = 20;
    DrawLine(tabs);
    return 0;
}

void DrawLine(int tabs) {
}

 

 

вместо такого

Спойлер

void DrawLine(int); // без tabs

int main()
{
    int tabs = 20;
    DrawLine(tabs);
    return 0;
}

void DrawLine(int tabs) {
}

 

 

или такого?

Спойлер

void DrawLine(int); // без tabs

int main()
{                  
 // без int tabs
    DrawLine(20);
    return 0;
}

void DrawLine(int tabs) {
}

 

 

 

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

void DrawLine(int);

а определение функции должно содержать возвращаемый тип функции "void", имя функции, типы и имена а̶р̶г̶у̶м̶е̶н̶т̶о̶в параметров функции в том же порядке.

void DrawLine(int tabs) {
}

 

Больше всего мне интересно почему у тебя в объявлении функции указан не только тип, но и имя аргумента.

Спрашиваю для того, чтобы понять как на самом деле нужно объявлять.

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Больше всего мне интересно почему у тебя в объявлении функции указан не только тип, но и имя аргумента.

Наверно нашёл ответ в интернете - "Имена аргументов, при объявления прототипов являются необязательными."

 

Вариант решения задания без for, while, do, recursive function, string(), но с тем же cout

Спойлер

#include "pch.h" 
#include <iostream> 
using namespace std;

int main(){
	int l = 20 * 2, i = l;
	l1: if (i < (l / 2 + 1) * l){
	if (i != l && !(i % l)) cout << endl;
	i % l >= l - (i / l + (i / l - 1)) ? cout << 'x' : cout << ' '; ++i; goto l1;}
	cout << "\r\n";
return 0;}

 

 

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Вариант решения задания без for, while, do, recursive function, string()

GOTO это тот же jmp label(цикл) и считается дурным тоном использовать его.

  • Понравилось 1
Ссылка на комментарий
Поделиться на другие сайты

11 минут назад, partoftheworlD сказал:

GOTO это тот же jmp label(цикл) и считает дурным тоном использовать его.

Порой он полезен.

 

Кстати, как оказалось в оригинале книги пирамида не выравнивается по правому краю, а имеет вид -

           x

         xxx

       xxxxx

 

У тебя правда она получилась немного кривоватая, наверно это от того, что разница между количеством "x" не 2 а 1..

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Порой он полезен.

Как говорилось в одной книге, кажется Страуструпа. "Если есть смысл в использовании goto, то стоит задуматься о том, чтобы переписать код"
Проблемы с использованием goto еще обсуждались в 1968 году, т.е да он как бы не плох, но вреда от него больше, чем пользы, особенно если это крупный проект.

 

your slow connection sucks, get a faster one to see this image

 

1 час назад, Antonshka сказал:

У тебя правда она получилась немного кривоватая

Ну я "программист", а не художник, пусть красивостями другие занимаются.?

Ссылка на комментарий
Поделиться на другие сайты

7 часов назад, Antonshka сказал:

Больше всего мне интересно почему у тебя в объявлении функции указан не только тип, но и имя аргумента.

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

 

6 часов назад, Antonshka сказал:

goto l1;

Зло злейшее и никогда так не делай больше.

 

7 часов назад, Antonshka сказал:

DrawLine(20);

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

Ссылка на комментарий
Поделиться на другие сайты

31 минуту назад, Xipho сказал:

...

Понятно, буду знать.

 

Что если использовать "goto" в такой ситуации?

Спойлер

#include "pch.h" 
#include <iostream> 

using namespace std;

int main()
{
	int a, b, c, d;
	char dummy = 'a';
	char method = 'a';
	char stop = 'y';
	while (stop != 'n')
	{
		cout << "enter first fraction (a / b): "; cin >> a >> dummy >> b;
		cout << "enter second fraction (c / d): "; cin >> c >> dummy >> d;
		cout << "method: "; cin >> method;
		switch (method)
		{
		case '+':cout << a * d + b * c << " / " << b * d << endl; break;
		case '-':cout << a * d - b * c << " / " << b * d << endl; break;
		case '*':cout << a * c << " / " << b * d << endl; break;
		case '/':cout << a * d << " / " << b * c << endl; break;
		default: cout << "wrong method" << endl;
		}
	metka:
		cout << "calculate again? (y\\n): "; cin >> stop;
		if (stop == 'y' || stop == 'n')
			if (stop == 'n')
				break;
			else
				continue;
		else
			cout << "wrong answer" << endl;
		goto metka;
	}
	return 0;
}

 

Этот скрипт на задание из книги. Первое что мне пришло в голову, это использовать goto для прыжка назад.

Ссылка на комментарий
Поделиться на другие сайты

Немного лучше так.

 

Спойлер

#include <iostream> 

using namespace std;

void header(char dummy, int &a, int &b, int &c, int &d)
{
	cout << "enter first fraction (a / b): ";
	cin >> a >> dummy >> b;
	cout << "enter second fraction (c / d): ";
	cin >> c >> dummy >> d;
	cout << "method: ";
}

bool calculate(char m, int &a, int &b, int &c, int &d)
{
	switch (m)
		{
			case '+':cout << a * d + b * c  << " / "          << b * d << endl; break;
			case '-':cout << a * d - b * c  << " / "          << b * d << endl; break;
			case '*':cout << a * c          << " / "          << b * d << endl; break;
			case '/':cout << a * d          << " / "          << b * c << endl; break;
			default : cout << "wrong method" << endl; return 0;
		}
	return 1;
}

int main()
{
	int a, b, c, d;
	char dummy  = 'a';
	char method = 'a';
	char stop   = 'y';
	while (stop != 'n')
	{
		header(dummy, a, b, c, d);
		cin >> method;
		if(calculate(method, a, b, c, d))
		{
			cout << "calculate again? (y\\n): "; 
			cin >> stop;
			
			switch(stop)
			{
				case 'y': continue;
				case 'n': break;
				default : cout << "wrong answer" << endl; return 0;
			}

		}
		else
		{
			break;
		}

	}
	return 0;
}

 


Немного офтопа о cpp. Т.к. это лучшее объяснение как работать с языком.


Цитата

И тут мы поняли, что многие не знают как правильно пользоваться этой функцией. Так вот, правильное использование — не пользоваться.

 


 

 

Ссылка на комментарий
Поделиться на другие сайты

10 часов назад, partoftheworlD сказал:

Немного лучше так.

 

  Скрыть контент


#include <iostream> 

using namespace std;

void header(char dummy, int &a, int &b, int &c, int &d)
{
	cout << "enter first fraction (a / b): ";
	cin >> a >> dummy >> b;
	cout << "enter second fraction (c / d): ";
	cin >> c >> dummy >> d;
	cout << "method: ";
}

bool calculate(char m, int &a, int &b, int &c, int &d)
{
	switch (m)
		{
			case '+':cout << a * d + b * c  << " / "          << b * d << endl; break;
			case '-':cout << a * d - b * c  << " / "          << b * d << endl; break;
			case '*':cout << a * c          << " / "          << b * d << endl; break;
			case '/':cout << a * d          << " / "          << b * c << endl; break;
			default : cout << "wrong method" << endl; return 0;
		}
	return 1;
}

int main()
{
	int a, b, c, d;
	char dummy  = 'a';
	char method = 'a';
	char stop   = 'y';
	while (stop != 'n')
	{
		header(dummy, a, b, c, d);
		cin >> method;
		if(calculate(method, a, b, c, d))
		{
			cout << "calculate again? (y\\n): "; 
			cin >> stop;
			
			switch(stop)
			{
				case 'y': continue;
				case 'n': break;
				default : cout << "wrong answer" << endl; return 0;
			}

		}
		else
		{
			break;
		}

	}
	return 0;
}

 

 

 

Спасибо, интересный способ. Единственное что мне пока не понятно -

Спойлер

if (calculate(method, a, b, c, d))
		{
			cout << "calculate again? (y\\n): ";
			cin >> stop;

			switch (stop)
			{
			case 'y': continue;
			case 'n': break;
			default: cout << "wrong answer" << endl; return 0; //как влияет return 0 на программу?
			}

		}

 

 

Функция calculate и оператор switch в определенной ситуации могут вернуть - return 0.

Если calculate  вернет 0, то условие "if (calculate(method, a, b, c, d))" - будет ложно, и сработает brear для цикла while (stop != 'n'), - этот момент понятен.

Не понятно почему while (stop != 'n') зависит от этого возвращаемого нуля - "default: cout << "wrong answer" << endl; return 0;". Ведь в условии выполнения while только значение переменной stop. Или этот 0 возвращается для int main()?

 

Если 0 для while , то верно ли то, что любой цикл, будь то for, while, do, можно завершить не только изменив условие цикла или выполнив break, но и вернув ему (циклу) 0? А значит можно записать код так?

			switch (stop)
			{
			case 'y': continue;
			case 'n': return 0; //case 'n': break;
			default: cout << "wrong answer" << endl; return 0;
			}

А если 0 из  "default: cout << "wrong answer" << endl; return 0;" для int main(), то значит ли это то, что return 0 минует все множество вложенных циклов, и всегда предназначен для текущей конкретной фунции (для возврата текущей функцией в вызывающий её оператор этого нуля (или может не 0, а чего другого).

Если при выполнении функции случится выполниться методу "return чего либо", например в середине функции, то значит ли это то, что функция на этом самом месте немедленно прекратит свою работу, вернув результат, несмотря на то, что другая часть/части этой функции также желали быть исполненными?

 

Ответ на эти вопросы я возможно ещё встречу в книге, но мне уже сейчас хочется его узнать.

 

P.S. если ввести не 'y' и не 'n' программа завершится. Но что если нужно снова спросить о желании расчёта? Ведь GOTO я и использовал для этого.

 

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

3 часа назад, Antonshka сказал:

Если calculate  вернет 0, то условие "if (calculate(method, a, b, c, d))" - будет ложно, и сработает brear для цикла while (stop != 'n'), - этот момент понятен.

Не понятно почему while (stop != 'n') зависит от этого возвращаемого нуля - "default: cout << "wrong answer" << endl; return 0;". Ведь в условии выполнения while только значение переменной stop. Или этот 0 возвращается для int main()?

 

calculate возвращает состояние 1 если посчиталось, 0 при wrong method и выходит из calculate, ведь какой смысл если вычисления не удались выдавать 
 

cout << "calculate again? (y\\n): "; 

 

 

3 часа назад, Antonshka сказал:

default: cout << "wrong answer" << endl; return 0; //как влияет return 0 на программу?

 

выход не из цикла, а сразу из main для завершения программы. Не лучший способ, но за ошибки надо платить, хотя бы выходом из программы.?

 

3 часа назад, Antonshka сказал:

Но что если нужно снова спросить о желании расчёта?

Ну что ж, придется быть внимательным и вводить всегда "y". 

 

3 часа назад, Antonshka сказал:

Если 0 для while , то верно ли то, что любой цикл, будь то for, while, do, можно завершить не только изменив условие цикла или выполнив break, но и вернув ему (циклу) 0? А значит можно записать код так?

Не, break выходит из цикла/свича, return выходит из метода.

 

т.е break используется, когда не надо завершать программу и продолжать выполнение/повторение. return используется, когда надо завершить выполнение метода.

 

3 часа назад, Antonshka сказал:

Если при выполнении функции случится выполниться методу "return чего либо", например в середине функции, то значит ли это то, что функция на этом самом месте немедленно прекратит свою работу, вернув результат, несмотря на то, что другая часть/части этой функции также желали быть исполненными?

Именно так.

 


 

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.