C++ для начинающих
Модератор: Olej
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Очень много примеров и задач на C++ осталось в старой теме: примеры задач при изучении C++.
Там всё можно скачать и более-менее прокомментировано.
Там всё можно скачать и более-менее прокомментировано.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Ещё ресурс, где показано множество формулировок и решений задач на C++:
C++ для приматов
Если отбросить некоторую ... претенциозность названия сайта о приматах, то очень приличная подборка задач и решений.
Рекомендую.
P.S. Относительно приматов, это совсем не сразу понятно из ресурса - это у них такой профессиональный юмор ... кондовый : приматы - ПРИкладныеМАТематикЫ ... факультет у них такой приматов
C++ для приматов
... доктор Мазурок Игорь Евгеньевич и его студенты...Начальный курс программирования для студентов направления "Прикладная математика" Одесского национального университета имени И.И.Мечникова
Если отбросить некоторую ... претенциозность названия сайта о приматах, то очень приличная подборка задач и решений.
Рекомендую.
P.S. Относительно приматов, это совсем не сразу понятно из ресурса - это у них такой профессиональный юмор ... кондовый : приматы - ПРИкладныеМАТематикЫ ... факультет у них такой приматов
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Вот хорошая задача попрактиковаться:
- есть строка, в которой записано произвольное скобочное выражение (скобки (), [], или {})
- написать функцию check(), которая проверяет правильность этого скобочного выражения:
Причём здесь интересны 2 варианта: когда строка задана в стиле C как char*, и когда это С++ тип string:
Ну, наконец, здесь можно попрактиковаться в переопределённых функциях C++, и записать эту задачу единым тестовым файлом, что-то типа:
Остаётся только вписать то, что закомментировано под "реализация" ...
Ну и последним хорошим дополнением к задаче было бы: записать это как можно более кратким кодом.
- есть строка, в которой записано произвольное скобочное выражение (скобки (), [], или {})
- написать функцию check(), которая проверяет правильность этого скобочного выражения:
Код: Выделить всё
check("a(b)") -> true
check("[{}]") -> true
check("[(]") -> false
check("}{") -> false
check("z([{}-()]{a})") -> true
check("") -> true
Код: Выделить всё
bool check( char* );
bool check( string );
Код: Выделить всё
#include <iostream>
#include <cstring>
using namespace std;
bool check( string str ) {
bool result = true;
// реализация: result = ...
return result;
}
bool check( char* str ) {
bool result = true;
// реализация: result = ...
return result;
}
int main( int argc, char **argv ) {
string test[] = {
"a(b)", "[{}]", "[(]", "}{", "z([{}-()]{a})", ""
};
for( int i = 0; i < sizeof( test ) / sizeof( test[ 0 ] ); i++ )
cout << "'" << test[ i ] << "'" << " ==> "
<< ( check( test[ i ] ) ? "true" : "false" ) << " ... "
<< ( check( test[ i ].c_str() ) ? "true" : "false" )
<< endl;
return 0;
}
Код: Выделить всё
olej@nvidia ~/tmp $ g++ lex.cc -o lex
olej@nvidia ~/tmp $ ./lex
'a(b)' ==> true ... true
'[{}]' ==> true ... true
'[(]' ==> true ... true
'}{' ==> true ... true
'z([{}-()]{a})' ==> true ... true
'' ==> true ... true
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Интерес этой задачи в том, что при ... более глубоких потребностях анализа скобочного выражения, его всё-равно придётся разбивать на вложенные токены, тем или иным способом.Olej писал(а): - написать функцию check(), которая проверяет правильность этого скобочного выражения:
Способов таких много ... поэтому задача (разных решений) остаётся.
Но если задачу сформулировать именно так, в усечённом виде, что нужно только проверить синтаксическую правильность, но не делать разбора получаемых токенов, то её можно и решить в таком же кастрированном стиле:
- заталкивать в стек открывающий разделитель текущего найденного токена;
- искать ближайший закрывающий разделитель текущего найденного токена...
- ... если он не совпадает с открывающим - это ошибка структуры
- ... если совпадает, то это завершение токена - выталкиваем из стека закрывающий символ-разделитель и продолжаем последовательный разбор строки.
Вот что-то такое:
Код: Выделить всё
#include <iostream>
#include <cstdint>
#include <cstring>
#include <vector>
using namespace std;
const char *delim[ 2 ] = { "([{", ")]}" };
bool check( const string& s ) {
string stack = "";
for( uint i = 0; i < s.size(); i++ ) {
const char c = s[ i ];
if( index( delim[ 0 ], c ) != NULL ) {
stack.push_back( c );
continue;
}
const char *z;
if( NULL == ( z = index( delim[ 1 ], c ) ) )
continue;
if( stack.empty() ||
stack.back() != delim[ 0 ][ z - delim[ 1 ] ] )
return false;
stack.pop_back();
}
return stack.empty();
}
bool check( const char* p ) {
vector<char> stack( 0 );
for( ; *p != '\0'; p++ ) {
if( index( delim[ 0 ], *p ) != NULL ) {
stack.push_back( *p );
continue;
}
const char *z;
if( NULL == ( z = index( delim[ 1 ], *p ) ) )
continue;
if( stack.empty() ||
stack.back() != delim[ 0 ][ z - delim[ 1 ] ] )
return false;
stack.pop_back();
}
return stack.empty();
}
int main( int argc, char **argv ) {
string test[] = {
"a(b)", "[{}]", "[(]",
"}{", "z([{}-()]{a})", "",
"a( b{c) d}e", "a(b{c[d]e}f)g", "a(c[c]{d(e)})f"
};
for( uint i = 0; i < sizeof( test ) / sizeof( test[ 0 ] ); i++ )
cout << "'" << test[ i ] << "'" << " ==> "
<< ( check( test[ i ] ) ? "true" : "false" ) << " ... "
<< ( check( test[ i ].c_str() ) ? "true" : "false" )
<< endl;
return 0;
}
Код: Выделить всё
olej@nvidia ~/2015_WORK/in.WORK/SchoolCPP/brackets $ ./lexv
'a(b)' ==> true ... true
'[{}]' ==> true ... true
'[(]' ==> false ... false
'}{' ==> false ... false
'z([{}-()]{a})' ==> true ... true
'' ==> true ... true
'a( b{c) d}e' ==> false ... false
'a(b{c[d]e}f)g' ==> true ... true
'a(c[c]{d(e)})f' ==> true ... true
- Вложения
-
- lexv.cc
- (1.5 КБ) 334 скачивания
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Этот ресурс чем мне очень нравится (IMHO)?Olej писал(а): ... доктор Мазурок Игорь Евгеньевич и его студенты...
Если отбросить некоторую ... претенциозность названия сайта о приматах, то очень приличная подборка задач и решений.
Своей идеологией обучения языку C++ - Hello, World!
В качестве базового языка программирования был выбран С++. Выбран не потому, что он наиболее подходит или наиболее удобен для начального изучения программирования. Просто я твердо убежден, что потенциальный профессиональный программист вынужден начинать именно с этого языка. Достаточно давно так сложилось, что без уверенного знания С++ практические невозможно стать серьёзным специалистом в области программирования и разработки программного обеспечения. Если бы у меня действительно был выбор, я скорее всего отклонился от верного курса и выбрал Java или Scala, или даже продемонстрировал для начала воздушный цирк Monty Python. Но выбора нет, нужно делать как следует делать…
Они ломают тот сложившийся везде идиотизм, когда лекторами в университетах по C++ являются вчерашние аспиранты, не представляющие языка C как базы C++, и излагающие C++ через задницу (через MS Visual Studio), как будто до этой задницы ничего в природе не существовало!Этот суржик как раз и поясняет наши ближайшие планы – мы будем изучать язык программирования Си, но только в той его части, которая допустима и в С++ 11. При этом вполне допустимо (но не особенно поощряется) использование “настоящего” Си. Делается это в надежде принести всю возможную пользу от изучения языка программирования Си и создать как можно меньше “крепатур“, затрудняющих переход на объектные и почти функциональные рельсы С++.Код: Выделить всё
#include <iostream> int main() { printf("Hello, World!"); return 0; }
C++ нужно изучать через C!
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
... а C нужно изучать через GCC!Olej писал(а):C++ нужно изучать через C!
Так что те, кто приступает к C++ через MS Visual Studio оказываются в сильно незавидном положении...
Но всё это лирика...
Но вот если задачу сформулировать ... ближе к жизни, что нужно не только оценить синтаксическую правильность выражения но и выполнить само выражение, то тут таким хитрым трюком не обойтись.Olej писал(а): Но если задачу сформулировать именно так, в усечённом виде, что нужно только проверить синтаксическую правильность, но не делать разбора получаемых токенов, то её можно и решить в таком же кастрированном стиле:
Т.е. как в LISP требуется выполнить выражение:
Код: Выделить всё
( f1 1 2 ( f2 3 4 ) )
Код: Выделить всё
{ 1 + [ 2 / 3 ] - ( 4 - 5 ) }
Вот здесь, но уже для преподавателей, непаханное поле деятельности для формулирования новых учебных (тестовых) красивых задач.
(красивыми я считаю задачи, которые не требуют сложных привходящих объяснений, большого числа специальных данных для выполнения, долгих разъяснений как это должно работать... - коротко, в 2 слова + алгоритм и код, которые потребуют изрядной изобретательности).
Из той же области (скобочных вычислений) хорошая задача:
- преобразовать выражение в той же скобочной записи его стековый эквивалент - обратную польскую запись, которая не требует ни скобок ни предопределённых приоритетов операций для вычислений.
Например:
Код: Выделить всё
( [a + b] ) - c * ( d + e ) ) => a . b + c . d . e + * -
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Мне тут задали задачку ...
P.S. Причём задали в совершенно реальных условиях:
- это тестирование, в несколько этапов, проводимое при отборе на работу кандидатов одной израильской фирмой. )
- я к ним напросился на вакансию ... хотя совершенно не уверен, что стану у них работать, даже при самом благоприятном стечении обстоятельств
- ... т.е. они думают, что тестируют меня на вакансию разработчика C++, а я думаю, что тестирую их на их методику тестирования и тестовые задачи ...
- вот так и живём ... уже 3 тура
Но вся эта история имеет очень любопытное отношение к обучающимся (и обучающим ) программированию на C/C++.
Это целый класс задач для обучения и контроля ... точнее даже целых 2 класса:
1. улучшить (или изменить) предлагаемый код ... по каким-то признакам, чаще всего это упрощение и укорочение, причём для этих задач я имею виду формально улучшить код, особенно сильно не вникая в то, что он делает...
2. понять что делает предложенный фрагмент кода и попытаться его улучшить, или написать эквивалент в другой технике.
Это задачи на а). умение читать чужой код + б). глубокое понимание синтаксических конструкций (для улучшения).
А теперь оригинал задачи, предложенный из Израиля:
P.S. Причём задали в совершенно реальных условиях:
- это тестирование, в несколько этапов, проводимое при отборе на работу кандидатов одной израильской фирмой. )
- я к ним напросился на вакансию ... хотя совершенно не уверен, что стану у них работать, даже при самом благоприятном стечении обстоятельств
- ... т.е. они думают, что тестируют меня на вакансию разработчика C++, а я думаю, что тестирую их на их методику тестирования и тестовые задачи ...
- вот так и живём ... уже 3 тура
Но вся эта история имеет очень любопытное отношение к обучающимся (и обучающим ) программированию на C/C++.
Это целый класс задач для обучения и контроля ... точнее даже целых 2 класса:
1. улучшить (или изменить) предлагаемый код ... по каким-то признакам, чаще всего это упрощение и укорочение, причём для этих задач я имею виду формально улучшить код, особенно сильно не вникая в то, что он делает...
2. понять что делает предложенный фрагмент кода и попытаться его улучшить, или написать эквивалент в другой технике.
Это задачи на а). умение читать чужой код + б). глубокое понимание синтаксических конструкций (для улучшения).
А теперь оригинал задачи, предложенный из Израиля:
Simplify the implementation below as much as you can.
Even better if you can also improve performance as part of the simplification!
FYI: This code is over 35 lines and over 300 tokens, but it can be written in 5 lines and in less than 60 tokens.
Код: Выделить всё
char *func1(char *s, char a, char b)
{
char *aptr;
char *bptr;
char *res;
int i;
if (s[0] == '\0')
{
if ((a == '\0') || (b == '\0'))
return &(s[0]);
else
return NULL;
}
i = 0;
aptr = NULL;
bptr = NULL;
while (aptr == NULL && bptr == NULL)
{
if (s[i] == a)
aptr = s+i;
if (s[i] == b)
bptr = s+i;
if (s[i] == '\0')
{
if ((aptr != s+i) && (bptr != s+i))
return NULL;
}
i++;
}
if (aptr == NULL)
res = bptr;
else if (bptr == NULL)
res = aptr;
else if (aptr < bptr)
res = aptr;
else if (bptr < aptr)
res = bptr;
else
res = aptr;
return res;
}
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Они ещё предлагают это делать на скорость: через 30 минут они отключают окно редактирования.Olej писал(а): А теперь оригинал задачи, предложенный из Израиля:
Но, по-моему, это как-раз глупость...
Модифицированный мой вариант (тот, который а). сделан в 30 минут и, поэтому, черновой и б). сделан по принципу "не особенно вникая что делает код", т.е. как выше названо класс 1):
Код: Выделить всё
char *func2(char *s, char a, char b) {
char *aptr = strchr( s, a ),
*bptr = strchr( s, b );
return 0 == strlen( s ) ? ( ( ( a == 0 ) || ( b == 0 ) ) ? s : NULL ) :
( ( NULL == aptr ) && ( NULL == bptr ) ) ? NULL :
aptr == NULL ? bptr :
bptr == NULL ? aptr :
bptr < aptr ? bptr : aptr;
}
Код: Выделить всё
struct test {
const char *str;
char a, b;
friend inline ostream& operator << ( ostream& stream, test& obj ) {
stream << '<' << ( obj.str ? obj.str : "NULL" ) << "|'";
if( isprint( obj.a ) ) stream << obj.a;
else stream << '\\' << int( obj.a );
stream << "'|'";
if( isprint( obj.b ) ) stream << obj.b;
else stream << '\\' << int( obj.b );
stream << "'>";
return stream;
}
};
void strshow( char* s, const char* s1 ) {
if( NULL == s ) cout << "NULL";
else if( '\0' == *s ) cout << "\"\"";
else cout << (char)*s << "[" << s - s1 << "]";
}
int main( int argc, char **argv ) {
test at[] = {
{ "123456789", '7', '3' },
{ "123456789", '7', '8' },
{ "123455432", '7', '3' },
{ "123456789", '5', 'A' },
{ "123456789", 'B', '6' },
{ "123456789", 'x', 'y' },
{ "", 2, 3 },
{ "", 5, 0 },
};
for( uint i = 0; i < sizeof( at ) / sizeof( at[ 0 ] ); i++ ) {
char *pf1 = func1( (char*)at[ i ].str,
at[ i ].a, at[ i ].b ),
*pf2 = func2( (char*)at[ i ].str,
at[ i ].a, at[ i ].b );
cout << i + 1 << " : " << at[ i ] << " => ";
strshow( pf1, at[ i ].str );
cout << " ... ";
strshow( pf2, at[ i ].str );
cout << endl;
}
return 0;
}
Выполнение:
Код: Выделить всё
olej@nvidia ~/2015_WORK/in.WORK/SchoolCPP/strsimpl $ ./strsimpl
1 : <123456789|'7'|'3'> => 3[2] ... 3[2]
2 : <123456789|'7'|'8'> => 7[6] ... 7[6]
3 : <123456789432|'7'|'3'> => 3[2] ... 3[2]
4 : <123456789|'5'|'A'> => 5[4] ... 5[4]
5 : <123456789|'B'|'6'> => 6[5] ... 6[5]
6 : <123456789|'x'|'y'> => NULL ... NULL
7 : <|'\2'|'\3'> => NULL ... NULL
8 : <|'\5'|'\0'> => "" ... ""
Умение работать (практика) с чужим кодом (да ещё написанном и форматированном в самых разных стилях) - это, порой, важнее, чем писать собственный код. Особенно это так в мире опенсорсных проектов, Linux, где в каждом крупном проекте приходится использовать десятки уже существующих публичных и опенсорсных.
- Вложения
-
- simplecod.tgz
- (1.43 КБ) 289 скачиваний
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
Задача с того сайта ... для пыанэров, с обсуждения которого началась тема:
Но только:
- придав им более обобщённую формулировку - почему 4-х разрядное число? ... положительное целое любой разрядности!
- и поставив целью своей разминки составить как можно более короткий код.
1-й вариант :
Это уже действительно будет "для начинающих", как в заголовке темы.
Задача плёвая ... но как пианист для разминки играет гаммы, так и с такими задачами есть смысл поиграться.1. Распространённая задача: Дано четырехзначное число (к примеру 5678), вывести на экран в обратном порядке цифры из которых это число состоит. То есть мы должны увидеть на экране 8765.
Но только:
- придав им более обобщённую формулировку - почему 4-х разрядное число? ... положительное целое любой разрядности!
- и поставив целью своей разминки составить как можно более короткий код.
1-й вариант :
Код: Выделить всё
#include <iostream>
using namespace std;
int main() {
unsigned long long e;
while( true ) {
cout << "Введите любое положительное целое : ";
cin >> e;
cout << "Введенные цифры в обратном порядке : ";
for( ; e != 0; e /= 10 )
cout << e % 10;
cout << endl;
}
return 0;
}
Код: Выделить всё
olej@nvidia ~/2015_WORK/in.WORK/SchoolCPP/digrev $ ./digrev
Введите любое положительное целое : 1235
Введенные цифры в обратном порядке : 5321
Введите любое положительное целое : 123456789
Введенные цифры в обратном порядке : 987654321
Введите любое положительное целое : 1
Введенные цифры в обратном порядке : 1
Введите любое положительное целое : 12
Введенные цифры в обратном порядке : 21
Введите любое положительное целое : 123
Введенные цифры в обратном порядке : 321
Введите любое положительное целое : ^C
- Вложения
-
- digrev.cc
- (381 байт) 265 скачиваний
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: C++ для начинающих
В той задаче можно пойти на обманOlej писал(а): - и поставив целью своей разминки составить как можно более короткий код.
Обман состоит в том, что чтение из потока cin (или cin.get()) читает с терминала всё-равно текстовую строку, которую потом, из-за требования совместимости с типом результата, преобразовывает в целое (хотя приглашения ввода и убедительно предлагает ввести именно целое ):
Код: Выделить всё
#include <iostream>
using namespace std;
int main() {
string e;
while( true ) {
cout << "Введите любое положительное целое : ";
cin >> e;
cout << "Введенные цифры в обратном порядке : ";
for( string::const_reverse_iterator i = e.rbegin(); i != e.rend(); i++ )
cout << *i;
cout << endl;
}
}
Код: Выделить всё
olej@nvidia ~/2015_WORK/in.WORK/SchoolCPP/digrev $ ./digrevs
Введите любое положительное целое : 1234567
Введенные цифры в обратном порядке : 7654321
Введите любое положительное целое : 678
Введенные цифры в обратном порядке : 876
Введите любое положительное целое : ^C
- Вложения
-
- digrevs.cc
- (400 байт) 315 скачиваний
-
- digrev.tgz
- (740 байт) 264 скачивания
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 3 гостя