Пример программы на cpp

Один из авторов Qt Блога поделился своим опытом использования утилиты Cling. Для решения повседневных задач ему потребовалось написать несколько скриптов, а в качестве скриптового языка он использовал C++. Для этого он воспользовался утилитой Cling, которая является интерпретатором C++ на базе компилятора Clang, и создана CERN.

Cling позволяет разработчикам писать сценарии с использованием C и C ++. Поскольку он использует компилятор Clang, он поддерживает последние версии стандарта C ++. Если вы выполняете интерпретатор напрямую, у вас будет живая среда исполнения, в которой вы можете начать писать код на C ++. В качестве части стандартного синтаксиса C/C ++ вы найдете несколько других команд, начинающихся с «.» (Точка). Когда вы используете интерактивный интерпретатор, вы можете написать код, например:

#include printf(«hello worldn»);

Как вы можете видеть, нет необходимости беспокоиться о областях; вы можете просто вызвать функцию. Если вы планируете использовать Cling в качестве интерпретатора для создания ваших скриптов, вам необходимо обернуть все внутри функции. Точка входа скрипта по умолчанию такая же, как имя файла. Он может быть настроен для вызова другой функции. Таким образом, предыдущий пример превратился бы в нечто вроде:

Создание игры на C++ / Змейка — Урок #1 (Создание карты)

#include void _01_hello_world()
#include void _02_hello_world()

Примеры довольно просты, но они показывают, с чего начать.

Что по поводу Qt?

#include #include void _03_basic_qt()

Но данный код не будет работать из коробки — вам нужно передать некоторые пользовательские параметры для Cling:

cling -I/usr/include/x86_64-linux-gnu/qt5 -fPIC -lQt5Widgets 03_basic_qt.cpp

Вы можете настроить свой «cling» в пользовательском скрипте на основе ваших потребностей. Вы также можете загрузить Cling в качестве библиотеки в своих приложениях, чтобы использовать C++ в качестве скриптового языка.

Рекомендуем хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB

Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

По статье задано0 вопрос(ов)
Подписка на обсуждение 2
Подписка на раздел 336

Вам это нравится? Поделитесь в социальных сетях!

Источник: evileg.com

Пример программы игры в крестики-нолики

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

Матрица для игры в крестики-нолики имеет вид двумерного массива символов 3 на 3. Пользователь всегда играет крестиками, а компьютер — ноликами. Когда ходит пользователь, «X» помещается в указанную позицию матрицы. Когда наступает очередь ходить компьютеру, он сканирует матрицу и помещает «О» в пустое место матрицы. (Это достаточно тупая игра и можно получить определенное удовольствие, немного ее улучшив.) Если компьютер не может найти пустой ячейки, он выводит результат игры и завершает работу программы. Игровая матрица инициализируется так, что в начале игры она содержала пробелы. Ниже показана программа крестики-нолики:

Что пишут на языке программирования C++?

/* простая программа игры в крестики-нолики */
#define SPACE ‘ ‘
char matrix[3][3] = < /* матрица для крестиков-ноликов */
,
,

> ;
void get_computer_move(void), get_player_move(void);
void disp_matrix(void);
char check (void);
int main()
char done;
printf(«This is the game of Tic-Tac-Toe.n»);
printf(«You will be playing against the computer.n»);
done = SPACE;
do disp_matrix(); /* вывод игровой доски */
get_player_move(); /* ходит игрок */
done = check(); /* проверка на победу */
if (done!=SPACE) break; /* победитель */
get_computer_move(); /* ходит компьютер */
done=check(); /* проверка на победу */
> while(done==SPACE);
if(done==’X’) printf(«You won!n»);
else printf(«I won. n»);
disp_matrix(); /* отображение результирующего положения */
return 0;
>

Читайте также:
Топ программ для хранения паролей

/* ввод хода игрока */
void get_player_move(void)
int x, у;
printf(«Enter coordinates for your X.n»);
printf(«Row? «);
scanf («%d»,
printf(«Column? «);
scanf(«%d»,
х—; y—;
if (x2 || y>2 || matrix[x] [y] !=SPACE)
printf(«Invalid move, try again.n»);
get_player_move();
>
else matrix[x][y]=’X’;
>

/* ход компьютера */
void get_computer_move(void)
register int t;
char *p;
p = (char *) matrix;
for (t=0; *p!=SPACE t if(t==9)
printf(«drawn»);
exit(0); /* game over */
>
else *p = ‘O’;
>

/* отображение игровой доски */
void disp_matrix(void)
int t;
for(t=0; t printf(» %c | %c | %c», matrix[t][0], matrix[t][1], matrix[t][2]);
if(t!=2) printf(«n-|-|-n»);
>
printf(«n»);
>

Массив инициализируется пробелами, поскольку пробелы используются для отображения вакантного состояния функциями get_player_move() и get_computer_move(). Тот факт, что пробелы используются вместо нулевых символов, упрощает функцию отображения матрицы — disp_matrix(), позволяя выводить содержимое массива на экран без преобразований. Обратим внимание, что процедура get_player_move() вызывает рекурсию в случае ввода неправильного значения. Это пример использования рекурсий для упрощения подпрограммы и уменьшения количества кода, необходимого для реализации функции.

В главном цикле каждый раз при вводе хода вызывается функция check(). Данная функция определяет, выиграна ли игра и, если да, то кем. Функция check() возвращает «X» в случае выигрыша пользователя, или «О», если выиграл компьютер. В противном случае она возвращает пробел. check() сканирует строки, столбцы и диагонали с целью поиска выигрышной конфигурации.

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

Источник: www.c-cpp.ru

Записки программиста

В более ранних постах было рассказано про многопоточность в Windows при помощи CreateThread и прочего WinAPI, а также многопоточность в Linux и других *nix системах при помощи pthreads. Если вы пишите на C++11 или более поздних версиях, то вам доступны std::thread и другие многопоточные примитивы, появившиеся в этом стандарте языка. Далее будет показано, как с ними работать. В отличие от WinAPI и pthreads, код, написанный на std::thread, является кроссплатформенным.

Примечание: Приведенный код был проверен на GCC 7.1 и Clang 4.0 под Arch Linux, GCC 5.4 и Clang 3.8 под Ubuntu 16.04 LTS, GCC 5.4 и Clang 3.8 под FreeBSD 11, а также Visual Studio Community 2017 под Windows 10. CMake до версии 3.8 не умеет говорить компилятору использовать стандарт C++17, указанный в свойствах проекта. Как установить CMake 3.8 в Ubuntu 16.04 описано здесь.

Чтобы код компилировался при помощи Clang, в *nix системах должен быть установлен пакет libc++. Для Arch Linux пакет доступен на AUR. В Ubuntu есть пакет libc++-dev, но вы можете столкнуться с непофикшенным багом, из-за которого код так просто собираться не будет. Воркэраунд описан на StackOverflow. Во FreeBSD для компиляции проекта нужно установить пакет cmake-modules.

Читайте также:
Javascript как запустить программу

Мьютексы

Ниже приведен простейший пример использования трэдов и мьютексов:

#include
#include
#include
#include

std :: mutex mtx ;
static int counter = 0 ;
static const int MAX_COUNTER_VAL = 100 ;

void thread_proc ( int tnum ) {
for ( ;; ) {
{
std :: lock_guard < std :: mutex >lock ( mtx ) ;
if ( counter == MAX_COUNTER_VAL )
break ;
int ctr_val = ++ counter ;
std :: cout ctr_val }
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 10 ) ) ;
}
}

int main ( ) {
std :: vector < std :: thread >threads ;
for ( int i = 0 ; i < 10 ; i ++ ) {
std :: thread thr ( thread_proc, i ) ;
threads. emplace_back ( std :: move ( thr ) ) ;
}

Обратите внимание на оборачивание std::mutex в std::lock_guard в соответствии c идиомой RAII. Такой подход гарантирует, что мьютекс будет отпущен при выходе из скоупа в любом случае, в том числе при возникновении исключений. Для захвата сразу нескольких мьютексов с целью предотвращения дэдлоков существует класс std::scoped_lock. Однако он появился только в C++17 и потому может работать не везде. Для более ранних версий C++ есть аналогичный по функционалу шаблон std::lock, правда для корректного освобождения локов по RAII он требует написания дополнительного кода.

RWLock

Нередко возникает ситуация, в которой доступ к объекту чаще происходит на чтение, чем на запись. В этом случае вместо обычного мьютекса эффективнее использовать read-write lock, он же RWLock. RWLock может быть захвачен сразу несколькими потоками на чтение, или только одним потоком на запись. RWLock’у в C++ соответствуют классы std::shared_mutex и std::shared_timed_mutex:

#include
#include
#include
#include

// std::shared_mutex mtx; // will not work with GCC 5.4
std :: shared_timed_mutex mtx ;

static int counter = 0 ;
static const int MAX_COUNTER_VAL = 100 ;

void thread_proc ( int tnum ) {
for ( ;; ) {
{
// see also std::shared_lock
std :: unique_lock < std :: shared_timed_mutex >lock ( mtx ) ;
if ( counter == MAX_COUNTER_VAL )
break ;
int ctr_val = ++ counter ;
std :: cout ctr_val }
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 10 ) ) ;
}
}

int main ( ) {
std :: vector < std :: thread >threads ;
for ( int i = 0 ; i < 10 ; i ++ ) {
std :: thread thr ( thread_proc, i ) ;
threads. emplace_back ( std :: move ( thr ) ) ;
}

По аналогии с std::lock_guard для захвата RWLock’а используются классы std::unique_lock и std::shared_lock, в зависимости от того, как мы хотим захватить лок. Класс std::shared_timed_mutex появился в C++14 и работает на всех* современных платформах (не скажу за мобильные устройства, игровые консоли, и так далее).

В отличие от std::shared_mutex, он имеет методы try_lock_for, try_lock_unti и другие, которые пытаются захватить мьютекс в течение заданного времени. Я сильно подозреваю, что std::shared_mutex должен быть дешевле std::shared_timed_mutex. Однако std::shared_mutex появился только в C++17, а значит поддерживается не везде. В частности, все еще широко используемый GCC 5.4 про него не знает.

Thread Local Storage

Иногда бывает нужно создать переменную, вроде глобальной, но которую видит только один поток. Другие потоки тоже видят переменную, но у них она имеет свое локальное значение. Для этого придумали Thread Local Storage, или TLS (не имеет ничего общего с Transport Layer Security!). Помимо прочего, TLS может быть использован для существенного ускорения генерации псевдослучайных чисел. Пример использования TLS на C++:

Читайте также:
Комплекс программ обеспечивающих согласованную работу всех узлов компьютера это

#include
#include
#include
#include

std :: mutex io_mtx ;
thread_local int counter = 0 ;
static const int MAX_COUNTER_VAL = 10 ;

void thread_proc ( int tnum ) {
for ( ;; ) {
counter ++ ;
if ( counter == MAX_COUNTER_VAL )
break ;
{
std :: lock_guard < std :: mutex >lock ( io_mtx ) ;
std :: cout counter }
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 10 ) ) ;
}
}

int main ( ) {
std :: vector < std :: thread >threads ;
for ( int i = 0 ; i < 10 ; i ++ ) {
std :: thread thr ( thread_proc, i ) ;
threads. emplace_back ( std :: move ( thr ) ) ;
}

Мьютекс здесь используется исключительно для синхронизации вывода в консоль. Для доступа к thread_local переменным никакая синхронизация не требуется.

Атомарные переменные

Атомарные переменные часто используются для выполнения простых операций без использования мьютексов. Например, вам нужно инкрементировать счетчик из нескольких потоков. Вместо того, чтобы оборачивать int в std::mutex, эффективнее воспользоваться std::atomic_int. Также C++ предлагает типы std::atomic_char, std::atomic_bool и многие другие.

Еще на атомарных переменных реализуют lock-free алгоритмы и структуры данных. Стоит отметить, что они весьма сложны в разработке и отладке, и не на всех системах работают быстрее аналогичных алгоритмов и структур данных с локами.

#include
#include
#include
#include
#include

static std :: atomic_int atomic_counter ( 0 ) ;
static const int MAX_COUNTER_VAL = 100 ;

std :: mutex io_mtx ;

void thread_proc ( int tnum ) {
for ( ;; ) {
{
int ctr_val = ++ atomic_counter ;
if ( ctr_val >= MAX_COUNTER_VAL )
break ;

{
std :: lock_guard < std :: mutex >lock ( io_mtx ) ;
std :: cout ctr_val }
}
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 10 ) ) ;
}
}

int main ( ) {
std :: vector < std :: thread >threads ;

int nthreads = std :: thread :: hardware_concurrency ( ) ;
if ( nthreads == 0 ) nthreads = 2 ;

for ( int i = 0 ; i < nthreads ; i ++ ) {
std :: thread thr ( thread_proc, i ) ;
threads. emplace_back ( std :: move ( thr ) ) ;
}

Обратите внимание на использование процедуры hardware_concurrency. Она возвращает оценку количества трэдов, которое в текущей системе может выполняться параллельно. Например, на машине с четырехядерным процессором, поддерживающим hyper threading, процедура возвращает число 8. Также процедура может возвращать ноль, если сделать оценку не удалось или процедура попросту не реализована.

Кое-какую информацию о работе атомарных переменных на уровне ассемблера можно найти в заметке Шпаргалка по основным инструкциям ассемблера x86/x64.

Насколько я вижу, все это действительно неплохо работает. То есть, при написании кроссплатформенных приложений на C++ про WinAPI и pthreads можно благополучно забыть. В чистом C начиная с C11 также существуют кроссплатформенные трэды. Но они все еще не поддерживаются Visual Studio (я проверил) , и вряд ли когда-либо будут поддерживаться. Не секрет, что Microsoft не видит интереса в развитии поддержки языка C в своем компиляторе, предпочитая концентрироваться на C++.

За кадром осталось еще немало примитивов: std::condition_variable(_any), std::(shared_)future, std::promise, std::sync и другие. Для ознакомления с ними я рекомендую сайт cppreference.com.

Полная версия исходников к этой заметке, как обычно, лежит на GitHub. А как вы сейчас пишите многопоточные приложения на C++?

Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.

Источник: eax.me

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru