Форум программистов, компьютерный форум CyberForum.ru

C++

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 2744, средняя оценка - 4.89
ForEveR
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 3
#1

Задачи для тренировки и лучшего понимания - C++

15.07.2010, 05:53. Просмотров 341691. Ответов 1272
Метки нет (Все метки)

Ребят. Кто-нибудь может дать задачу для тренировки? Приблизительно по всему курсу С++. Буду благодарен за сложную задачу, но которую способен сделать новичок-любитель. Затраты сил-времени не важно. Главное, чтобы это было интересно и не слишком рутинно. + Если найдется человек который даст задачу просьба помогать с кодом, который я буду себя скидывать. Не переписывать за меня, но указывать на ошибки и желательно объяснять. Заранее спасибо.

Список задач, решение которых присутствует в данной теме:
Лучшие ответы (59)
Сообщение: #857841 Сообщение: #857861 Сообщение: #858352 Сообщение: #859371 Сообщение: #860160 Сообщение: #860255 Сообщение: #860259 Сообщение: #860317 Сообщение: #860368 Сообщение: #860466 Сообщение: #860508 Сообщение: #860720 Сообщение: #861091 Сообщение: #862174 Сообщение: #862617 Сообщение: #867259 Сообщение: #870298 Сообщение: #872053 Сообщение: #876456 Сообщение: #880114 Сообщение: #882889 Сообщение: #884418 Сообщение: #886414 Сообщение: #886989 Сообщение: #887733 Сообщение: #888464 Сообщение: #888487 Сообщение: #888941 Сообщение: #888947 Сообщение: #889040 Сообщение: #889450 Сообщение: #889587 Сообщение: #891772 Сообщение: #891790 Сообщение: #891862 Сообщение: #897758 Сообщение: #897782 Сообщение: #906325 Сообщение: #907991 Сообщение: #943672 Сообщение: #943700 Сообщение: #967735 Сообщение: #1053777 Сообщение: #1054209 Сообщение: #1083853 Сообщение: #1083928 Сообщение: #1131058 Сообщение: #1131359 Сообщение: #1273743 Сообщение: #1275465 Сообщение: #1276743 Сообщение: #1279215 Сообщение: #1282583 Сообщение: #1309088 Сообщение: #1315633 Сообщение: #1366395 Сообщение: #1550164 Сообщение: #1603678 Сообщение: #1604364
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.07.2010, 05:53     Задачи для тренировки и лучшего понимания
Посмотрите здесь:
C++ Элементарные программы, для лучшего понимания языка...
Нужны задачи для тренировки C++
Нужны задачи для тренировки C++
C++ Нужны простые задачи для тренировки
C++ Какая база требуется для понимания C++?
C++ Builder Прошу примеров для понимания INDY
C++ Нужен пример рекурсивной функции для понимания ее назначения и практической пользы
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nikkka
25.07.2010, 16:19     Задачи для тренировки и лучшего понимания
  #201

Не по теме:

посмотрел, задачи трудные :-s

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
В астрале
Эксперт С++
7969 / 4731 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 3
27.07.2010, 00:34  [ТС]     Задачи для тренировки и лучшего понимания #202
nikkka, А вы ноктюрн сыграть смогли бы на флейте водосточных труб? ©

Добавлено через 15 часов 26 минут
Где же интересные задачки?( Кончились?
Kastaneda
Форумчанин
Эксперт С++
4479 / 2841 / 227
Регистрация: 12.12.2009
Сообщений: 7,224
Записей в блоге: 1
Завершенные тесты: 1
27.07.2010, 07:59     Задачи для тренировки и лучшего понимания #203
Вот задачка с одного известного ресурса. Многие наверное ее там видели, но для тех, кто не знает будет интересно)
Нужно заменить ровно один (любой) символ в следующей строке, причём так, чтобы она скомпилилась и было выведено ровно 20 звёздочек:
C++
1
int main() { int i, n = 20; for (i = 0; i < n; i--) { printf("*"); } }
Для тех, кто «набил руку» на особенностях C, задачка, скорее всего, сложности не представляет; но существует как минимум 3 решения, и если вы нашли одно — то это не повод расслабиться А может быть, вы найдёте ещё четвёртое, пятое..?
nikkka
Мат в 32 хода
235 / 170 / 8
Регистрация: 10.09.2009
Сообщений: 1,096
27.07.2010, 09:13     Задачи для тренировки и лучшего понимания #204
Решение №1

C++
1
int main() { int i, n = 20; for (i = 0; i < n; n--) { printf("*"); } } //поменять i-- на n--

прошу присылать ответы в теге CUT.

Добавлено через 18 минут
Решение №2
C++
1
int main() { int i, n = 20; for (i = 0; i + n; i--) { printf("*"); } } //будет выводить символ пока i не станет равным -20, то есть пока n+i!=0, а 0 это false


Добавлено через 5 минут
всё, третее потом придумаю, сейчас времени нет...
Kastaneda
Форумчанин
Эксперт С++
4479 / 2841 / 227
Регистрация: 12.12.2009
Сообщений: 7,224
Записей в блоге: 1
Завершенные тесты: 1
27.07.2010, 10:46     Задачи для тренировки и лучшего понимания #205
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Я тоже эти 2 решения нашел, третье так и не смог, поэтому посмотрел в ответы. Там оказывается решение состоит в том, что добавляется один символ, что по-моему не совсем соответствует условию задачи. (кстати об этом решении я думал, но счел его некорректным)

Добавлено через 10 минут
Помните недавно задачку, сейчас случайно в инете нашел более подробное описание, почему данный код так себя ведет.
Кому интересно.
Неочевидная особенность в синтаксисе определения переменных
Предлагается совершенно невинный на вид кусок кода на C++. Здесь нет ни шаблонов, ни виртуальных функций, ни наследования, но создатели этого чудесного языка спрятали грабли посреди чистa поля.

struct A {
A (int i) {}
};

struct B {
B (A a) {}
};

int main () {
int i = 1;
B b(A(i)); // (1)
return 0;
}

* This source code was highlighted with Source Code Highlighter.


Вопрос: какой тип у переменной b? Совсем не тот, который можно было бы предположить на первый взгляд.


Анализ

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

Для начала добавим немного отладочной печати:
#include <iostream>
struct A {
A (int i) { std::cout << 'A';}
};

struct B {
B (A a) { std::cout << 'B';}
};

int main () {
int i = 1;
B b(A(i)); // (1)
return 0;
}

* This source code was highlighted with Source Code Highlighter.


Если попробовать запустить этот код, окажется, что вообще ничего не выводится. Но если заменить строку (1) на
B b(A(1));

внезапно всё начинает работать.

А теперь посмотрим внимательно на вывод компилятора при максимально включенных предупреждениях
$ g++ -W -Wall test.cpp
x.cpp:2: warning: unused parameter ‘i’
x.cpp:6: warning: unused parameter ‘a’
x.cpp: In function ‘int main()’:
x.cpp:10: warning: unused variable ‘i’

С первыми двумя строками всё понятно, действительно параметры конструкторов не используются. А вот последняя строка выглядит очень странно. Как переменная i оказалась неиспользуемой, если она используется в следующей строке?

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

#include <iostream>
#include <typeinfo>

struct A {
A (int i) {}
};

struct B {
B (A a) {}
};

int main () {
int i = 1;
B b(A(i)); // (1)
std::cout << typeid(b).name() << std::endl;
return 0;
}

* This source code was highlighted with Source Code Highlighter.


При компиляции GCC 4.3 результатом выполнения этой программы является строка
F1B1AE

в которой зашифрована нужная нам информация о типе переменной (конечно, другой компилятор выдаст другую строку, формат вывода type_info::name() в стандарте не описан и оставлен на усмотрение разработчика). Узнать же, что означают эти буквы и цифры, нам поможет c++filt.
$ c++filt -t F1B1AE
B ()(A)

Вот и ответ: это функция, принимающая на вход параметр типа A и возвращающая значение типа B.

Причина

Осталось понять, почему наша строка проинтерпретировалась таким неожиданным способом. Всё дело в том, что в объявлении типа переменной лишние скобки вокруг имени игнорируются. Например, мы можем написать
int (v);

и это будет означать в точности тоже самое, что
int v;


Поэтому многострадальную строку (1) можно без изменения смысла переписать, убрав лишнюю пару скобок:
B b(A i);

Теперь невооружённым взглядом видно, что b это объявление функции с одним аргументом типа A, которая возвращает значение типа B.

Заодно мы объяснили странный ворнинг о неиспользованной переменной i — действительно, она не имеет никакого отношения к формальному параметру i.

Workarounds

Нам осталось только объяснить компилятору, что же на самом деле мы от него хотим — то есть, получить переменную типа B, проинициализированную переменной типа A. Самый простой способ — добавить лишних скобок, вот так:
B b((A(i)));

или так:
B b((A)(i));

Этого достаточно, чтобы убедить парсер, что это не объявление функции.

Как альтернативу, можно использовать форму вызова конструктора с помощью присваивания, если только конструктор не объявлен explicit:
B b = A(i);

Несмотря на наличие знака '=', никакого лишнего копирования здесь не происходит, в чём можно легко убедиться, заведя в классе B приватный конструктор копирования.

А можно просто ввести дополнительную переменную:
A a(i);
B b(a);

Правда, при этом потребуется лишнее копирование переменной a, но во многих случаях это приемлемо.

Выберите тот способ, который кажется вам более понятным
nikkka
27.07.2010, 10:57
  #206

Не по теме:

Цитата Сообщение от Kastaneda Посмотреть сообщение
решение состоит в том, что добавляется один символ
ага, то есть можно не убирая какой то символ, добавить ещё?! другое дело...

Kastaneda
27.07.2010, 11:28
  #207

Не по теме:

Цитата Сообщение от nikkka Посмотреть сообщение

Не по теме:


ага, то есть можно не убирая какой то символ, добавить ещё?! другое дело...

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

Mr.X
Эксперт С++
3043 / 1688 / 265
Регистрация: 03.05.2010
Сообщений: 3,867
27.07.2010, 12:47     Задачи для тренировки и лучшего понимания #208
Цитата Сообщение от Kastaneda Посмотреть сообщение
Кому интересно.Как альтернативу, можно использовать форму вызова конструктора с помощью присваивания, если только конструктор не объявлен explicit:
C++
1
 B b = A(i);
М-да, это заставляет усомниться в справедливости рекомендации Дьюхэрста всегда применять прямую инициализацию (т.е. со скобками), а не инициализацию копированием (т.е. со знаком присваивания). Он мотивирует это тем, что стандарт только разрешает компиляторам неявно заменять инициализацию копированием прямой инициализацией, но не требует этого, т.е. возможны реализации, где этой неявной замены не происходит. Но, мне кажется, лучше пожертвовать эффективностью, чем смыслом.
Хохол
Эксперт C++
475 / 443 / 13
Регистрация: 20.11.2009
Сообщений: 1,292
27.07.2010, 13:22     Задачи для тренировки и лучшего понимания #209
Цитата Сообщение от Kastaneda Посмотреть сообщение
int main() { int i, n = 20; for (i = 0; i < n; i--) { printf("*"); } }
Третье решение
C++
1
int main() { int i, n = 20; for (i = 0;-i < n; i--) { printf("*"); }}
Заменили пробел на минус.
Kastaneda
Форумчанин
Эксперт С++
4479 / 2841 / 227
Регистрация: 12.12.2009
Сообщений: 7,224
Записей в блоге: 1
Завершенные тесты: 1
27.07.2010, 13:32     Задачи для тренировки и лучшего понимания #210
Вообще то я в своем предыдущем посте имел ввиду '+' на '-', но решение правильное)
rangerx
1932 / 1541 / 141
Регистрация: 31.05.2009
Сообщений: 2,909
27.07.2010, 14:00     Задачи для тренировки и лучшего понимания #211
Цитата Сообщение от Kastaneda Посмотреть сообщение
сейчас случайно в инете нашел более подробное описание
И что здесь сказано такого чего не сказал я? )) В стандарте кстати это п. 8.x(8.2 или 8.3... точно не помню )) )
По теме: Попробуйте реализовать калькулятор, который бы умел считать вводимые пользователем выражения, например (2+10)*2+1.0/2
---
P.S. Ну и ещё такое несложное задание: написать макрос, котрый бы выполнял функцию такого цикла как foreach, т.е.
C++
1
2
3
4
foreach(int i, array)
{
    std::cout << i << std::endl; 
}
должен поочерёдно вывести на экран все элементы массива array(массив естественно НЕ динамический).
nikkka
Мат в 32 хода
235 / 170 / 8
Регистрация: 10.09.2009
Сообщений: 1,096
27.07.2010, 14:11     Задачи для тренировки и лучшего понимания #212
rangerx, буду признателен если кто нить обяснит что такое макрос

Добавлено через 1 минуту
Хохол, блин, почему я сам не додумался... спасибо
Kastaneda
Форумчанин
Эксперт С++
4479 / 2841 / 227
Регистрация: 12.12.2009
Сообщений: 7,224
Записей в блоге: 1
Завершенные тесты: 1
27.07.2010, 14:28     Задачи для тренировки и лучшего понимания #213
Цитата Сообщение от nikkka Посмотреть сообщение
буду признателен если кто нить обяснит что такое макрос
Например:
C++
1
2
3
4
5
6
7
8
9
//Вспомогательный макрос для вывода строки и значения
#define PRINT (STR, VAR) \
cout<<STR " = "<<VAR<<endl;
//////////////////
int main (){
int x=5;
PRINT ("X",x);
/////////////////////
}
nikkka
Мат в 32 хода
235 / 170 / 8
Регистрация: 10.09.2009
Сообщений: 1,096
27.07.2010, 14:33     Задачи для тренировки и лучшего понимания #214
Kastaneda, но для этого же функции существуют...
Nameless One
Эксперт С++
5769 / 3418 / 255
Регистрация: 08.02.2010
Сообщений: 7,444
27.07.2010, 14:41     Задачи для тренировки и лучшего понимания #215
Цитата Сообщение от nikkka Посмотреть сообщение
Kastaneda, но для этого же функции существуют...
Есть кое-что, что не могут сделать функции. Существуют различные примеры, демонстрирующий операторы, доступные препроцессору (#, ## и #@). В частности, предыдущий пример можно переписать так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
 
#define print(X) std::cout << #X << " = " << X << std::endl;
 
int main()
{
    int a = 5;
    std::string buffer("Preproccessor's operator #");
    print(a);
    print(buffer);
    system("pause");
    return EXIT_SUCCESS;
}
Добавлено через 4 минуты
Есть также существенные различия между макросами и функциями:
  1. Функции "вызываются", что увеличивает затраты на время выполнения программы, в то время как препроцессор "подставляет" тело макроса в исходный код программы, что увеличивает ее размер. Таким образом, макросы выполняются быстрее функций
  2. Для макросов отсутствует проверка типов, ввиду того, что в определении макроса типы параметров не указываются. Это может стать источником ошибок
nikkka
Мат в 32 хода
235 / 170 / 8
Регистрация: 10.09.2009
Сообщений: 1,096
27.07.2010, 14:48     Задачи для тренировки и лучшего понимания #216
Цитата Сообщение от Nameless One Посмотреть сообщение
Есть кое-что, что не могут сделать функции.
а... на пример функция должна принимать определённые тип, а макрос может любой, так? и не смотря на то что для подобных случеев есть перегрузка функции, соглашаюсь что это удобнее чем писать на каждый тип по функции...
спасибо!...

Добавлено через 3 минуты
Nameless One, а что будет если я создам макрос который выводит ВТОРОЙ элемент массива, а передам ему тип int?

Добавлено через 53 секунды
будет то же самое как если бы я написал
C++
1
int i=5; cout<<i[2]
?
Nameless One
Эксперт С++
5769 / 3418 / 255
Регистрация: 08.02.2010
Сообщений: 7,444
27.07.2010, 15:00     Задачи для тренировки и лучшего понимания #217
Цитата Сообщение от nikkka Посмотреть сообщение
а... на пример функция должна принимать определённые тип, а макрос может любой, так?
Вообще-то я хотел акцентировать внимание именно на операторах, доступных препроцессору (и только препроцессору):
  1. Оператор "#" конвертирует параметр макроса в строку. В моем примере он использовался для того, чтобы вывести на экран имя переменной вместе с ее значением (опять-таки, независимо от типа переменной);
  2. Оператор "#@" действует подобно предыдущему оператору, но конвертирует параметр не в строку, а символ;
  3. Оператор "##" объединяет два идентификатора.



Добавлено через 7 минут
Цитата Сообщение от nikkka Посмотреть сообщение
соглашаюсь что это удобнее чем писать на каждый тип по функции...
Вот тут есть подвох. К примеру, можно написать макрос для вычисления минимума из двух элементов:
C
1
#define min(a, b) ( (a) < (b) ? (a) : (b) )
Но если "вызвать" этот макрос для двух строк С, то он не будет работать правильно, т.к. для сравнения строк используются специальные функции.
В данном случае лучше было бы использовать шаблонные функции и специализировать шаблон для const char*.

Добавлено через 2 минуты
Цитата Сообщение от nikkka Посмотреть сообщение
Nameless One, а что будет если я создам макрос который выводит ВТОРОЙ элемент массива, а передам ему тип int?
По идее, это ошибка. Но ms vc ее видит еще до компиляции. Как происходит дело с другими компиляторами/IDE, я не знаю.
rangerx
1932 / 1541 / 141
Регистрация: 31.05.2009
Сообщений: 2,909
27.07.2010, 15:24     Задачи для тренировки и лучшего понимания #218
Цитата Сообщение от Nameless One Посмотреть сообщение
Функции "вызываются", что увеличивает затраты на время выполнения программы, в то время как препроцессор "подставляет" тело макроса в исходный код программы, что увеличивает ее размер. Таким образом, макросы выполняются быстрее функций
Это справедливо скорее для C, чем для C++. В C++ есть такая штука как inline функции.
Цитата Сообщение от Nameless One Посмотреть сообщение
Вот тут есть подвох. К примеру, можно написать макрос для вычисления минимума из двух элементов:
C
1
#define min(a, b) ( (a) < (b) ? (a) : (b) )
Но если "вызвать" этот макрос для двух строк С, то он не будет работать правильно, т.к. для сравнения строк используются специальные функции.
Ну, про строки это ещё ничего:
C++
1
2
3
4
5
int a = 1;
int b = 2;    
min(++a, ++b);        
std::cout << "a: " << a << std::endl;
std::cout << "b: " << b << std::endl;
nikkka
Мат в 32 хода
235 / 170 / 8
Регистрация: 10.09.2009
Сообщений: 1,096
27.07.2010, 15:28     Задачи для тренировки и лучшего понимания #219
тело макроса заключено в собки "(" и ")", как я понял.
вот только правельно ли я понял...

Добавлено через 2 минуты
чё за... почему a=b?!?!?!?! О.О
Цитата Сообщение от rangerx Посмотреть сообщение
Ну, про строки это ещё ничего:
C++
1
2
3
4
5
int a = 1;
int b = 2; 
min(++a, ++b); 
std::cout << "a: " << a << std::endl;
std::cout << "b: " << b << std::endl;
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
27.07.2010, 15:38     Задачи для тренировки и лучшего понимания
Еще ссылки по теме:
C++ Киньте задачки для тренировки
Дайте задания для тренировки C++
Книги для тренировки/развития котелка и просто убийства времени C++
C++ Какой компилятор выбрать для лучшего изучения С++ по книге Берна Страуструпа?п
На соревнованиях по фигурному катанию оценки заносятся в компьютер. Составить программу для вывода на экран лучшего результата после каждого выступлен C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Nameless One
Эксперт С++
5769 / 3418 / 255
Регистрация: 08.02.2010
Сообщений: 7,444
27.07.2010, 15:38     Задачи для тренировки и лучшего понимания #220
Тело макроса - это все то, что идет после #define ИМЯ_МАКРОСА(ПАРАМЕТРЫ)
Скобки нужны для того, чтобы не напутать с приоритетами операций. К примеру, если проанализировать следующую программу:
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
 
#define sum(a, b) a + b
int main()
{
    int x = 5 * sum(2, 3);
    system("pause");
    return EXIT_SUCCESS;
}
Казалось бы, по задумке при подстановке макроса должно было получиться такое выражение:
C++
1
int x = 5 * (2 + 3);
Но получилось такое:
C++
1
int x = 5 * 2 + 3;
В результате, мы имеем совсем не то, что хотели.
Также параметрами макроса могут быть не отдельные объекты, а выражения, поэтому в теле макроса параметры лучше тоже заключать в скобки.
Наиболее "правильный" вариант должен был выглядеть так:
C++
1
2
#define sum(a, b) \
    ((a) + (b))
Заметь, здесь символ '\' означает перенос строки; его нужно использовать тогда, когда твой макрос не влезает в одну строку, иначе все последующие строки препроцессор не отнесет к макросу.
К макросам нужно относиться с осторожностью, что уже показал rangerx.

Добавлено через 2 минуты
Цитата Сообщение от nikkka Посмотреть сообщение
чё за... почему a=b?!?!?!?! О.О
Вспомни, что препроцессор производит подстановку тела макроса и что в параметрах макроса можно передавать выражение. Так что подсчитай, сколько раз выполнится инкремент для каждой из переменных (с учетом того, что последнее выражение тернарного оператора "?:" вычисляться не будет, т.к. условие оператора является истинным)
Yandex
Объявления
27.07.2010, 15:38     Задачи для тренировки и лучшего понимания
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru