Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ооп.docx
Скачиваний:
8
Добавлен:
26.09.2019
Размер:
129.74 Кб
Скачать

1)Си (англ. C) — стандартизированный процедурный язык программирования, разработанный в начале 1970-х годов сотрудниками Bell Labs Кеном Томпсоном и Деннисом Ритчи как развитие языка Би. Си был создан для использования в операционной системе UNIX.

Си – язык системного программирования; его принято относить к языкам среднего уровня, позволяющим

выполнять как стандартные высокоуровневые подпрограммы, так и ассемблерно ориентированный код.

Можно выделить следующие основные особенности Си:

 легкий доступ к аппаратным средствам компьютера, позволяющий писать высокоэффективные

программы;

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

архитектурой, так и между различными операционными средами;

 принцип построения "что пишем, то и получаем", т. е., в состав компилятора не включен код, который

мог бы проверить корректность работы программы в процессе ее выполнения;

 в транслятор не включена информация о стандартных функциях, отсутствуют операции, имеющие дело

непосредственно с составными объектами;

 компактный синтаксис, потенциально приводящий к трудноуловимым ошибкам.

Достоинства и недостатки

+-язык компактный, мало встроенных конструкций

-язык стандартизирован

-имеет широкую распространенность

-практически все ОС написаны или переписаны на Си/С++

-за время существования накоплены большие библиотеки алгоритмов

-Язык поддерживает низкоуровневые возможности

-Язык консервативен (нет стандартных средств: многопоточность, работа в сети и тд)

-не поддерживает объектно-ориентированную парадигму программирования.

Алфавит: базовый и расширенный

Базовый: основные конструкции (константы, идентификаторы, зарезервированные слова)

Расширенный: всевозможные знаки и символы, табуляция, переход на новую строку и тд

Идентификаторы: называется последовательность цифр и букв, а также специальных символов, при условии, что первой стоит буква или специальный символ. Для образования идентификаторов могут быть использованы строчные или прописные (они разные)буквы латинского алфавита. В качестве специального символа может использоваться символ подчеркивание _.

Триграф — последовательность из трёх символов, первые два— вопросительные знаки, а третий указывает на значение триграфа.

Зарезерви́рованное сло́во  , имеющее специальное значение. Идентификаторы с такими именами запрещены.

auto double int struct break else long switch register tupedef char extern return void case float unsigned default for signed union do if sizeof volatile continue enum short while

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

Стандартное комментирование блока /* ... */ как в C Комментирование линии с использованием //

Знаки операций

Знаки операций определяют действия, которые должны быть выполнены над операндами.

Операнд - это константа, литерал, идентификатор, вызов функции, индексное выражение, выражение выбора

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

операнд имеет тип.

Знак операции Операция Группа операций

* Умножение

/ Деление Мультипликативные

% Остаток от деления

+ Сложение Аддитивные

- Вычитание

<< Сдвиг влево Операции сдвига

>> Сдвиг вправо

< Меньше Операции отношения

<= Меньше или равно

>= Больше или равно

== Равно

!= Не равно

& Поразрядное И Поразрядные операции

| Поразрядное ИЛИ

^ Поразрядное исключающее ИЛИ

&& Логическое И Логические операции

|| Логическое ИЛИ

, Последовательное вычисление Последовательного вычисления

= Присваивание Операции присваивания

*= Умножение с присваиванием

/= Деление с присваиванием

%= Остаток от деления с присваиванием

-= Вычитание с присваиванием

+= Сложение с присваиванием

<<= Сдвиг влево с присваиванием

>>= Сдвиг вправо присваиванием

&= Поразрядное И с присваиванием

|= Поразрядное ИЛИ с присваиванием

^= Поразрядное исключающее ИЛИ с присваиванием

2) Константы

Целочисленные,вещественные,символьные(один символ) и строковые. Целые: десятичн,8-ричн, 16-ричн система счисления. (limits.h)

Веществ: float;(long) double; short (float.h)

Строковые: пример- “A”’A,’\0’’

Целочисленная константа представляет собой число, записываемое явным образом, например, 212 или 1776. В языке С++, как и в С, целые числа можно записывать в трех различных системах счисления: с основанием 10 (наиболее распространенная форма), с основанием 8 (старая запись в системах семейства Unix) и с основанием 16 (излюбленная форма компьютерных хакеров). Описание этих систем можно найти в приложении А, а сейчас мы остановимся на рассмотрении представлений в С++. В языке С++ для обозначения основания постоянного числа используется первая или две первые цифры. Если первая цифра находится в диапазоне 1-9, то это число десятичное (с основанием 10); поэтому основанием числа 93 является 10. Если первой цифрой является ноль, а вторая цифра находится в диапазоне 1-7, то это число восьмеричное (основание 8); таким образом, 042 — это восьмеричное значение, соответствующее десятичному числу 32. Если первыми двумя символами являются Ох или ОХ, то это шестнадцатеричное значение (основание 16); поэтому 0x42 — это шестнадцатеричное значение, соответствующее десятичному числу 66. В представлении десятичных значений символы a-f и A-F представляют шестнадцатеричные цифры, соответствующие значениям 10-15. OxF — это 15, а 0хА5 — это 165 (10 раз по шестнадцать плюс 5). В листинге 3.3 показан пример этих представлений. Листинг 3.3. hexoctl. cpp // hexoctl.cpp — показывает шестнадцатеричные и восьмеричные константы #include int main() { using namespace std; int chest =42; // десятичная целочисленная константа int waist = 0x42; // шестнадцатеричная целочисленная константа int inseam = 042; // восьмеричная целочисленная константа cout « "Monsieur cuts a striking figure!\n"; cout « "chest = " « chest « "\n"; cout « "waist = " « waist « "\n"; cout « "inseam = " « inseam << "\n"; return 0; } По умолчанию cout отображает целые числа в десятичной форме, независимо от того, как они были записаны в программе. Подтверждением этого является результат выполнения программы из листинга 3.3: Monsieur cuts a striking figure! chest = 42 (42 in decimal) waist = 66 (0x42 in hex) inseam = 34 (042 in octal) Имейте в виду, что эти обозначения используются просто для удобства. Например, если вы прочитаете, что сегментом видеопамяти CGA является В000 в шестнадцатеричном представлении, то вам не придется переводить его в значение 45056 десятичного формата, прежде чем применять его в своей программе. Наоборот, вы можете просто использовать ОхВООО. Вне зависимости от того, как вы запишете число десять— как 10, 012 или ОхА — в памяти компьютера оно будет храниться как двоичное число (с основанием 2). Между прочим, если вам нужно будет отобразить значение в шестнадцатеричной или восьмеричной форме, то для этого можно воспользоваться возможностями объекта cout. Вспомните, что заголовочный файл iostream предлагает манипулятор endl, который сигнализирует объекту cout о начале новой строки. Кроме этого манипулятора существуют манипуляторы dec, hex и oct, которые сигнализируют объекту cout о форматах отображения целых чисел: десятичном, шестнадцатеричном и восьмеричном, соответственно. В листинге 3.4 манипуляторы hex и oct применяются для отображения десятичного значения 42 в трех формах. (Десятичная форма используется по умолчанию, и каждая форма записи остается в силе до тех пор, пока вы не измените ее.) Листинг 3.4. hexoct2. cpp //hexoct2.cpp—отображает значения в шестнадцатеричном и восьмеричном формате #include using namespace std; int main() { using namespace std; int chest = 42; int waist = 42; int inseam = 42; cout « "Monsieur cuts a striking figure!" << endl; cout « "chest = " « chest « " (decimal)" « endl; cout << hex; // манипулятор для изменения основания системы счисления cout « "waist = " << waist « " hexadecimal" << endl; cout << oct; // манипулятор для изменения основания системы счисления cout « "inseam = " « inseam << " (octal)" << endl; return 0; Далее показан результат выполнения этой программы: Monsieur cuts a striking figure! chest = 42 (decimal) waist = 2a hexadecimal inseam = 52 (octal) Обратите внимание, что код, подобный cout << hex; ничего не отображает на экране монитора. Наоборот, он изменяет способ отображения целых чисел. Поэтому манипулятор hex на самом деле является сообщением для cout, на основании которого определяется дальнейшее поведение объекта cout. Обратите внимание также на то, что поскольку идентификатор hex является частью пространства имен std, используемого в этой программе, то программа не может применять hex в качестве имени переменной. Однако если опустить директиву using, и вместо нее использовать std: :cout, std: :endl, std: :hex и std: :oct, тогда hex можно будет использовать для именования переменных.

Теперь, после того как вы познакомились со всеми целочисленными типами в С++, мы можем перейти к рассмотрению чисел с плавающей точкой, которые составляют вторую основную группу фундаментальных типов в С++. Эта группа позволяет представлять числа с дробными частями, например, расход топлива танка Ml (0.56 миль на галлон). Также эта группа предлагает более широкий диапазон значений. Если число слишком большое, чтобы его можно было представить как тип long, например количество звезд в нашей галактике (примерно 400 000 0000 000), можно использовать один из типов чисел с плавающей точкой.

Посредством типов с плавающей точкой можно представлять такие числа, как 2.5 и 3.14159 и 122442.32 — то есть числа с дробными частями. Такие числа компьютер хранит в двух частях. Одна часть представляет значение, а другая часть увеличивает или уменьшает его. Приведем такую аналогию. Сравним два числа: 34.1245 и 34124.5. Они идентичны друг другу за исключением масштаба. Первое значение можно представить как 0.341245 (базовое значение) и 100 (масштабный множитель). Второе значение можно представить как 0.341245 (такое же базовое значение) и 100 000 (больший масштабный множитель). Масштабный множитель необходим для того, чтобы перемещать десятичную точка, которая поэтому и называется плавающей точкой. В языке С++ используется еще один похожий способ внутреннего представления чисел с плавающей точкой: он отличается тем, что основан на двоичных числах, поэтому масштабирование производится с помощью множителя 2, а не 10. К счастью, вам не нужно досконально разбираться в механизме внутреннего представления чисел. Вы должны усвоить одно: с помощью чисел с плавающей точкой можно представлять дробные очень большие и очень малые значения, и что их внутреннее представление сильно отличается от представления целых чисел.

Как и в ANCI С, язык С++ имеет три типа чисел с плавающей точкой: float, double и long double. Эти типы характеризуются количеством значащих цифр, которые они могут представлять, и минимальным допустимым диапазоном экспонент. Значащими цифрами являются значащие разряды числа. Например, запись высотной отметки горы Шаста (Shasta) в Калифорнии 14162 фута содержит пять значащих цифр, которые определяют высоту с точностью до ближайшего фута. А в записи высотной отметки этой же горы 14000 футов используется две значащие цифры, поэтому результат округляется до ближайшего тысячного фута; в данном случае остальные три разряда являются просто заполнителями. Количество значащих цифр не зависит от позиции десятичной точки. Например, высоту можно записать как 14.162 тысяч футов. В этом случае также используются пять значащих разрядов, поскольку это значение имеет точность до пятого разряда.

Требования в языках С и С++ относительно количества значащих разрядов следующие: тип float должен иметь как минимум 32 бита, double должен иметь как минимум 48 битов и, естественно, быть не меньше чем float, и long double должен быть как минимум таким же, как и тип double. Все три типа могут иметь одинаковый размер. Однако обычно float имеет 32 бита, double имеет 64 бита, a long double имеет 80, 96 или 128 битов. Кроме того, диапазон экспонент для каждого из этих трех типов ограничен в пределах от -37 до +37. Об ограничениях системы можно узнать в файле cfloat или float.h. (Файл cfloat является аналогом файла float.h в языке С.) Далее в качестве примера показаны некоторые строки из файла float.h для Borland C++Builder:

// минимальное количество значащих цифр #define DBL_DIG 15 // double #define FLT_DIG 6 // float #define LDBL_DIG 18 // long double // количество битов, используемых для представления мантиссы #define DBL_MANT_DIG 53 #define FLT_MANT_DIG 24 #define LDBL_MANT_DIG 64 // максимальные и минимальные значения экспоненты #define DBL_MAX_10_EXP +308 #define FLT_MAX_10_EXP +38 #define LDBL_MAX_10_EXP +4 932 #define DBL_MIN_10_EXP -307 #define FLT_MIN_10_EXP -37 #define LDBL_MIN_10_EXP -4 931 Замечание по совместимости He все реализации языка С++ имеют заголовочный файл cfloat, и также не все реализации, основанные на компиляторах, разработанных до выхода стандарта ANSI С, имеют заголовочный файл float .h. В листинге 3.8 показан пример использования типов float и double и продемонстрированы также их различия в точности, с которой они представляют числа (то есть количество значащих цифр). В программе показан пример использования метода ostream, который называется setf (); о нем мы будем говорить в главе 17. В данном примере этот метод устанавливает формат вывода с фиксированной точкой, который позволяет визуально определять точность выходных данных. Благодаря этому методу программа не будет переключаться на экспоненциальное обозначение больших чисел и будет отображать шесть цифр справа от десятичной точки. Аргументы ios base: : fixed и ios base: : floatfield являются константами из файла iostream. Листинг 3.8. floatnum.cpp // floatnum.cpp — типы с плавающей точкой #include int main() { using namespace std; cout.setf(ios_base::fixed, ios_base::floatfield) ; // фиксированная точка float tub = 10.0/3.0; // подходит для б разрядов double mint = 10.0/3.0; // подходит для 15 разрядов const float million = 1.0e6; cout « "tub = " « tub; cout << ", a million tubs = " << million * tub; cout << ",\nand ten million tubs = "; cout « 10 * million * tub << endl; cout << "mint = " << mint << " and a million mints = "; cout « million * mint << endl; return 0; Ниже показан пример выполнения этой программы: tub = 3.333333, a million tubs = 3333333.250000, and ten million tubs = 33333332.000000 mint = 3.333333 and a million mints = 3333333.333333 Замечание по совместимости В стандарте С++ заменены ios : : fixed на ios_base : : fixed и ios : : floatfield на ios_base: : floatfield. Если ваш компилятор не принимает формы ios_base, попробуйте использовать вместо них ios; другими словами, замените ios: : fixed на ios_base: : fixed и так далее. По умолчанию в старых версиях С++ при отображении значений с плавающей точкой отображались в общей сложности шесть цифр справа от десятичной точки, например 2345.831541. В стандарте С++ по умолчанию отображается шесть цифр (2345.83), при этом, если значения достигают миллиона или более, происходит переключение на экспоненциальную форму (2.34583Е+06). В режимах отображения, не используемых по умолчанию, как в fixed из предыдущего примера, отображаются шесть цифр справа от десятичной точки в старых и в новых версиях. В настройке по умолчанию удаляются конечные нули, отображая 23.4500 как 23.45. Реализации языка отличаются реакцией на использование оператора setf () для отмены настроек по умолчанию. В старых версиях, например Borland С++ 3.1 для DOS, также удаляются конечные нули. Версии, соответствующие стандарту, такие как Microsoft Visual С++ 7.0, Metrowerks CodeWarrior 9, Gnu GCC 3.3 и Borland С++ 5.5, отображают нули, как показано в листинге 3.8.

Когда в своей программе вы записываете константу с плавающей точкой, с каким именно типом программа будет хранить ее значение? По умолчанию константы с плавающей точкой, например, 8.24 и 2.4Е8, имеют тип double. Чтобы константа имела тип float, необходимо указать суффикс f или F. Для типа long double используется суффикс 1 ирги L. (Поскольку начертание буквы 1 в нижнем регистре очень похоже на начертание цифры 1, рекомендуется использовать верхний регистр.) Далее показаны примеры использования суффиксов: 1.234f // константа float 2.45E20F // константа float 2.345324Е28 // константа double 2.2L // константа long double

Строковая константа представляет собой последовательность символов кода ASCII, заключенную в двойные кавычки: "Character constant".

Строковая константа - это массив символов, заключенный в кавычки. Она имеет тип string. Если необходимо ввести в строку двойную кавычку ("), то перед ней надо поставить символ обратной косой черты (\). В строку могут быть введены любые специальные символьные константы, перед которыми стоит символ обратной косой черты (\). Длина строковой константы - от 0 до 255 символов. Если длина строковой константы превосходит максимальную, лишние символы справа отбрасываются, и компилятор выдает соответствующее предупреждение.

Примеры:

"This is a character string"

"Это строковая константа"

"Символ копирайта\t\xA9"

"эта строка содержит символ перевода строки \n"

"C:\\Program Files\\MetaTrader 4"

"А" "1234567890" "О" "$"

Внутреннее представление - структура размером 8 байт. Первый элемент структуры - длинное целое, содержит размер распределенного для строки буфера. Второй элемент структуры - 32-разрядный адрес буфера, содержащего строку.

3) Общая структура программы

include <stdio.h> - деректива препроцессора

int main() - обьявление функции с именем main (возвращающ. Целочисл значение)

{ тело фунции (описание переменных и действия)

return 0 – возвращает управление из функции main;}

4) Операции: математические операции, присваивание, составное присваивание, преобразование типов, операции отношения, операции инкремента (++) и декремента (--), операция sizeof, операция <<запятая>> ,указатель; определение адреса переменной

Выражения – это переменные, функции и константы, называемые операндами, объединенные знаками операций, возвращает значение

5)

6) Целочисленные: char; short; int; long

Вещественные(числа с плавающей точкой): float; long double;double

[класс памяти] описание типа......имя [,имя2];

7)Глобальная переменная (классы памяти exturn, static) в общ случае время жизни бесконечно.

Локальная переменная (классы памяти auto, register) время жизни ограничено временем выполнения блока, в котором оно объявлено.

8)Имя вводится в программе с помощью описания, которое задает его тип и, возможно, начальную величину. Перед использованием имени (идентификатора) в программе оно должно быть описано. То есть следует задать его тип, чтобы сообщить компилятору, к какого вида объектам относится имя.

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

9) Классы памяти (влияет на область видимости и время жизни переменной)

auto — автоматическая (локальная).

static — статическая переменная (локальная). Хранение только в одном файле, но как глобальной переменной

extern — внешняя (глобальная) переменная. Автоматически, глобальная во всех файлах

register — регистровая переменная (локальная) (для частоиспользуемых переменных)

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

[тип] имя([список формальных параметров])

описания формальных параметров;

{описания;

операторы;}

11) Назначение прототипа функции-

объявление функции, которое не содержит тело функции, но указывает имя функции, арностьтипы аргументов и возвращаемый тип данных. Пример: int foo(int n);

12)Оператор выражение, который имеют вид: выражение;

Составной оператор, или блок дает возможность использовать несколько операторов в том месте, где предполагается использование одного: { список операторов}

Условный оператор if ( выражение ) оператор; if ( выражение ) оператор else оператор

Оператор while: while ( выражение ) оператор

Оператор do: do оператор while (выражение);

Оператор for: for ( выражение_1 ; выражение_2 ; выражение_3 ) оператор

Оператор switch вызывает передачу управления на один из нескольких операторов

switch ( выражение ) оператор Выражение должно быть целого типа или типа указателя. Любой оператор внутри оператора помечен одним или более префиксом case: case константное_выражение :

один префикс оператора вида default :

Оператор break ;прекращает выполнение ближайшего охватывающего оператора;

Оператор continue ;вызывает передачу управления на управляющую продолжением цикла часть т.е. на конец петли цикла.

Возврат из функции в вызывающую программу осуществляется с помощью оператора return, им два вида: return ; return выражение ;

Пустой оператор имеет вид ;

Оператор delete имеет вид delete выражение ; Результатом выражения должен быть указатель.

Оператор goto метка; метка предварительно описывается

13) Массивы-конечная совокупность данных одного типа

Имя массива – адрес нулевого элемента

Описание. Элементы не могут быть void, function. Могут быть массивом, указателем.

Инициализация. Можно использовать явную и неявную инициализацию(int x[10], int x[3]={1,2,3})

Z[100]={1,2,3} если описание не полное, то остальные обнуляются. Можно задавать неявно z[]={1,2,3,4,5}; <- (z[5])

Многомерные массивы

double d[2][3]; d[0][0]=1.76; double d[2][3]={1,2,3,4,5,6}; char ch[ ][2]={‘A’, ‘B’, ‘C’, ‘D’};

В многомерном массиве вторая и след. размерности задают тип элементов, влияют на размер массива.

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

Передача массивов в функции

Функция может инициализировать массив, прибавить к массиву значения или вывести элементы массива на экран. Когда вы передаете массив в функцию, вы должны указать тип массива. Нет необходимости указывать размер массива. Вместо этого вы передаете параметр например number_of_elements, который содержит количество элементов в массиве void some_function(int array[], int number_of_elements);

14) В C++ можно передавать параметры в функцию по значению (func2) и по ссылке (func1):

void func1 ( A& a ); void func2 ( A a );

Здесь кроется засада: в func2 внутрь функции передается на самом деле не a, а его копия.

Пример,swap

void swap (int x; int y) {

int tmp=x; x=y; y=tmp; }

int main(){

int a=5, b=10;

swap (a,b);

printf(“a=%d\t b=%d\n”,a,b);

}

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

15)

Указатели –это переменная, содержащая адрес памяти или функции. Ук-ли разделяют на данные(типизированные и нет.) и на код(тип.). Базовый_тип *имя;

как хранится в памяти-целое неотрицательное значение; мн-во допустимых значений-допустимые значения адресов

Мн-во допуст. операц. для нетип. указ. явл. подмн-вом мн-ва допуст. опер. для типизиров.

ДЛЯ НЕТИП(void *pv): операц. получения адреса &, =,если в левой части нетипизир указатель, а в правой любой указатель, ==, !=, <, <=, >, >=. int *p,x=5; p=&x; Операция разодресации *р=100;

ДЛЯ ТИП: =, если в левой части тип. указатель, то и в правой части указатель такого же типа. На типиз. указ. на данные разрешена функция индексирования. P [2] эквивалентно записи *(P+2) , *(2+P) = 2[P]

16) 1-Когда нужно работать с конкретным адрессом.

2-Когда функция должна изменять передаваемые ей аргументы. void swap(int *x,int *y) {int tmp=*x;*x=*y;*y=tmp;}

void main() {int a=5, b=10; swap (&a,&b);}

3-Когда мы обр. к функции-ссылке компилятор применяет к адресу операцию разодресацию

(В С++ определен ссылочный тип данных. Ссылка – скрытый указатель) void swap(int &x,int &y) {int tmp=x;x=y;y=tmp;}

void main() {int a=5, b=10; swap (a,b);}

4-Когда ф-я должна возвращать адрес

17)Динамическое распределение памяти

ОС позволяет программе захватывать свободные блоки постранично(4кб) Исполняющая система С Runtime(минимум 4байта) Стартовый код создает списки свободных и занятых блоков в куче (В каждой записе о блоке хранится адрес его начала и размер в байтах) Для динамического распр. памяти в стандартной библ. есть 4 функции. stdlib.h

void malloc(t size); t-unsigned int, ф-я malloc пытается захватить в куче блок размером size, возвращает адресс блока, если неудача то возвр. NULL.

new and delete в С++

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

Оператор delete возвращает память, выделенную оператором new, обратно в кучу. Вызов delete должен происходить для каждого вызова new, дабы избежать утечки памяти. После вызова delete объект, указывающий на этот участок памяти, становится некорректным и не должен больше использоваться.

18)Работа с указателями на примере строк

Вывод строки на экран:

#include <iostream.h>

void show_string(char *string)

{    while (*string != '\0')

   {       cout<<*string;        string++;     } }

void main(void)

{    show_string("Учимся программировать на языке C++!"); }

Определения количества символов в строке:

#include <iostream.h>

int string_length(char *string)

{    int length = 0;     while (*string != '\0')

   {       length++;        string++;    }     return(length); }

void main(void)

{    char title[] = "Учимся программировать на языке C++";     cout << title << " содержит " << string_length(title) << " символов"; }

Сравнение строк:

int strcmp(const char *a, const char *b);

strcmp сравнивает две строки

Если *a в лексикографическом порядке идет после *b, то strcmp возвращает

число, большее нуля. Если две строки совпадают, то strcmp возвращает ноль.

Если *a в лексикографическом порядке идет пеpед *b, то strcmp возвращает

число, меньшее нуля.

Си-вариант:

int strcmp(const char *cs, const char *ct)

{

signed char __res;

while (1) {

if ((__res = *cs - *ct++) != 0 || !*cs++)

break;

}

return __res;

}

Сравнение строк

Для лексикографического сравнения строк используются функции strcmp и

stricmp. Первая сравнивает строки с учетом регистра, вторая – без. Однако, все

это относится только к латинице. Если вы хотите сравнивать без учета регистра

кириллические строки, придется разобраться с локалями.

Прототипы этих функций таковы:

int stricmp(const char *string1, const char *string2);

int strcmp(const char *string1, const char *string2); Обе функции возвращают число меньшее 0, если первая строка меньше второй,

большее нуля если первая строка больше второй и 0, если строки

лексикографически равны.

Полагаю, вам не придет в голову сравнивать строки, используя операции ‘<’ и ‘>’.

Конкатенация строк

char* strcat(char* dest, const char* source)

char* strncat(char* dest, const char* source, size_t size)

Эти функции добавляют к строке, на которую указывает dest, символы из строки source. Первая версия добавляет все символы до нуль-терминатора, вторая – максимум size символов. Результирующая строка завершается нуль-терминатором.

Удалить последний символ строки

String s = "aljfhwfhgc vwiu"; s.Delete(10, 5);//s = "aljfhwfhgc"

Удаление символов строки #include <string>

erase (size_type pos=0,size_type n=npos) - удаляет n символов с указанной позиции;

erase (iterator p) - удаляет один символ в указанной позиции;

erase (iterator f, iterator l) - удаляет символы с позиции f по l.

19) Сегмент данных для хранения констант

Директива #define служит для замены часто использующихся констант,

ключевых слов, операторов или выражений некоторыми идентификаторами.

Идентификаторы, заменяющие текстовые или числовые константы, называют

именованными константами. Идентификаторы, заменяющие фрагменты

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

иметь аргументы.

Директива #define имеет две синтаксические формы:

#define идентификатор текст

#define идентификатор (список параметров) текст

Препроцессор С/С++ — программный инструмент, изменяющий код программы для

последующей компиляции и сборки, используемый в языках программирования Си и его

потомка - C++. Этот препроцессор обеспечивает использование стандартного набора

возможностей:

 Замена триграфов ??=, ??(, ??) (и других) символами #, [, ]

 Замена комментариев пустыми строками

 Включение файла — #include

 Макроподстановки — #define

 Условная компиляция — #if, #ifdef, #elif, #else, #endif

define — задаёт макроопределение (макрос) или символическую константу

Замена лексических единиц. Командная строка вида #define name text вызывает в оставшейся части

программы замену всех вхождений идентификатора name на строку text. Например, определение #define p1

3.14159265 позволяет использовать в программе имя p1 вместо константы 3.14159265. Обратите внимание, что

это определение не завершается точкой с запятой. Замещающий текст обычно представляет собою остаток

строки. Длинное определение можно продолжить, если в конце продолжаемой строки поставить \. Внутри

строк, заключенных в кавычки, подстановка не производится, так что, например, для определенного выше

имени P1 в printf("P1"); подстановки не будет. Имена могут переопределяться и новые определения могут

использовать ранее введенные определения.

Применение моделей памяти позволяет контролировать ее сегментное распределение и делать его более эффективным или

адекватным решаемой задаче. По умолчанию при компиляции и редактировании связей генерируется код для работы в малой (small)

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

 размер кода программы превышает 64 Кб;

 размер статических данных программы превышает 64 Кб.

Имеется два варианта выбора модели памяти для программы:

 назначить нужную модель в опциях компилятора;

 использовать в объявлении объектов программы модификаторы near, far и huge.

Можно комбинировать эти способы.

Архитектура процессоров, основанных на базе 8086/8088, предусматривает разбиение оперативной памяти на физические сегменты,

способные содержать информацию объемом до 64 Кб. Минимальное количество сегментов, выделяемое программе, равно двум: сегмент

кода и сегмент статических данных. К статическим данным при этом относятся все объекты, объявленные с классом памяти extern или

static. Формальные параметры функций и локальные переменные не являются статическими. Они хранятся не в сегменте данных, а в

стеке (однако при этом стек может быть совмещен со стандартным сегментом данных физически).

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

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

данными области и стеком (ближняя динамическая память).

Адрес оперативной памяти состоит из двух частей:

 базовый адрес сегмента — 16-битовое число;

 смещение относительно начала сегмента — также 16-битовое число.

Для доступа к коду или данным, находящимся в единственном стандартном сегменте, достаточно использовать только смещение. В

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

быстродействием.

Если код или данные находятся в другом сегменте по отношению к адресующему, для доступа к ячейке памяти должны и адрес

сегмента, и смещение. В этом случае указатели объявляются с модификатором far (дальний). Доступ к объектам по дальним указателям

позволяет программе адресовать всю оперативную память, а не только в пределах сегмента размером 64 Кб.

Наконец, указатели с модификатором huge (максимальный) также включают адрес сегмента, и смещение, но имеют иную адресную

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

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

объекта объемом 64 Кб. Для указателей huge арифметические действия выполняются над всеми 32 битами адреса.

Тип адреса huge определен только для данных, таких как массивы и указатели на них. Таким образом, никакой из исходных файлов,

составляющих программу, не должен генерировать более 64 Кб кода.

Кратко опишем шесть имеющихся в Си моделей памяти.

Минимальная модель (tiny). Код вместе с данными не превышает по объему 64 Кб. Применялась для исполняемых файлов,

преобразуемых к формату *.com.

Малая модель (small). Программа занимает 2 стандартных сегмента: сегмент кода и сегмент данных, в котором размещается также

стек. Как код, так и данные программы не могут превышать 64 Кб. Модель подходит для большинства несложных программ и назначается

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

Средняя модель (medium). Для данных и стека выделяется один сегмент, для кода — произвольное число сегментов. Каждому

исходному модулю программы выделяется собственный сегмент кода. Модель применяется для программ с большим количеством кода

(более 64 Кб) и небольшими объемами данных (менее 64 Кб). Для доступа к функциям по умолчанию используются указатели far, а для

доступа к данным — указатели near. Модель предлагает компромисс между скоростью выполнения и компактностью кода, поскольку

многие программы чаще обращаются к данным, чем к функциям.

Компактная модель (compact). В этой модели выделяется один сегмент для кода, и произвольное число сегментов для данных.

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

указателям near, а к данным — по указателям far.

Большая модель (large) использует по несколько сегментов и для кода, и для данных. Модель подходит для больших программ со

значительным объемом данных. В этой модели доступ к элементам кода и данных производится по указателям типа far. Как и во всех

предшествующих моделях умолчания можно обойти, явно используя модификаторы near, far и huge там, где они требуются при

объявлении данных и функций.

Максимальная модель (huge) аналогична большой за исключением того, что в ней снимается ограничение на размер массивов в 64 Кб.

Однако для больших массивов не допускается пересечения элементами границ сегмента, из чего следует, что элемент массива не может

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

быть степенью двойки.

20) string.h

char *strcopy(char *dsk, char *src); \\ из src копирует в dsk

int strcomp(char *s1, char *s2); \\ сравнение строк, то что по алф раньше-меньше

char *strcut (char *s1, char *s2); \\ s2 дописывается к s1

сhar *strstr(char *str,char *substr); \\ первое вхождение substr в строке str

сhar *strchr(char *str,int key); \\ первое вхождение символа key в строкe str

int strlen(char *s);

char *strtok(char * str, char * delim); \\ разбивает фразу на части

21) Функция strtok

#include <string.h>

char *strtok(char *str1, const char *str2);

Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1. Символы, образующие строку, адресуемую параметром str2, представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.

В версии С99 к параметрам str1 и str2 применен квалификатор restrict.

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

При каждом обращении к функции strtok() можно использовать различные наборы разделителей.

Пример

Эта программа разбивает строку "Травка зеленеет, солнышко блестит" на лексемы, разделителями которых служат пробелы и запятые. В результате получится

Травка|зеленеет|солнышко|блестит

#include <stdio.h>

#include <string.h>

int main(void)

{

char *p;

p = strtok("Травка зеленеет, солнышко блестит", " ");

printf(p);

do {

p = strtok('\0', ", ");

if(p) printf("|%s", p);

} while(p);

return 0;

}

ПР. Разбить текст на лексемы

#include <stdio.h>

#include<string.h>

int main (){

char *s=”Hello_World!”;

str[]=”Hello_World!”;

char *word;

char *dilim=” !”;

word=strtok (str,dilim);

while(word !=Null){

printf(“% s\n”,word);

word=strtok(Null,delim);}

return 0; }

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

Указатели на функции[1] — очень мощное средство языка С. Хотя нельзя не отметить, что это весьма трудный для понимания термин. Функция располагается в памяти по определенному адресу, который можно присвоить указателю в качестве его значения. Адресом функции является ее точка входа. Именно этот адрес используется при вызове функции. Так как указатель хранит адрес функции, то она может быть вызвана с помощью этого указателя. Он позволяет также передавать ее другим функциям в качестве аргумента.

В программе на С адресом функции служит ее имя без скобок и аргументов (это похоже на адрес массива, который равен имени массива без индексов). Рассмотрим следующую программу, в которой сравниваются две строки, введенные пользователем. Обратите внимание на объявление функции check() и указатель p внутри main(). Указатель p, как вы увидите, является указателем на функцию.

#include <stdio.h>

#include <string.h>

void check(char *a, char *b,

int (*cmp)(const char *, const char *));

int main(void)

{

char s1[80], s2[80];

int (*p)(const char *, const char *);

/* указатель на функцию */

p = strcmp;

/* присваивает адрес функции strcmp указателю p */

printf("Введите две строки.\n");

gets(s1);

gets(s2);

check(s1, s2, p); /* Передает адрес функции strcmp

посредством указателя p */

return 0;

}

void check(char *a, char *b,

int (*cmp)(const char *, const char *))

{

printf("Проверка на совпадение.\n");

if(!(*cmp)(a, b)) printf("Равны");

else printf("Не равны");

}

Проанализируем эту программу подробно. В первую очередь рассмотрим объявление указателя p в main():

int (*p)(const char *, const char *);

Это объявление сообщает компилятору, что p — это указатель на функцию, имеющую два параметра типа const char * и возвращающую значение типа int. Скобки вокруг p необходимы для правильной интерпретации объявления компилятором. Подобная форма объявления используется также для указателей на любые другие функции, нужно лишь внести изменения в зависимости от возвращаемого типа и параметров функции.

Теперь рассмотрим функцию check(). В ней объявлены три параметра: два указателя на символьный тип (a и b) и указатель на функцию cmp. Обратите внимание на то, что указатель функции cmp объявлен в том же формате, что и p. Поэтому в cmp можно хранить значение указателя на функцию, имеющую два параметра типа const char * и возвращающую значение int. Как и в объявлении p, круглые скобки вокруг *cmp необходимы для правильной интерпретации этого объявления компилятором.

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

(*cmp)(a, b)

вызывает функцию strcmp(), на которую указывает cmp, с аргументами a и b. Скобки вокруг *cmp обязательны. Существует и другой, более простой, способ вызова функции с помощью указателя:

cmp(a, b);

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

Вызов функции check() можно записать, используя непосредственно имя strcmp():

check(s1, s2, strcmp);

В этом случае вводить в программу дополнительный указатель p нет необходимости.

У читателя может возникнуть вопрос: какая польза от вызова функции с помощью указателя на функцию? Ведь в данном случае никаких преимуществ не достигнуто, этим мы только усложнили программу. Тем не менее, во многих случаях оказывается более выгодным передать имя функции как параметр или даже создать массив функций. Например, в программе интерпретатора синтаксический анализатор (программа, анализирующая выражения) часто вызывает различные вспомогательные функции, такие как вычисление математических функций, процедуры ввода-вывода и т.п. В таких случаях чаще всего создают список функций и вызывают их с помощью индексов.

Альтернативный подход — использование оператора switch с длинным списком меток case — делает программу более громоздкой и подверженной ошибкам.

В следующем примере рассматривается расширенная версия предыдущей программы. В этой версии функция check() устроена так, что может выполнять разные операции над строками s1 и s2 (например, сравнивать каждый символ с соответствующим символом другой строки или сравнивать числа, записанные в строках) в зависимости от того, какая функция указана в списке аргументов. Например, строки "0123" и "123" отличаются, однако представляют одно и то же числовое значение.

#include <stdio.h>

#include <ctype.h>

#include <stdlib.h>

#include <string.h>

void check(char *a, char *b,

int (*cmp)(const char *, const char *));

int compvalues(const char *a, const char *b);

int main(void)

{

char s1[80], s2[80];

printf("Введите два значения или две строки.\n");

gets(s1);

gets(s2);

if(isdigit(*s1)) {

printf("Проверка значений на равенство.\n");

check(s1, s2, compvalues);

}

else {

printf("Проверка строк на равенство.\n");

check(s1, s2, strcmp);

}

return 0;

}

void check(char *a, char *b,

int (*cmp)(const char *, const char *))

{

if(!(*cmp)(a, b)) printf("Равны");

else printf("Не равны");

}

int compvalues(const char *a, const char *b)

{

if(atoi(a)==atoi(b)) return 0;

else return 1;

}

Если в этом примере ввести первый символ первой строки как цифру, то check() использует compvalues(), в противном случае — strcmp(). Функция check() вызывает ту функцию, имя которой указано в списке аргументов при вызове check(), поэтому она в разных ситуациях может вызывать разные функции. Ниже приведены результаты работы этой программы в двух случаях:

Введите два значения или две строки.

тест

тест

Проверка строк на равенство.

Равны

Введите два значения или две строки.

0123

123

Проверка значений на равенство.

Равны

Сравнение строк 0123[2] и 123 показывает равенство их значений.

[1]Иногда их называют просто указателями функций. Но следует помнить, что в языках программирования под этим термином подразумевается также средство обращения к подпрограмме-функции или встроенной функции, имеющее конструкцию <имя-функции> (<список-аргументов>).

[2]Обратите внимание, что в языке С нулем начинаются восьмеричные константы. Если бы эта запись была в выражении, то 0123 не было бы равно 123. Однако здесь функция atoi() обрабатывает это число как десятичное.

23) Описания в кот. встреч. [],(),* считаются сложными

Пример int *(*f[3])(int, double) 1- имя f. 2-массив в 3х эл. (Если справа () – то функция, если [] то массив)

3- массив из 3х указателей на функцию с 2мя арг. int, double.(Ecли справа от имени есть(), а слева *, то приоритет имеют скобки) 4-тип возвращ. значения вначале int *,т.е. функции возвращ. указатели на int.

24) Примеры использования массивов указателей.

определение:

int *array[6]; вводит массив указателей на объекты типа int. Имя массива array, он состоит из

шести элементов, тип каждого int *. Определение:

int (*ptr)[6];

вводит указатель ptr на массив из шести элементов, каждый из которых имеет

тип int. Возможность создания массивов указателей позволяет экономить память при

использовании многомерных массивов.

По определению массива, его элементы должны быть однотипные и одинаковые по

длине. Пусть необходимо определить массив для представления списка фамилий. Если

определять его как двумерный массив типа char, то в определении элементов массива

необходимо задать предельные размеры каждого из двух индексов, например: char

spisok[25][20];. Таким образом, количество фамилий в списке не более 25 и что длина

каждой фамилии не превышает 19 символов (букв). При определении массива одну из его

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

случае количество элементов массива определяется, например, инициализацией (рис.1):

char spisok[][20] = {"ИВАНОВ", "ПЕТРОВ", "СИДОРОВ"}; .

Рис.1. Схема размещения в памяти элементов массива spisok

Теперь в массиве spisok только 3 элемента, каждый из них длиной 20 элементов

типа char. В противоположность этому при определении и инициализации этими же

символьными строками одномерного массива указателей типа char *память

распределяется гораздо рациональнее (рис.2):

Рис.2. Схема размещения в памяти элементов с помощью массива указателей

Для указателей массива pointer, в котором 3 элемента и каждый является указателем-

переменной типа char *, выделяется всего 3*sizeof(char *) байтов. Кроме того,

компилятор размещает в памяти три строковые константы "ИВАНОВ" (7 байт), ПЕТРОВ"

(7 байт), "СИДОРОВ" (8 байт), а их адреса становятся значениями элементовpointer[0],

pointer[l], pointer[2] (рис.2).

Применение указателей и их массивов позволяет рационально решать, в частности,

задачи сортировки сложных объектов с неодинаковыми размерами. Например,

рассмотрим задачу сортировки строк матрицы. Матрица с элементами

типа double представлена двумерным массивом double array [n][m], где n и m -

целочисленные константы. Предположим, что нужно упорядочить строки матрицы в

порядке возрастания сумм их элементов. Чтобы не переставлять сами строки исходного массива введен вспомогательный одномерный массив указателей double * par[n].

Инииализируем его элементы адресами массивов строк. В качестве значений элементов

массива используем номера строк. Матрицу напечатаем три раза: до и после сортировки с

помощью вспомогательного массива указателей и (после сортировки) с использованием

основного имени массива.

Приведем текст этой программы.

#include <iostream.h>

void main()

{

const int n=5; //Количество строк.

const int m=7; //Количество столбцов.

double array[n][m]; //Основной массив.

for (int i=0;i<n;i++)

for (int j=0;j<m;j++)

array[i][j]=n-i; //Заполнение массива.

double *par[n]; //Массив указателей.

for (i=0;i<n;i++) //Цикл перебора строк.

par[i]=(double*)array[i];

//Печать массива через указатели.

cout << "\n До перестановки элементов массива указателей: ";

for (i=0;i<n;i++)

{ cout<< "\n строка " << i+1 <<": ";

for (int j=0;j<m;j++)

cout << "\t" << par[i][j];

}

//Упорядочение указателей на строки массива.

double si,sk;

for (i=0;i<n-1;i++)

{ for (int j=0, si=0;j<m;j++)

si+=par[i][j];

for (int k=i+1;k<n;k++)

{ for (j=0,sk=0;j<m;j++)

sk+=par[k][j];

if (si>sk)

{ double *pa=par[i];

par[i]=par[k];

par[k]=pa;

double a=si;

si=sk;

sk=a;

}

}

}

//Печать массива через указатели.

cout << "\nПосле перестановки элементов массива:";

for (i=0;i<n;i++)

{ cout << "\n строка " << i+1 <<": ";

for (int j=0;j<m;j++)

cout << "\t" << par[i][j];

}

cout << "\nИсходный массив остался неизменным: ";

for (i=0;i<n;i++)

{ cout << "\nstroka " << i+1 <<": ";

for (int j=0;j<m;j++)

cout << "\t" << array[i][j]; }

}

25) typedef-позволяет задавать новые имена типов. Пример typedef int INT; INT x=5;

Конструкция typedef позволяет задавать новые имена типов.

Tupedef int INT

Т.е теперь типы одинаковы)

Typedef

Int Int *Pint

Pint ptr int *ptr

Pint *ptr int **ptr

typedef позволяет объявить синоним нашей переменной. Вот пример использования

ключевого слова typedef в языке си ( c ):

typedef struct foot_klub f_club;

f_club a, *p, b[5];

Т.е. мы заменили struct foot_klub синонимом f_club, что в разы облегчает понимание

кода. Большинство программистов на языке си ( с ) используют typedef сразу при

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

typedef struct {

char name[20];

int liga;

float ochki;

}f_club;

Т.е. при объявлении вместе двух ключевых слов - typedef struct, мы сразу создаем тип

f_club. Теперь для объявления переменной созданного типа достаточно всего-навсего

воспользоваться одним словом. С основами разобрались!

26) Препроцессор С/С++ — программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка - C++. Этот препроцессор обеспечивает использование стандартного набора возможностей:

Замена триграфов ??=, ??(, ??) (и других) символами #, [, ]

Замена комментариев пустыми строками

Включение файла — #include

Макроподстановки — #define

Условная компиляция — #if, #ifdef, #elif, #else, #endif

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

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

27) Макросы в языке Си преимущественно используются для определения небольших фрагментов кода. Во время обработки кода препроцессором, каждый макрос заменяется соответствующим ему определением. Если макрос имеет параметры, то они указываются в теле макроса; таким образом, макросы языка Си могут походить на Си-функции. Распространенная причина использования — избежание накладных расходов при вызове функции в простейших случаях, когда небольшого кода, вызываемого функцией, достаточно для ощутимого снижения производительности.

Например,

#define max(a,b) ((a) > (b) ? (a) : (b))

определяет макрос max, использующий два аргумента a и b. Этот макрос можно вызывать как любую Си-функцию, используя схожий синтаксис. То есть, после обработки препроцессором,

z = max(x,y);

становится

z = ((x) > (y) ? (x) : (y));

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

Например, если f и g — две функции, вызов

z = max(f(), g());

не вычислит один раз f()и один раз g(), и поместит наибольшее значение в z, как этого можно было ожидать. Вместо этого одна из функций будет вычислена дважды. Если функция имеет побочные эффекты, то вероятно, что её поведение будет отличаться от ожидаемого.

28) #ifdef имя

текст

#endif

Если имя было прежде объявлено с помощью define тогда текст поступает на вход компилятора

#ifтdef имя

текст

#endif

Если имя не было прежде объявлено с помощью define тогда текст компилируется. применяется в заголовочных файлах.

my.h

#ifndef _ _MY_H_FILE_ _

int x;

#define _ _MY_H_FILE_ _

…….

#endif

#if выражение (только константы и +! -! || && != == << = >>)

Текст 1

[#elif выражение 2 текст 2]

……….

[#elif выражение N текст N]

[#else

текст

#endif

Если значение выражения не 0 то компилируется текст1, все остальные нет

#include <stdio.h>

#define STEP 1

int main () {

#if STEP = = 1

printf(‘”zadanie 1\n”);

#elif STEP = = 2

………

#endif

return 0; }

29) Стандартные операции, определенные для препроцесса.

Компилятор языка C++ содержит препроцессор,способный выполнять макроподстано

вки, условную компиляцию и включение именованных файлов. Строки, начинающиеся с

#, относятся к препроцессору.

Смотреть походу препроцессор

30) Предопределённые макросы

Существуют встроенные (заранее определенные) макроимена, доступные препроцессору

во время обработки. Они позволяют получить следующую информацию (таблица 1):

Таблица 1. Общие встроенные макроимена

Макрос Назначение

__LINE__

Десятичная константа - номер текущей обрабатываемой строки файла с программой C++. Принято,

что номер первой строки исходного файла равен 1.

__FILE__

Строка символов - имя компилируемого файла. Имя изменяется всякий раз, когда препроцессор

встречает директиву#include с указанием имени файла. После окончания включения файла по

команде #include восстанавливается предыдущее значение макроимени __FILE__.

__DATE__

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

файла.

__TIME__

Строка символов вида "часы:минуты:секунды", определяющая время начала обработки

препроцессором текущего исходного файла.

__STDC__

Константа, равная 1, если компилятор работает в соответствии с ANSI-стандартом. В противном

случае значение макроимени не определено. Проект стандарта C++ предполагает, что наличие

имени __STDC__ определяется реализацией.

__cplusplus

Имя, определенное равным 1 при компиляции программы на языке C++. В остальных случаях этот

макрос не определен.

В конкретных реализациях набор предопределенных имен шире. Например, в

препроцессор BC++ дополнительно включены (таблица 2):

Таблица 2. Дополнительные встроенные макроимена в BC++

Макрос Назначение

__BCOPT__ Имя, определенное равным 1, если в компиляторе имеется оптимизатор.

__BCPLUSPLUS__ Числовое значение соответствует версии компилятора.

__CDECL__

Идентифицирует порядок передачи параметров функциям, значение 1 соответствует

порядку, принятому в языках C и C++ (в отличие от языка Pascal).

__CONSOLE__

Определено для 32-разрядного компилятора и установлено в 1 для программ консольного

приложения.

__DLL__ Соответствует работе в режиме Windows DLL.

__MSDOS__

Равно 1 для 16-разрядных компиляторов BC++, устанавливается в 0 для 32-разрядного

компилятора.

__MT__ Доступен только для 32-разрядного компилятора.

__OVERLAY__ Равно 1 в оверлейном режиме.

__PASCAL__ Противоположен __CDECL__.

__STDC__ Установлен в 1, если компилятор удовлетворяет стандарту ANSI.

__TCPLUSPLUS__ Числовое значение соответствует версии компилятора.

__TEMPLATES__ Означает, что ВС++ поддерживает шаблоны.

__TLS__ Определен как истинный для 32-разрядного компилятора.

__TURBOC__ Числовое значение, равное 0х0400 для компилятора ВС++4.0.

__Windows__ Означает генерацию кода для Windows.

__WIN32__

Определен для 32-разрядного компилятора и установлен в 1 для консольных приложений

и GUI.

31) Тэги Используется для объявления перечислений, структур и объединений. Тег не является

самостоятельным именем типа (в С++ может быть)

. Тег структуры определяется следующим образом:

struct тег { список описаний; };

где тег является идентификатором.

В приведенном ниже примере идентификатор student описывается как тег структуры:

struct student { char name[25];

int id, age;

char prp; };

Тег структуры используется для последующего объявления структур данного вида в форме:

struct тег список-идентификаторов;

Пример:

struct studeut st1,st2;

Использование тегов структуры необходимо для описания рекурсивных структур. Ниже рассматривается

использование рекурсивных тегов структуры.

struct node { int data;

struct node * next; } st1_node;

Тег структуры node действительно является рекурсивным, так как он используется в своем собственном

описании, т.е. в формализации указателя next. Структуры не могут быть прямо рекурсивными, т.е. структура node

не может содержать компоненту, являющуюся структурой node, но любая структура может иметь компоненту,

являющуюся указателем на свой тип, как и сделано в приведенном примере.

Доступ к компонентам структуры осуществляется с помощью указания имени структуры и следующего через

точку имени выделенного компонента, например:

st1.name="Иванов";

st2.id=st1.id;

st1_node.data=st1.age;

32) Перечислимые типы

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

Объявление перечисления начинается с ключевого слова enum и имеет два формата представления.

Формат 1. enum [имя-тега-перечисления] {список-перечисления} описатель[,описатель...];

Формат 2. enum имя-тега-перечисления описатель [,описатель..];

Объявление перечисления задает тип переменной перечисления и определяет список именованных констант, называемый списком-перечисления.

Значением каждого имени списка является некоторое целое число.

Переменная типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int.

Таким образом, память соответствующая переменной перечисления, это память необходимая для размещения значения типа int.

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

В первом формате 1 имена и значения перечисления задаются в списке перечислений. Необязательное имя-тега-перечисления, это идентификатор, который именует тег перечисления, определенный списком перечисления.

Описатель именует переменную перечисления. В объявлении может быть задана более чем одна переменная типа перечисления.

Список-перечисления содержит одну или несколько конструкций вида: идентификатор [= константное выражение]

Каждый идентификатор именует элемент перечисления. Все идентификаторы в списке enum должны быть уникальными. В случае отсутствия константного выражения первому идентификатору соответствует значение 0, следующему идентификатору - значение 1 и т.д. Имя константы перечисления эквивалентно ее значению.

Идентификатор, связанный с константным выражением, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип int и может быть как положительным, так и отрицательным.

Следующему идентификатору в списке присваивается значение, равное константному выражению плюс 1, если этот идентификатор не имеет своего константного выражения. Использование элементов перечисления должно подчиняться следующим правилам:

1. Переменная может содержать повторяющиеся значения.

2. Идентификаторы в списке перечисления должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков перечислений. 3. Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и смесей в этой же области видимости.

4. Значение может следовать за последним элементом списка перечисления.

Пример:

enum week { SUB = 0, /* 0 */ VOS = 0, /* 0 */ POND, /* 1 */ VTOR, /* 2 */ SRED, /* 3 */ HETV, /* 4 */ PJAT /* 5 */ } rab_ned ;

В данном примере объявлен перечислимый тег week, с соответствующим множеством значений, и объявлена переменная rab_ned имеющая тип week.

Во втором формате используется имя тега перечисления для ссылки на тип перечисления, определяемый где-то в другом месте. Имя тега перечисления должно относится к уже определенному тегу перечисления в пределах текущей области видимости. Так как тег перечисления объявлен где-то в другом месте, список перечисления не представлен в объявлении.

Пример: enum week rab1;

В объявлении указателя на тип данных перечисления и объявляемых typedef для типов перечисления можно использовать имя тега перечисления до того, как данный тег перечисления определен. Однако определение перечисления должно предшествовать любому действию используемого указателя на тип объявления typedef. Объявление без последующего списка описателей описывает тег, или, если так можно сказать, шаблон перечисления.

33) Структуры

За одной переменной скрывается несколько переменных разных типов.

Struct person{

Int age;

Char name[20];}

Под переменные структурированмного типа выделяется в памяти , не меньше чем необходимо для

размещения всех переменных.

Допустимые операции.

1)sizeof;

2)&-получение адреса

3)присваивание для одинакового типа

4).-доступ к полю структуры.

x.y //где х-имя переменной у-имя поля структуры.

Структура - это множество, состоящее из одного или более объектов, возможно

имеющих различные типы, объединенных под одним именем. Тип данных struct - один из основных строительных блоков данных в языке. Он

предоставляет удобный способ объединения различных элементов, связанных между

собой.

Описание структуры начинается со служебного слова struct, за которым может

следовать необязательное имя, называемое именем типа структуры (здесь это date),

которое еще называется именем шаблона. Такое имя типа структуры может

использоваться в дальнейшем как сокращенная запись подробного описания однотипных

структур.

За именем типа структуры идет заключенный в фигурные скобки список элементов

структуры, с описанием типа каждого элемента (элементом структуры может быть

переменная, массив, структура или объединение). Элементы структуры отделяются друг

от друга точкой с запятой. Например:

struct date

{

int day;

int month;

int year;

int yearday;

char mon_name[5];

};

За правой фигурной скобкой, закрывающей список элементов, может следовать список

объектов. Например, операторstruct date {...} x,y,z; определяет переменные x,y,z в

качестве структур описанного типа и приводит к выделению памяти.

Изобразим распределение памяти для структуры x типа date:

Рис.1. Распределение памяти для структуры

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

Вследствие выравнивания объектов разной длины в структуре могут появляться

безымянные "дыры". Так, например, если переменная типа char занимает один байт,

а int - четыре байта, то для структуры:

struct

{

char c;

int i;

} может потребоваться восемь байт, а не пять. Правильное значение возвращает

операция sizeof.

Описание структуры, за которым не следует список объектов, не приводит к

выделению памяти (как в программе выше); оно только определяет шаблон (форму)

структуры. Однако, если такое описание снабжено именем типа (например, date), то это

имя типа может быть использовано позднее при определении фактических экземпляров

структур (определение структур d и f в программе).

Внешнюю или статическую структуру можно инициализировать, поместив вслед за ее

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

скобки. В программе таким образом инициализированы структуры d и f (они являются

внешними для функции main).

date d = { 0,0,1776,186,"июл" };

date f = { 1,9,1986,0,"сент" }; .

Автоматические структуры инициализации не подлежат!

Элемент структуры может быть указан в выражении с помощью конструкции вида:

<имя структуры>.<имя элемента>.

Структуры могут вкладываться одна в другую, но самовложение структур

запрещено!

34)

35)

36)

37)

38) Для осуществления операций с файлами предусмотрено три класса: ifstream, ofstream и fstream. Эти классы являются производными, соответственно, от классов istream, ostream и iostream. Поскольку эти последние классы, в свою очередь, являются производными от класса ios, классы файловых потоков наследуют все функциональные возможности своих родителей (перегруженные операции << и >> для встроенных типов, функции и флаги форматирования, манипуляторы и пр.). Для реализации файлового ввода-вывода нужно включить в программу заголовочный файл fstream.h.

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

Для создания файлового потока эти классы предусматривают следующие формы конструктора:

создать поток, не связывая его с файлом:

ifstream();      ofstream();      fstream();

создать поток, открыть файл и связать поток с файлом:

ifstream(const char *name, ios::openmode mode = ios::in) ;      ofstream(const char* name, ios::openmode mode=ios::out | ios::trunc);      fstream(const char * name, ios::openmode mode = ios::in | ios::out);

Чтобы открыть файл для ввода или вывода, можно использовать вторую форму нужного конструктора

fstream fs("FileName.dat");

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

void ifstream::open(const char *name, ios::openmode mode = ios::in);      void ofstream::open      (const char * name, ios::openmode mode = ios::out | ios::trunc);      void fstream::open      (const char * name, ios::openmode mode = ios::in | ios::out);

Здесь name - имя файла, mode - режим открытия файла. Параметр mode является перечислением и может принимать значения, указанные в табл. 8.

Таблица 8

Режимы открытия и их назначение

Режим открытия

Назначение

ios::in

Открыть файл для чтения

ios::out

Открыть файл для записи

ios::ate

Начало вывода устанавливается в конец файла

ios::app

Открыть файл для добавления в конец

ios::trunc

Усечь файл, то есть удалить его содержимое

ios::binary

Двоичный режим операций

Режимы открытия файла представляют собой битовые маски, поэтому можно задавать два или более режима, объединяя их побитовой операцией ИЛИ. В следующем фрагменте кода файл открывается для вывода с помощью функции open():

ofstream ofs;      ofs.open("FileName.dat");

Обратим внимание, что по умолчанию режим открытия файла соответствует типу файлового потока. У потока ввода или вывода флаг режима всегда установлен неявно. Например, для потока вывода в режиме добавления файла можно вместо оператора

ofstream ofs("FName.txt", ios::out | ios::app); написать      ofstream ofs("FName.txt", ios::app);

Между режимами открытия файла ios::ate и ios::app имеется небольшая разница.

Если файл открывается в режиме добавления, весь вывод в файл будет осуществляться в позицию, начинающуюся с текущего конца файла, безотносительно к операциям позиционирования в файле. В режиме открытия ios::ate (от английского "at end") можно изменить позицию вывода в файл и осуществлять запись, начиная с нее. Для потоков вывода режим открытия эквивалентен ios::out | ios::trunc, то есть можно опустить режим усечения файла. Однако для потоков ввода-вывода его нужно указывать явно. Файлы, которые открываются для вывода, создаются, если они еще не существуют.

Если открытие файла завершилось неудачей, объект, соответствующий потоку, будет возвращать 0:

if (!ofs){ cout << "Файл не открыт\n";}

Проверить успешность открытия файла можно также с помощью функции-члена is_open(), имеющей следующий прототип:

int is_open() const;

Функция возвращает 1, если поток удалось связать с открытым файлом. Например,

if (!ofs.is_open()){ cout << "Файл не открыт\n"; return; }

Если при открытии файла не указан режим ios::binary, файл открывается в текстовом режиме и после того, как файл успешно открыт, для выполнения операций ввода-вывода можно использовать операторы извлечения и вставки в поток. Для проверки, достигнут ли конец файла, можно использовать функцию ios::eof(), имеющую прототип int eof();

Завершив операции ввода-вывода, необходимо закрыть файл, вызвав функцию-член close() с прототипом void close():

ofs.close();

Закрытие файла происходит автоматически при выходе потокового объекта из области существования, когда вызывается деструктор потока.

39)

40)

41)

42) В центре ООП находится понятие объекта. Объект — это сущность, которой можно посылать сообщения, и которая может на них реагировать, используя свои данные. Данные объекта скрыты от остальной программы. Сокрытие данных называется инкапсуляцией.

Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности — для этого требуется наличие наследования.

Но даже наличие инкапсуляции и наследования не делает язык программирования в полной мере объектным с точки зрения ООП. Основные преимущества ООП проявляются только в том случае, когда в языке программирования реализован полиморфизм; то есть возможность объектов с одинаковой спецификацией иметь различную реализацию.

Язык Self, соблюдая многие исходные положения объектно-ориентированного программирования, ввёл альтернативное классам понятие прототипа, положив начало прототипному программированию, считающемуся подвидом объектного.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]