Архив рубрики: Основы программирования на C++

В этой рубрике объединены статьи нашего сайта, которые освещают основы программирования на C++ для начинающих

Работа с локализованными строками




Первое, что нужно уметь делать с локализованными строками — это записывать символьные константы широких локализованных символов и отличать их от обычных строк char[]. Для этого строка записывается с предшествующим ей квалификатором L:

Результатом будет:

Обратим внимание, что длина строки (число символов) в этом случае отчётливо меньше, чем число байт выделенных под строку (в вашей операционной системе их отношение может отличаться от того, что я показываю в Linux, но это никак не влияет на технику программирования).

В такой строке рядом с равным успехом могут стоять символы самой разнообразной природы: различных языков, специальные математические символы, общепринятые в технике обозначения из греческого алфавита (α, ε, θ, π, σ, λ, φ, Ω…), музыкальные ноты и др. Как вы, очевидно, понимаете, точно также в составе строк широких символов, с равным успехом, могут встречаться и символы латинского алфавита (основная таблица ASCII), при этом каждый такой символ тоже будет занимать 2 или 4 байт (в зависимости от соглашений принятых в операционной системе), в отличие от привычного 1 байта.

Проделаем ряд операций с русскоязычными строками, но записывая их (пока) в традиционной форме массивов char:

Выполняем:

Казалось бы, что (почти) всё работает в точности как по учебнику и зачем нам какие-то широкие локализованные строки? Но это обманчивая иллюзия! Дело здесь в том, что некоторые традиционные строчные функции (strcat(), strcpy(), strdup(), strstr() и др.) будут возвращать корректный результат. Это потому что они выполняют операции над байтами, байт за байтом, не вникая во внутреннюю структуру копируемых символов.

Но другие операции (и ошибочный результат strlen() на это уже наглядно указывает) будут работать некорректно: strncpy(), strchr(), strsep(), strtok() и др. И они будут создавать вам очень неожиданные результаты, весьма сложные для толкования. Посмотрите как сработает побайтовый реверс строки, и как различается его работа на англоязычной и русскоязычной строке:

Сработает это так, и это определённо не то, что вы рассчитывали получить:

На этом мы закончим рассмотрение возможности представления русскоязычных строк традиционными массивами char[] и обработка их традиционными строчными функциями, и завершим это рассмотрение выводом: работать с русскоязычными строками как массивом char можно только:

а). либо когда мы используем строчные константы в неизменном виде, только как строки для их ввода-вывода в неизменном виде;

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

Во всех остальных случаях корректная работа с кириллицей возможна только как с массивами широких локализованных символов wchar_t (с завершающим строку широким нулевым символом L’\0′). Для работы с таким представлением локализованных строк библиотека C предоставляет широкий набор строчных функций, полностью аналогичный традиционным строчным функциям, но вместо префикса str в их именах используется префикс wcs: wcslen() вместо strlen(), wcsncpy() вместо strncpy() и т.д.

Посмотрим как это работает на примере:

Такой иллюстрации вполне достаточно для того, чтобы увидеть прямые аналогии использования функций работы с символами wchar_t. Тот, кто имеет некоторый опыт работы со строками char без усилий перенесёт его широкие строки. Установка языковой локали (вызов setlocale()) устройства вывода (терминала) обязательна, потому что по умолчанию программа C/C++ устанавливает локаль “C” (так сложилось исторически), которая допускает вывод только 128 символов младшей половины 8-битной таблицы ASCII.

В показанном написании функция устанавливает локаль, используемую в операционной системе по умолчанию — я предполагаю, что мы экспериментируем в русскоязычной установленной системе. Новый стандарт языка (C99) вводит и новый формат для функций форматирования строк (printf(), sprintf()) %ls, это форматирование строк wchar_t[].

Точно так же, как и с массивами char, перешедшими в C++ из C, библиотека C++ вводит полный аналог контейнерного класса string, но содержащий в своём составе широкие локализованные символы, и носит название этот класс wstring:

Здесь вывод строки локализованных символов (ws) должен выводится в поток вывода wcout (аналогичный по смыслу cout, но отличный от cout).

В показанном написании: locale::global( locale( “” ) )это установка локали по умолчанию в ООП манере C++, аналогично тому, как это было показано раньше в манере C.

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

Рассылка новых уроков по программированию:

О локализации символьных строк




локализация символьных строк в с++

Подавляющее число примеров кодов со строками C/C++ (в любых публикуемых источниках) оперирует с нуль-терминальными массивами (ASCIZ) элементов char (в стиле C), или с контейнерным типом string (в стиле C++), построенным как надстройка над такими массивами. Всё это замечательно работает со строками латинских (англоязычных) символов, но может идти вразнос на строках, содержащих символы иноязычных алфавитов (русский, китайский, арабский или иврит). Здесь всё не так просто… и весьма плохо описано в литературе, что и понятно: англоязычных авторов мало занимают вопросы иноязычной локализации, а отечественные авторы, в большинстве, переписывающие и адаптирующие англоязычные публикации, не уделяют внимания этой стороне вопроса.

Язык C — весьма старый язык программирования, а C++ наследует из него форматы и сдерживается требованиями синтаксической совместимости с C. Для того, чтобы не иметь в C/C++ проблем с такими строками (называемыми локализованными) нужно понимать что там с этими локализациями происходит…

Исторически, символы (char) представлялись (1963 год) стандартом ASCII как младшие 7 бит одного байта, при этом старший 8-й бит предназначался для контроля ошибок, возникших при передаче данных. Такая кодировка позволяет кодировать максимально всего 128 различных символов, и этого числа с трудом хватает на символы английского алфавита (большие и малые), цифровые (коды 0x30-0x39), управляющие (код меньше 0x20) и специальные символы. Когда возникала необходимость представления национальных алфавитов, вводилась альтернативная таблица символов, например KOI-7 для русского языка. Переключение в потоке ввода-вывода на альтернативную таблицу символов производилось символом с кодом 0x18 (код называется: Device Control 2) в потоке, а возврат к основную таблицу ASCII — символом с кодом 0x17 (Device Control 1).

Позже, с середины 80-х годов, с времени широкого распространения IBM PC и замены ними компьютеров других семейств, стандарт ASCII был расширен на 8-й бит байта char, байт мог представлять 256 символов: младшие 127 представляли исходную таблицу ASCII (с латинским шрифтом), а старшие — национальный алфавит. Но, поскольку национальные алфавиты могут быть самыми разнообразными, то для поддержки каждого из них потребовалось ввести свою кодовую страницу, например, для русского языка это могут быть страницы CP-866 (в MS-DOS), CP-1251 (в Windows), KOI-8r (в UNIX, Linux) — и каждая из этих страниц предлагает свой, отличающийся от других, порядок символов русского языка. При этом, для корректного отображения (или декодирования) любой локализованной символьной строки нужно обязательно знать кодовую страницу в которой она представлена.

Для того, чтобы положить конец этому вавилонскому столпотворению языковых кодовых страниц, был предложен (1991г.) стандарт представления UNICODE, в системе кодирования которого каждый символ кодируется 32-бит значением (4 байта, но не все 32-бит значения допустимы). Применение данного стандарта позволяет закодировать огромное количество символов разных систем письменности. Документы, закодированные по стандарту UNICODE, могут содержать в едином тексте японские и китайские иероглифы, буквы латиницы, кириллицы, греческого алфавита (α, ε, θ, π, σ, λ, φ, Ω…), математические символы, символы музыкальной нотной нотации, символы вымерших, редких, экзотических народностей. При этом нет необходимости в переключении кодовых страниц. Например, вот как выглядят некоторые символы языка, обозначенного как “сингальский”:

Первый UNICODE стандарт был выпущен в 91-м году. Последний на данный момент — в 2017 и он описывает 136755 разнообразных символов.

Но UNICODE — это ещё только стандарт представления каждого символа. Для представления этого символа в конкретной операционной системе (или языке программирования) нужна ещё система кодирования символов UNICODE.

  • Достаточно широко используются системы кодирования:
    UTF-32 — для представления каждого символа используются 4 байта, непосредственное численное значение кода UNICODE
  • UTF-32 — для представления наиболее часто используемых символов используются 2 байта (первые 65536 позиций), а остальные представляются в виде в виде «суррогатных пар». Такое кодирование используется в операционных системах Windows начиная с Windows NT.
  • UTF-32 — для представления каждого символа используются последовательность байт переменной длины: от 1 байта для символов основной таблицы ASCII, до 6 байт для редко используемых символов (символы русского алфавита кодируются 2-мя байтами). Эта кодировка создавалась позже других для операционных систем Plan 9 и Inferno в 1992г. Кеном Томпсоном и Робертом Пайком с коллегами, и вошла как единая и основная кодировка символьных строк в более поздних языках программирования Python и Go. Такое кодирование используется, на сегодня повсеместно, в POSIX/UNIX операционных системах, Linux.

Возвращаясь к тому, что C/C++ старое семейство языков программирования, для представления в них локализованных символов потребовалось ввести новый тип данных — широкие символы wchar_t вместо char (тип данных появился в стандарте C89, но, в полной мере с API поддержки, только в стандарте C99). Вместо строчных функций библиотеки C вида str*() для широких предлагаются их полные аналоги, но в виде wcs*() (вместо префикса str записываем префикс wcs). В разных системах wchar_t может иметь разную разрядность (в Linux это int32_t, в Windows int16_t) но для программиста это не имеет значения и не создаёт различий.

Для работы и преобразования многобайтовых последовательностей записанных в кодировке UTF-8 в C/C++ вводится семейство функций вида mb*(): mbtowc(), mblen(), mbstowcs(), wcstombs() и др. Это механизм взаимных преобразований между массивами char[] (в которых также выражаются строки UTF-8) и wchar_t[]. Если вы не сталкиваетесь с кодировкой UTF-8 (что с большой вероятностью имеет место в Windows), то эта группа функций вас не должна занимать.

Аналогично, вместо контейнерного класса C++ string вводится аналогичный контейнерный класс широких символов wstring.

Конкретно о технике работы с широкими локализованными строками мы поговорим в следующей статье. А пока 1-й элементарный пример … без комментариев — как повод для размышления (обратите внимание и объясните, что вызов strlen() в каждом случае даёт число байт в строке явно не соответствующее визуально видимое число букв в ней):

P.S. С большой детальностью про локализацию в C/C++ и работе с локализованными строками, кто интересуется с большей подробностью, могут почитать здесь: Языковая локализация C/C++ Языковая локализация C/C++ — там объяснений более 22 страниц формата офисного документа.

Рассылка новых уроков по программированию:

sqrt() — функция библиотеки cmath




sqrt( value );

Функция sqrt() библиотеки cmath (math.h) принимает параметр value и возвращает его квадратный корень.

Если параметр ( в нашем случае – value) отрицательный, возникает ошибка.

Результат выполнения показан в онлайн компиляторе ideone

пример работы функции sqrt c++

Рассылка новых уроков по программированию:

Online компиляторы




Часто возникает необходимость быстро показать кому-либо, как решить небольшую задачу по программированию или как реализовать алгоритм. Можно просто скинуть в ответ кусок кода, но лучше воспользоваться одним из online-компиляторов. Во многих из них есть возможность получить специальную ссылку на скомпилированный код. Такую ссылку можно например оставлять в комментариях к статьям. Пройдя по ней люди увидят не только сам код, но и результат работы программы.

Рассмотрим несколько вариантов online-компиляторов поддерживающих язык программирования C++

1. Online компилятор для С++ на сайте primat.org . Добавляем код, жмем RUN и ждем выполнения.

online-компилятор на primat.org

Если программа по ходу работы требует действий пользователя – выполняем их:

online-компилятор - действия пользователя

Если возникнут ошибки они отобразятся во вкладке compilation, которая откроется автоматически. Во вкладе options можно выбирать разнообразные параметры для компиляции, если вас не устраивают заданные по умолчанию.

Чтобы получить ссылку на этот код – жмем

online-компилятор - действия пользователя

Так же на этом сайте есть компилятор для Паскаль.

2. ideone online-компилятор

ideone online-компилятор

Сразу при входе обратите внимание на тот язык программирования, который выбран по умолчанию. Смените его при необходимости. Входящие данные внесите в stdin:

ideone online-компилятор

ideone online-компилятор

Тут очень большой выбор языков для компиляции:

языки программирования на ideone

3. Online-компилятор Wandbox

Wandbox online-компилятор

Входящие данные надо прописывать в Stdin до того, как нажмете Run.

Wandbox online-компилятор

Мне понравилось, что он хранит историю компиляций. Кроме С++ здесь есть широкий выбор языков программирования для компиляции:

языки программирования на Wandbox

4. C/C++ Online Compiler

online-компилятор Compiler

online-компилятор Compiler

В последнем как-то заморочено со ссылкой у них. Плюс не понятно где смотреть результат выполнения программы. Просто показывает, что программа вернула значение 0.

Смотрите также как установить Microsoft Visual Studio 2015 Express

Рассылка новых уроков по программированию:

pow() — функция библиотеки cmath




pow(a, b);

Функция pow() библиотеки cmath принимает два параметра: a, b. Первое число a (базовое) возводится в степень b.

Возвращает значение ab .

Результат выполнения 23 , 53, 52 :

pow () - функция библиотеки cmath

 

Рассылка новых уроков по программированию:

fma () – функция библиотеки cmath




fma(a, b, c);

Функция fma() библиотеки cmath принимает три параметра: a, b – значения для умножения, c – значение для добавления.

Возвращает значение a * b + c.

Результат выполнения ( 2 * 2 + 3):

fma () - функция библиотеки cmath

Рассылка новых уроков по программированию:

Установка Microsoft Visual Studio 2015 Express (IDE).




Среда разработки Microsoft Visual Studio – это такая специальная программа в которой мы будем писать команды компьютеру, а она эти команды будет переводить (при помощи так называемого компилятора) в машинный язык (из единиц и нулей), обрабатывать и выдавать нам некий результат работы нашего программного кода. Чтобы приступить к установке Microsoft Visual Studio Express вам надо пройти по этой ссылке. Прокрутите страницу и найдите там блок с Express for Desktop – это то что нам нужно.установка Microsoft Visual Studio Express

Примечание: Сейчас Microsoft рекомендует устанавливать Visual Studio Community. Если хотите установите его с той же страницы.

Единственное, перед тем как нажать кнопку Загрузка, просмотрите пункты System Requirements (системные требования к вашему компьютеру). Если они не отвечают вашим, к примеру у вас более старая версия Windows, то найдите в Google Microsoft Visual Studio 2010 Express или Microsoft Visual Studio 2013 Express и выберите ту версию, которая сможет нормально работать на вашем компьютере. Ну а если все требования выполняются – жмите Загрузка.

как установить Microsoft Visual Studio 2015 ExpressНемного ждем, пока закачается файл wdexpss_full_RUS.exe Вы можете найти его в Загрузках на вашем компьютере. Кликаем на него два раза и нажимаем кнопку Запустить:

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.2

Если так случилось, что вы не являетесь счастливым обладателем Internet Explorer 10, вы увидите такое предупреждение:

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.3

Смело нажимайте Продолжить. Далее вам предстоит выбрать на какой диск будет произведена установка (можете оставить то, что предлагают по умолчанию). Нажимайте Установить.

как установить Microsoft Visual Studio 2015 Expressм
Установка Microsoft Visual Studio 2015 Express – рис.4

Тут уже придется подождать кому сколько отмерено. Для тех у кого SSD – минут 15, а для жесткого диска берем минут 30 – 40. Так что у вас появилось немного свободного времени. Можете отдохнуть.

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.5

После того, как всё будет принято и применено мы увидим сообщение:

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.6

Значит всё установилось без проблем и можно сразу запускать программу. Вам предложат войти в Учетную запись Майкрософт. Если у вас ее нет – нажмите Регистрация. Лучше зарегистрироваться сразу, так как если этого не сделать, то через 30 дней MVS 2015 Express перестанет работать, пока вы не создадите эту учетную запись.

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.7

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

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.8

В этом окне нажмите на Visual C++, Win32, Консольное приложение Win32, введите любое имя для вашего нового проекта и снимите галочку с Создать каталог для решения. Жмем ОК.

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.9

Откроется Мастер приложений. В нем нажмите Далее

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.10

отметьте Консольное приложение и Пустой проект. Далее можно нажимать Готово.

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.11

Проект создан. Теперь в нем нам надо создать файл с расширением .cpp. В него мы будем писать код программы. Делается это так: в окошке Обозреватель решений нажмите правой кнопкой мыши на имя вашего проекта (у меня это ConsoleApplication2)

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.12

Выберите Добавить и Класс:

создание проекта и файлов cpp в microsoft visual studio

Откройте вкладку Visual C++ и выберите C++, а затем в списке шаблонов в центральной области выберите Класс C++. Нажмите Добавить.

создание проекта и файлов cpp в microsoft visual studio

В поле мастере универсальных классов C++ введите в поле Имя класса mycode. Не изменяйте имена файлов и параметры по умолчанию. Нажмите кнопку Готово.

создание проекта и файлов cpp в microsoft visual studio

Все – теперь в вашем проекте создан файл, в который можно писать команды на языке С++.

создание проекта и файлов cpp в microsoft visual studio

Еще, для удобства работы, я вам сразу предлагаю включить нумерацию строк кода. Для этого нажмите Сервис – Параметры – Текстовый редактор – С/С++ и установите галочку Номера строк. ОК.

Установка Microsoft Visual Studio 2013 Express
Установка Microsoft Visual Studio 2015 Express – рис.15

Далее, не вдаваясь в подробности, просто скопируйте код ниже и вставьте в ваш файл с именем mycode.cpp. (все что в нем содержалось до этого можно удалить)

После вставки нажмите сочетание клавиш Ctrl + Shift + B – начнется компиляция программы. Вы должны увидеть в нижней строке окна Сборка: успешно: 1, с ошибками: 0 и т.д. После этого нажимаем Ctrl + F5 и видим в открывшемся окне сообщение: “Мы создали первый проект в MVS2015”.

как установить Microsoft Visual Studio 2015 Express
Установка Microsoft Visual Studio 2015 Express – рис.16

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

Существует также много online компиляторов которыми вы можете пользоваться для несложных задач по программированию.

Указатели на функции





указатель на функцию, с++, программирование для начинающих, c++

Уже было отмечено, что указатели могут указывать на самые разнообразные типы объектов в программе на языке C++. Точнее, на все и на любые виды объектов, являющиеся данными в программе.

Но такими же объектами, как и традиционные объекты данных, являются функции в программе. Поэтому напрашивается желание попытаться определить и использовать указатель на функцию. Создадим вот такую простейшую программу (ex1.cc):

Здесь с функцией area() всё ясно: она вычисляет площадь круга того радиуса, который предан ей, как параметр. Но позже мы объявляем переменную указатель на функцию:

В момент этого объявления указатель pfunc представляет собой ничего более, как некоторый адрес во внутреннем представлении компьютера (4 байта в 32-бит операционной системе, 8 байт в 64-бит операционной системе). Это в точности тот же внутренний вид, который имеет, скажем, указатель на целочисленную переменную int*. Но этот указатель имеет свой строго определённый тип: указатель на функцию, принимающую один параметр типа double, и возвращающую значение типа double. Но вот на какую конкретно функцию указывает указатель, в точке его определения — не важно: значение указателя не определено.

А вот следующим оператором присвоения мы привязываем указатель на функцию к конкретной функции area(). Абсолютно правильным было бы записать присвоение указателю адреса функции: pfunc = &area. Но компилятор C++ настолько умён, что и упоминание имени функции в операторе присвоения интерпретирует как её адрес. Таким образом запись pfunc = area также совершенно корректная. С этого момента мы можем использовать указатель pfunc для вызова функции на которую он указывает. Для этого мы записываем значение на которое указывает указатель *pfunc (операция * в таком контексте называется разыменованием указателя). Скобки вокруг разыменованного значения pfunc в записи (*pfunc)( r ) нужны из соображений приоритетов раскрытия операций в выражении. Выполнение этого примера:

указатель на функцию, с++, программирование для начинающих, c++

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

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

В этой ситуации мы можем поступить так (ex2.cc):

И вот что мы имеем на исполнении:

указатель на функцию, с++, программирование для начинающих, c++

В этом листинге tests[ ] – это массив указателей на функции без параметров и без возвращаемых значений. Красивое решение, не правда ли? Мы можем не задумываясь добавлять новые функции массива вызываемых тестов, и они все последовательно будут вызываться при выполнении.

Мы можем пойти ещё дальше: если указатель на функцию представляет функцию в выражениях, можно передать указатель на функцию в качестве параметра другой, охватывающей функции, и последняя будет выполнять в своём теле переданную параметром функцию, не зная какое действие при этом выполняется.

Для иллюстрации всего сказанного создадим программу самого примитивного калькулятора, выполняющего арифметические действия над целочисленными операндами (ex3.cc):

Здесь собственно вычисление выполняет функция calculate(). Но она ничего не «знает» о выполняемых действиях и о арифметических операциях вообще: она применяет к 2-м первым своим параметрам одну из 6-ти функций, которую ей передали 3-м параметром для выполнения.

Кто не знает о typedef читайте тут.

В этом коде функция strtod() – стандартная функция библиотеки языка C (ANSI C, стандарта POSIX), которая извлекает десятичное число из строки, полученной со стандартного потока ввода. В контексте наших обсуждений это интересно тем, что:

  • программа на C++ может использовать всё множество библиотечных вызовов языка C;
  • программа C++ использует на этапе выполнения разделяемые библиотеки языка C (.so или .dll), и при отсутствии стандартной библиотеки C, программы на C++ становятся неработоспособными.

Но вернёмся к работе показанного калькулятора (его предельная упрощённость связана с тем, что мы не занимаемся проблемами ввода, его формата и не обрабатываем ошибки ввода пользователем – в реальных программах так делать нельзя):

указатель на функцию, с++, программирование для начинающих, c++

Наблюдательный читатель мог бы заметить, что функция calculate() при всём своём желании и не могла бы выполнить ни одно из требуемых арифметических действий, так как выполняющие эти действия функции sum(), dif(), mul() и div() описаны позже функции calculate() и не видимы в коде функции calculate().

Таким образом, мы рассмотрели несколько различных случаев, когда функции в C++ используются, как экземпляры данных. Они могут объединяться в массивы, встраиваться в качестве полей структур, или передаваться другим функциям в качестве параметров. Все эти и подробные возможности реализуются за счёт указателей на функции (хотя по синтаксису записей они могут и не выглядеть как указатели, за счёт умного компилятора C++, который по контексту понимает, что должны использоваться адреса функций).

Если вам что-то не понятно по материалу или по коду программ – задавайте вопросы в комментариях.

Предлагаем вам оценить этот урок и урок Указатели на объекты:

Рассылка новых уроков по программированию:

Преобразование типов




преобразование типов с++, для начинающих, для чайников, с нуля, основы программирования c++Преобразование типов в С++ достаточно древняя, или точнее классическая операция. Если вкратце и по-русски: Преобразование типа – это указание компьютеру считать некий набор байтов целым или вещественным. Или указателем на определенный класс.

Вообще, чтобы понять преобразование типов нужно учитывать механизм и структуру переменных. К примеру, переменных целого типа несколько: короткий INT, int, долго INT, не считая беззнаковые. И компьютер размещает для них разное количество ячеек памяти (байт): 1, 2 и 4 соответственно. Преобразование в рамках таких типов одного класса называется стандартным преобразованием. в:

Сделает следующее: возьмет два младших байта из переменной «а», и просто пересадит их в два байта переменной «b». Поскольку значение в а (единица) вполне себе помещается в эти два байта, программа даст правильный результат, а С++ не будет против такого преобразования.

Почему нужно учитывать размер переменной при преобразовании?

Что будет если поместить в переменную «а» число 123456789? Оно прекрасно уместится в 4 байта типа int, но в 2 байта типа короткий INT оно уже не попадает. Слишком большое. С , как и полагается, просто обрежет это длинное число, взяв из него только хвост, и поместит в переменную «b». Получим естественно ерунду. Причем с минусом, если вывести ее на экран. Преобразование из переменной, которая занимает большее количество байт в памяти не будет правильным. Если преобразовывать наоборот из short в long к примеру таких проблем не будет, поскольку байтов в переменной-получателе больше, и места для данных которые хранит short вполне хватает.

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

Что касается преобразования типов вещественного, этим занимается математический сопроцессор. Тут уже не просто байты перегоняются из ячеек в ячейку, а выполняются специальные команды, которые конвертируют целое в тип вещественного с мантиссой и экспонентой, как полагается, и возвращают значение. Это нельзя назвать преобразованием, это именно конвертация. В любом случае, этим будет заниматься сам процессор.

В данном примере математический сопроцессор преобразует вещественное в целое, и загонит в переменную, а потом сделает обратную операцию: загонит целое в свой специальный регистр (называется ST), и уже после из него достанет вещественное с целой частью, равной той, что в переменной “а”.

Если же нужно преобразовать из вещественного double (8 байт) в float (4 байта), то тут таких проблем, как с целыми не будет. Математический сопроцессор просто округлит вещественное до значения, умещающегося в 4 байта, что не приведет к неправильному значению:

Результатом все равно будет число 1.234568e+18, что означает 1.2-с хвостиком в 18-й степени. Другое дело, что в “a” уже будет округленное число до 6-го знака после запятой, а не 1.234567891234566e+18. В целом для неточных вычислений это не мешает, но рекомендуется в программе использовать вещественные одного типа, чтоб не происходило такого вот округления.

Помимо преобразования типа есть такое понятие как приведение типа.

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

Если преобразование – это решение С++ (а точнее компилятора), в какой тип приводить, то приведение использует тип, жестко указанный программистом. В данном примере программист говорит компилятору, что нужно преобразовывать именно в int, а не в short int. Ведь 25 помещается и в int и в short, что выберет компилятор программист может и не знать.

В быту такие преобразования типов вообще-то редкие. Да и не нужные. Идеология программирования в бытовых условиях намекает избегать таких выкрутасов, поскольку они могут оказаться граблями (как в примере выше при преобразовании целых), поэтому приведение типов в С++ не стоит использовать повсеместно.

:) Спасибо за эту статью её автору Stilet – супер модератору форума программистов ProgrammersForum.

Рассылка новых уроков по программированию:

Исключения в С++





исключения в с++, исключения c++, программирования для начинающих

Иногда, во время работы программ, встречаются ситуации которые препятствуют дальнейшей нормальной их работе. К примеру при делении числа на ноль, программа завершит работу не смотря на то, сколько пользователь работал в программе, и какой объем данных внес. Программа просто закроется. И представьте, если до этого пользователь вносил в программу данные несколько часов и проводил расчеты. При таком аварийном закрытии программы все эти данные и расчеты пропадут. Согласитесь – не очень приятно. Также может встретиться такая ситуация, когда программа пытается открыть недоступный в этот момент файл, или запросить больше, чем доступно памяти.

Такого рода ситуации программистам надо стараться предвидеть и строить программы так, чтобы они могли гибко реагировать, а не аварийно закрываться. В моей любимой книге Язык программирования C++. Лекции и упражнения автора С. Прата, дано следующее определение исключениям в С++:

исключения в с++, исключения c++, программирования для начинающих

Чтобы вам не сложно было понять механизм работы исключений в С++, рассмотрим их на простом примере. В нем мы предвидим тот случай, что в какой-то момент в ходе расчетов программы, может встретиться деление числа на 0. Наберите и скомпилируйте код, расположенный ниже. Чтобы убедиться в том, как реагирует программа на такую ситуацию, внесите число 0 в переменную num2 (она выступает делителем в примере).

Так как переменная var равна 3, цикл while, в нормальной ситуации, должен отработать три раза. С каждым шагом цикла var уменьшается на единицу с помощью декремента. Но так как мы сразу внесли значение 0 в переменную num2, программа не пройдет до конца даже первый шаг цикла. Она прервется.

В следующем листинге, мы исправим это упущение – добавим несколько компонентов, которые помогут среагировать на данную ситуацию без прерывания работы программы. А именно:

  • блок try или try-блок (попытка, проба);
  • генератор исключения – блок throw (обработать, запустить);
  • обработчик исключения, который его перехватывает -команда catch (поймать, ловить)

Как работает исключение? – Программист прописывает в коде (в try-блоке) конкретное условие, что если переменная num2 станет равна 0, то в таком случае необходимо генерировать исключение в throw. Далее, то что сгенерировал throw, перехватывает catch-блок (в виде параметра функции) и программа выполнит тот код, который прописан в этом блоке.

Пример:

Разберем подробно. В строках 21-29 находится блок try. В нем необходимо размещать тот код, который может привести к необратимым ошибкам. Еще до арифметического выражения деления задаем условие: если num2 будет равно 0, то пусть throw генерирует число 999 (к примеру). В том случае, сразу после генерации числа, дальнейшие команды в блоке try выполняться уже не будут, а само число “упадет” в блок catch (в виде параметра). Далее выполнится то, что указано в блоке catch – в нашем случае, это будет сообщение об ошибке:

cout << "Ошибка №" << thr << " - деление на 0!!!" << endl;

и программа будет выполнять последующие команды. В том случае, если число num2 != 0, то throw ничего не генерирует и catch-блок не сработает.

Посмотрите теперь, как отреагирует программа, если вы введете num2 равное нулю. Запускайте программу.

исключения в с++, исключения c++, программирования для начинающих

Как видим, там где могла произойти ошибка и досрочное завершение программы, мы увидели сообщение Ошибка №999 – деление на 0!!! Программа “перескочила” через операцию деления на 0 и выполнила catch-блок.

Чтобы вы лучше поняли, как значение генерируемое throw перехватывает catch-блок, замените код в строках 21 – 33 на этот:

В этом примере, если num2 равно 0, throw генерирует строку, а не число. Строка “падает” в catch-блок и выводится на экран.

Рассмотрим еще такой пример, когда исключение генерируется в функции, которая делит одно число на другое:

Чтобы исключение сработало правильно, эту функцию надо вызвать в блоке try:

catch перехватит число 99, а деление на 0 не состоится.

Основное, что нужно запомнить об исключениях в С++:

  • В try-блоке (блоке повторных попыток) необходимо размещать код, который потенциально может привести к аварийному закрытию программы;
  • Исключение генерируется в блоке throw. Если throw сработает программа автоматически приступит к выполнению команд catch-блока, игнорируя оставшийся код в try-блоке;
  • Улавливающий блок – catch-блок, перехватывает то, что генерирует блок throw. Он обязательно должен находиться под try-блоком. Ничего не должно быть прописано между ними;
  • catch-блок не сработает, если исключение не было сгенерировано. Программа его просто проигнорирует.

Чтобы поддержать наш сайт – нажмите на копилку. Вам будет предложено отправить SMS. Сумма – на ваш выбор.

Рассылка новых уроков по программированию: