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

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) << " символов"; }

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

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)

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)

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

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; }

27)

28)

29)

30)

31)

32)

33)

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, соблюдая многие исходные положения объектно-ориентированного программирования, ввёл альтернативное классам понятие прототипа, положив начало прототипному программированию, считающемуся подвидом объектного.

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