Скачать презентацию Язык программирования Cи Язык программирования Си Стандартизованный Скачать презентацию Язык программирования Cи Язык программирования Си Стандартизованный

1. Синтаксис языка C++.pptx

  • Количество слайдов: 103

Язык программирования Cи++ Язык программирования Cи++

Язык программирования Си Стандартизованный процедурный язык программирования Разработан в начале 70 -х годов для Язык программирования Си Стандартизованный процедурный язык программирования Разработан в начале 70 -х годов для использования в UNIX Портирован на многие ОС Стал одним из самых широко используемых языков программирования для системного и прикладного программирования

Особенности Минимализм однопроходная компиляция компактный машинный код минимальная привязка к runtime-библиотеке относительно низкий уровень Особенности Минимализм однопроходная компиляция компактный машинный код минимальная привязка к runtime-библиотеке относительно низкий уровень языка простота разработки компилятора

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

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

Язык С++ (Си++) Компилируемый статически типизированный язык программирования общего назначения Является продолжателем языка программирования Язык С++ (Си++) Компилируемый статически типизированный язык программирования общего назначения Является продолжателем языка программирования Си Многие программы языка Си исправно работают и с компилятором Си++ Поддержка объектно-ориентированного и обобщенного программирования

Программа Hello World #include <stdio. h> int main(int argc, char * argv[]) { printf( Программа Hello World #include int main(int argc, char * argv[]) { printf("Hello, World!n"); return 0; }

Комментарии в языке Си++ #include заключённый в служебные символы /* и Текст, <stdio. h> Комментарии в языке Си++ #include заключённый в служебные символы /* и Текст, */ в этом порядке, полностью игнорируется /* Это простейшая компилятором. программа на языке Си, которая выводит фразу “Hello World” на устройство стандартного вывода */ Компиляторы, совместимые со стандартом int main() C 99, также позволяют использовать { // Выводим строку Hello World комментарии, начинающиеся с символов // и printf(“Hello World!n”); заканчивающиеся переводом строки return 0; }

Числовые константы Десятичные 12345, -34021 999999 L, 99983 UL Шестнадцатеричные 0 x. Feed. Beef, Числовые константы Десятичные 12345, -34021 999999 L, 99983 UL Шестнадцатеричные 0 x. Feed. Beef, 0 x 328 aadb Восьмеричные 003, 0723 Вещественные 1. 35, 8. 45 f 2 e+10 f, -3. 835 e-6 L

Логические константы Логическая константа true служит для обозначения логического значения «Истина» , а константа Логические константы Логическая константа true служит для обозначения логического значения «Истина» , а константа false – значения «Ложь»

Символьные константы Записывается в виде символа, обрамленного одиночными кавычками ‘A’, ‘ 1’ Значение символьной Символьные константы Записывается в виде символа, обрамленного одиночными кавычками ‘A’, ‘ 1’ Значение символьной константы – числовой код символа из набора символов на данной машине Некоторые символы записываются в виде escape-последовательностей, начинающихся с символа ‘’’, ‘’, ‘n’, ‘177’, ‘xff’

Строковые константы (строковые литералы) Нуль или более символов, заключенных в двойные кавычки “Hello, worldn” Строковые константы (строковые литералы) Нуль или более символов, заключенных в двойные кавычки “Hello, worldn” “” “worldn” эквивалентно “Hello worldn” “Hello ” Во внутреннем представлении строковая константа – массив символов, завершающихся нулевым символом ‘’

Типы данных языка Си++ Целые числа различных размеров со знаком или без int, short, Типы данных языка Си++ Целые числа различных размеров со знаком или без int, short, char Числа с плавающей запятой различной размерности float, double, long double Логический тип bool Перечисляемые типы (enum) Структуры (struct) Объединения (union) Массивы

Базовые типы данных Типы данных целых чисел char int квалификаторы short/long unsigned/signed Логический тип Базовые типы данных Типы данных целых чисел char int квалификаторы short/long unsigned/signed Логический тип bool Типы данных вещественных чисел float double

Пример - функция strlen /* strlen: возвращает длину строки s */ int strlen(char s[]) Пример - функция strlen /* strlen: возвращает длину строки s */ int strlen(char s[]) { int i = 0; while (s[i] != '') ++i; return i; }

Константы перечисления Задают список целых констант enum Week. Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Константы перечисления Задают список целых констант enum Week. Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}; Особенности Имена в различных перечислениях должны отличаться друг от друга Значения внутри одного перечисления могут совпадать: enum Status {Ok, Failure, Success = Ok}

Объявления переменных Переменные объявляются раньше их использоваться int lower, upper, step; char c, line[1000]; Объявления переменных Переменные объявляются раньше их использоваться int lower, upper, step; char c, line[1000]; bool success; При объявлении переменные могут быть инициализированы char esc = '\'; int i = 0; int limit = MAXLINE+1; float eps = 1. 0 e-5 f; bool success = true; Квалификатор const указывает, что значение переменной не будет далее изменяться const double e = 2. 7182845905; const char msg[] = "предупреждение: "; int strlen(const char str[]);

Ключевое слово typedef Язык Си++ предоставляет оператор typedef, позволяющий давать типам данных новые имена Ключевое слово typedef Язык Си++ предоставляет оператор typedef, позволяющий давать типам данных новые имена После этого новое имя типа может использоваться в качестве синонима оригинала Причины использования typedef Решение проблемы переносимости Желание сделать текст программы более ясным

Пример использования оператора typedef int Length; Length len, maxlen; len = 1; typedef int Пример использования оператора typedef int Length; Length len, maxlen; len = 1; typedef int 32; typedef short int 16; typedef char int 8; int 32 counter = 0;

Целочисленные типы данных Служат для хранения целых чисел различного размера char short int long Целочисленные типы данных Служат для хранения целых чисел различного размера char short int long Целые числа могут быть как со знаком, так и без него signed unsigned Гарантируется следующее соотношение размеров целочисленных типов: sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)

Примеры объявления целочисленных переменных char a = ‘A’; unsigned char b = 150; signed Примеры объявления целочисленных переменных char a = ‘A’; unsigned char b = 150; signed char c = -15; short d = 10000; unsigned short e = 49320; signed short f = -25000; int g = -1000 * 1000; unsigned int h = 0 xffff; signed int i = -99999; long j = -123456789; unsigned long k = 0 x 9 c 9 d 9 e 9 f; signed long k = j;

Типы данных с плавающей запятой Позволяют задавать вещественные числа различного размера и точности float Типы данных с плавающей запятой Позволяют задавать вещественные числа различного размера и точности float double long double Гарантированы следующие соотношения размеров вещественных типов данных sizeof(float) <= sizeof(double) <= sizeof (long double)

Пример использования вещественных чисел const float PI = 3. 1415927 f; double sin 60 Пример использования вещественных чисел const float PI = 3. 1415927 f; double sin 60 = 0. 86602540378443864676372317075294; double Fahrengeit. To. Celsius(double fahr) { return (fahr – 32) * 5. 0 / 9. 0; } float Degrees. To. Radian(float degrees) { return degrees * PI / 180. 0 f; }

Перечисляемые типы данных (перечисления) Позволяет задать ограниченный набор именованных целочисленных значений День недели Состояние Перечисляемые типы данных (перечисления) Позволяет задать ограниченный набор именованных целочисленных значений День недели Состояние конечного автомата Тип файла Модель компьютера и т. д

Пример использования перечислимых типов #include <stdio. h> typedef enum tag. Week. Day { SUNDAY Пример использования перечислимых типов #include typedef enum tag. Week. Day { SUNDAY = 0, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, }Week. Day; int main() { Week. Day today = SUNDAY; printf("Today is %dn", today); today++; printf("Tomorrow will be %dn", today); return 0; } Today is 0 Tomorrow will be 1

Пример использования логического типа данных double Calculate. Circle. Radius(double area) { bool argument. Is. Пример использования логического типа данных double Calculate. Circle. Radius(double area) { bool argument. Is. Valid = (area >= 0); if (argument. Is. Valid) { return sqrt(area / 3. 14159265); } else { return -1; } }

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

Пример использования структур typedef struct tag. Point { int x; int y; }Point; typedef Пример использования структур typedef struct tag. Point { int x; int y; }Point; typedef struct tag. Rectangle { Point left. Top; Point right. Bottom; }Rectangle; int main() { Point p 0 = {0, 3}; Point p 1 = {30, 20}; Rectangle r 1 = {{1, 1}, {20, 30}}; Rectangle r 2; r 2. left. Top = p 0; r 2. right. Bottom = r 1. right. Bottom; return 0; }

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

#include <stdio. h> typedef enum tag. Numeric. Type { TYPE_INTEGER, TYPE_REAL, }Numeric. Type; n #include typedef enum tag. Numeric. Type { TYPE_INTEGER, TYPE_REAL, }Numeric. Type; n = 5 n = 3. 80000 typedef struct tag. Numeric { Numeric. Type type; union { int. Value; double real. Value; }value; }Numeric; void Print. Numeric(Numeric n) { if (n. type == TYPE_INTEGER) printf("n = %dn", n. value. int. Value); else printf("n = %fn", n. value. real. Value); } int main() { Numeric a, b; a. type = TYPE_INTEGER; b. type = TYPE_REAL; Print. Numeric(a); Print. Numeric(b); return 0; } a. value. int. Value = 5; b. value. real. Value = 3. 8;

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

#include <stdio. h> int main() { int student. Ratings[3] = {5, 4, 4}; char #include int main() { int student. Ratings[3] = {5, 4, 4}; char student 0[] = "Bill"; char student 1[] = {'J', 'o', 'h', 'n', ''}; char student 2[6] = "Peter"; printf("Students' marks: n"); printf("1. %s - %dn", student 0, student. Ratings[0]); printf("2. %s - %dn", student 1, student. Ratings[1]); printf("3. %s - %dn", student 2, student. Ratings[2]); return 0; } Students' marks: 1. Bill - 5 2. John - 4 3. Peter - 4

Указатели Указатель – используются для хранения адресов переменных в памяти Основные области применения Работа Указатели Указатель – используются для хранения адресов переменных в памяти Основные области применения Работа с динамической памятью Работа с массивами Передача параметров в функцию по ссылке Организация связанных структур данных (списки, деревья)

#include <stdio. h> typedef struct tag. Point { int x, y; }Point; void Print. #include typedef struct tag. Point { int x, y; }Point; void Print. Point(Point *p. Point) { printf("point is (%d, %d)n", p. Point->x, (*p. Point). y); } void Swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int value = 0; int one = 1, two = 2; int *p. Value = &value; Point pnt = {10, 20}; printf("value is %dn", value); *p. Value = 1; printf("now value is %dnn", value); printf("one=%d, two=%dn", one, two); Swap(&one, &two); printf("now one=%d, two=%dnn", one, two); Print. Point(&pnt); return 0; } value is 0 now value is 1 one=1, two=2 now one=2, two=1 point is (10, 20)

Хранение данных В Си++ есть три разных способа выделения памяти для объектов Статическое: пространство Хранение данных В Си++ есть три разных способа выделения памяти для объектов Статическое: пространство для объектов создаётся в области хранения данных кода программы в момент компиляции; Автоматическое: объекты можно временно хранить в стеке; эта память затем автоматически освобождается и может быть использована снова, после того, как программа выходит из блока, использующего её. Динамическое: блоки памяти нужного размера могут запрашиваться во время выполнения программы с помощью библиотечных функций malloc, realloc и free из области памяти, называемой кучей. Эти блоки освобождаются и могут быть использованы снова после вызова для них функции free. В языке С++ следует использовать операторы new и delete для памяти и освобождения памяти

Набор используемых символов Используются почти все графические символы ASCII таблицы Язык является чувствительным к Набор используемых символов Используются почти все графические символы ASCII таблицы Язык является чувствительным к регистру символов Для записи операторов используются строчные буквы Для записи идентификаторов – цифры, заглавные и строчные буквы и символ подчеркивания

Основные операторы языка Си Общие Арифметические операторы и оператор присвания Логические операторы и операторы Основные операторы языка Си Общие Арифметические операторы и оператор присвания Логические операторы и операторы сравнения Оператор sizeof Управление ходом выполнения программы Условные операторы Операторы циклов Оператор множественного выбора Операторы для работы с массивами, структурами и объединениями Операторы для работы с указателями

Арифметические операторы Бинарные + * / % (остаток от деления – применяется только к Арифметические операторы Бинарные + * / % (остаток от деления – применяется только к целым) int i = 10 % 3; /* i = 1; */ Деление целых сопровождается отбрасыванием дробной части float f = 8 / 3; /* f = 2. 0 */ Унарные (ставятся перед операндом) + int i = +1; int j = -8;

Пример if ( ((year % 4 == 0) && (year % 100 != 0)) Пример if ( ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0) ) printf("%d високосный годn", year); else printf("%d невисокосный годn", year);

Операторы отношения > >= < <= Операторы сравнения на равенство == != Логические операторы Операторы отношения > >= < <= Операторы сравнения на равенство == != Логические операторы && - логическое И char ch = getchar(); int is. Digit = (ch >= ‘ 0’) && (ch <= ‘ 9’); || - логическое ИЛИ char ch = getchar(); if ((ch == ‘ ‘) || (ch == ‘n’) || (ch == ‘t’)) printf(“Разделитель”); ! – логическое НЕ if (!valid) эквивалентно if (valid == 0) Вычисления операторов && и || прекращаются как только станет известна истинность или ложность результата

Преобразование типов Происходит, когда операнды оператора принадлежат к разным типам Неявное преобразование int i Преобразование типов Происходит, когда операнды оператора принадлежат к разным типам Неявное преобразование int i = 7. 0 + 3 – 2. 0 f; Явное преобразование int i = (int)(7. 0 + 3 – 2. 0 f);

Операторы инкремента и декремента Увеличивают или уменьшают значение операнда на 1 ++ -- Имеют Операторы инкремента и декремента Увеличивают или уменьшают значение операнда на 1 ++ -- Имеют две формы Префиксная форма int i = 0; int j = ++i; /* i = 1; j = 1; */ Постфиксная форма int i = 0; int j = i--; /* i = -1; j = 0; */ Операторы инкремента и декремента можно применять только к переменным int i = (j + y)++; /* ошибка */

Пример – функция squeeze /* squeeze: удаляет все символы c из строки s*/ void Пример – функция squeeze /* squeeze: удаляет все символы c из строки s*/ void squeeze(char s[], int c) { int i, j; for (i = j = 0; s[i] != ''; i++) { if (s[i] != c) s[j++] = s[i]; } s[j] = ''; }

Побитовые операторы Данные операторы позволяют осуществлять операции над отдельными битами целочисленных операндов & - Побитовые операторы Данные операторы позволяют осуществлять операции над отдельными битами целочисленных операндов & - побитовое И int i = 0 xde & 0 xf 0; /* i = 0 xd 0 */ | - побитовое ИЛИ int i = 0 xf 0 | 0 x 03; /* i = 0 xf 3 */ ^ - побитовое исключающее ИЛИ int i = 0 x 03 ^ 0 x 02; /* i = 0 x 01 */ << - сдвиг влево int i = 1 << 3; /* i = 8 */ >> - сдвиг вправо int i = 0 xd 0 >> 4; /* i = 0 x 0 d */ ~ - побитовое отрицание (унарный оператор). char i = ~0 x 1; /* i = 0 xfe (0 xfe = 11111110 b) */

Пример: функция getbits /* getbits: получает n бит, начиная с p-й позиции */ unsigned Пример: функция getbits /* getbits: получает n бит, начиная с p-й позиции */ unsigned getbits(unsigned x, int p, int n) { return (x >> (p+1 -n)) & ~(~0 << n); } (x >> (9 + 1 – 7)) = ~0 << 7 = ~(~0 << 7) = (x >> (9 + 1 – 7)) & ~(~0 << 7) =

Операторы и выражения присваивания Служат для присваивания переменным значения некоторого выражения i = 3; Операторы и выражения присваивания Служат для присваивания переменным значения некоторого выражения i = 3; i += 8; i <<= 1; j %= 3; Типом и значением выражения присваивания является тип и значение левого операнда после завершения присваивания while ((c = getchar()) != EOF) { } // do something

Пример: функция bitcount /* bitcount: подсчет единиц в x */ int bitcount(unsigned х) { Пример: функция bitcount /* bitcount: подсчет единиц в x */ int bitcount(unsigned х) { int b; for (b = 0; х != 0; x >>= 1) { if (x & 0 x 01) b++; } return b; }

Условное выражение имеет вид: выр1 ? выр2 : выр3 Сначала вычисляется выражение 1 Если Условное выражение имеет вид: выр1 ? выр2 : выр3 Сначала вычисляется выражение 1 Если оно истинно (не равно нулю), то вычисляется выражение 2 и его значение становится значением всего условного выражения В противном случае вычисляется выражение 3 и становится значением всего условного выражения Пример z = (a > b) ? a : b; /* z = max(a, b)*/

Приоритет и очередность выполнения операторов Операторы () ! * + << < == & Приоритет и очередность выполнения операторов Операторы () ! * + << < == & ^ | && || ? : = , [] ~ / >> <= != += Выполняются ->. слева направо ++ -- + * & (type) sizeof справа налево % слева направо > >= слева направо слева направо справа налево -= *= /= %= &= ^= |= <<= >>= справа налево слева направо

Инструкции и блоки Выражение (например, x = 0) становится инструкцией, если в конце поставить Инструкции и блоки Выражение (например, x = 0) становится инструкцией, если в конце поставить точку с запятой x = 0; printf(“Hello”); В Си точка с запятой является заключающим символом инструкции, а не разделителем, как в языке Паскаль. Фигурные скобки { и } используются для объединения объявлений и инструкций в составную инструкцию, или блок с т. з. синтаксиса языка блок воспринимается как одна инструкция

Конструкция if-else Оператор if позволяет выполнить тот или иной участок кода в зависимости от Конструкция if-else Оператор if позволяет выполнить тот или иной участок кода в зависимости от значения некоторого выражения if (<выражение>) <инстр. 1> else <инстр. 2> if (<выражение>) <инстр>

Конструкция else-if Позволяет осуществлять многоступенчатое решение if (выражение) инструкция else инструкция Конструкция else-if Позволяет осуществлять многоступенчатое решение if (выражение) инструкция else инструкция

Пример, бинарный поиск /* binsearch: найти x в v[0] <= v[1] <=. . . Пример, бинарный поиск /* binsearch: найти x в v[0] <= v[1] <=. . . <= v[n-1] */ int binsearch(int x, const int v[], int n) { int low, high, mid; low = 0; high = n - 1; while (low <= high) { mid = (low + high) / 2; if (x < v[mid]) high = mid - 1; else if (x > v[mid]) low = mid + 1; else /* совпадение найдено */ return mid; } return -1; /* совпадения нет */ }

Оператор switch Используется для выбора одного из нескольких путей Осуществляется проверка на совпадение значения Оператор switch Используется для выбора одного из нескольких путей Осуществляется проверка на совпадение значения выражения с одной из некоторого набора целых констант, и выполняет соответствующую ветвь программы switch (выражение) { case конст-выр: инструкции default: инструкции }

#include <stdio. h> int main() /* подсчет цифр, символов-разделителей и прочих символов */ { #include int main() /* подсчет цифр, символов-разделителей и прочих символов */ { int c, i, nwhite, nother, ndigit[10]; nwhite = nother = 0; for (i = 0; i < 10; i++) ndigit[i] = 0; while ((c = getchar()) != EOF) { switch (c) { case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : ndigit[c - '0']++; break; case ' ': case 'n': case 't': nwhite++; break; default: nother++; break; } } printf ("цифр ="); for (i = 0; i < 10; i++) printf (" %d", ndigit[i]); printf(", символов-разделителей = %d, прочих = %dn", return 0; } nwhite, nother);

Циклическое выполнение Циклическое выполнение

Что такое циклическое выполнение Цикл – последовательность из нескольких операторов, указываемая в программе один Что такое циклическое выполнение Цикл – последовательность из нескольких операторов, указываемая в программе один раз, которая выполняется несколько раз подряд Допускается существование бесконечного цикла Тело цикла - последовательность операторов, предназначенная для многократного выполнения в цикле

Циклическое выполнение в языке Си осуществляется при использовании следующих операторов цикла: while for do. Циклическое выполнение в языке Си осуществляется при использовании следующих операторов цикла: while for do. . while Внутри циклов могут использоваться операторы управления работой цикла: break для досрочного выхода из цикла continue для пропуска текущей итерации

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

Примеры #include <stdio. h> int main() { int ch; while ((ch = getchar()) != Примеры #include int main() { int ch; while ((ch = getchar()) != EOF) // пока не конец файла { putchar(ch); } return 0; } #include int main() { while (1) // бесконечный цикл while { putchar(‘#’); } return 0; }

Оператор for служит для организации циклов со счетчиком Синтаксис for (выр1; выр2; выр3) инструкция Оператор for служит для организации циклов со счетчиком Синтаксис for (выр1; выр2; выр3) инструкция Выражение 1 выполняется один раз перед началом цикла Например, оператор инициализации счетчика цикла Выполнение инструкции (тело цикла) продолжается до тех пор, пока выражение 2 имеет ненулевое значение если выражение 2 отсутствует, то выполнение цикла продолжается бесконечно После каждой итерации цикла выполняется выражение 3 Например, изменение счетчика цикла

Пример #include <stdio. h> int main() { int i; // цикл от 0 до Пример #include int main() { int i; // цикл от 0 до 10 включительно с шагом 1 for (i = 0; i <= 10; ++i) { printf("%d^2 = %dn", i, i*i); } return 0; }

Оператор do-while служит для организации циклов с постусловием цикл, в котором условие проверяется после Оператор do-while служит для организации циклов с постусловием цикл, в котором условие проверяется после выполнения тела цикла тело всегда выполняется хотя бы один раз Синтаксис do инструкция while (выражение); Инструкция выполняется до тех пор, пока выражение принимает ненулевое значение

#include <stdio. h> void Print. Integer(int n) { char buffer[20]; int sign, i = #include void Print. Integer(int n) { char buffer[20]; int sign, i = 0; if ((sign = n) < 0) n = -n; do { // записываем в буфер десятичные разряды числа, начиная с самого правого buffer[i++] = (char)((n % 10) + ‘ 0’); } while((n /= 10) != 0); // пока число не обнулится if (sign < 0) buffer[i++] = '-'; for (--i; i >= 0; --i) putchar(buffer[i]); } int main() { Print. Integer(12345); putchar('n'); Print. Integer(-12345); putchar('n'); Print. Integer(0); putchar('n'); return 0; }

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

#include <stdio. h> void Print. Array(int v[], int n) { int i; printf( #include void Print. Array(int v[], int n) { int i; printf("{"); for (i = 0; i < n; ++i) printf((i != n - 1) ? "%d, " : "%d", v[i]); printf("}n"); } {76, 1, 9, 3, 15, 4, 10, 9, Sorting: {4, 1, 9, 3, 15, 76, 10, 9, {4, 1, 9, 3, 10, 9, 13, 20, {1, 3, 4, 9, 9, 10, 13, 15, void Shell. Sort(int v[], int n) { int gap, i, j, temp, unordered = 1; for (gap = n/2; (gap > 0) && unordered; gap /= 2) { for (unordered =0, i = gap; i < n; i++) for (j = i- gap; (j >= 0) && (v[j] > v[j+gap]); j -= gap) { unordered = 1; temp = v[j]; v[j] = v[j + gap]; v[j + gap] = temp; } Print. Array(v, n); } } int main() { int array[] = {76, 1, 9, 3, 15, 4, 10, 9, 13, 20}; const int ARRAY_LENGTH = sizeof(array) / sizeof(array[0]); Print. Array(array, ARRAY_LENGTH); printf("Sorting: n"); Shell. Sort(array, ARRAY_LENGTH); return 0; } 13, 20} 15, 76} 20, 76}

Инструкции break и continue Инструкция break осуществляет немедленный выход из тела цикла, внутри которого Инструкции break и continue Инструкция break осуществляет немедленный выход из тела цикла, внутри которого она находится Также инструкция break осуществляет выход из оператора switch Инструкция continue осуществляет пропуск оставшихся операторов тела цикла, внутри которого она находится, и переход на следующую итерацию цикла В циклах while и do-while осуществляется переход к проверке условия В цикле for осуществляется переход к приращению переменной цикла

#include <stdio. h> #include <string. h> /* trim: удаляет завершающие пробелы, табуляции и новые #include #include /* trim: удаляет завершающие пробелы, табуляции и новые строки */ int trim(char s[]) { int n; for (n = strlen(s) - 1; n >= 0; --n) { if ((s[n] != ' ') && (s[n] != 't') && (s[n] != 'n')) break; // выходим из цикла, встретив печатаемый символ } s[n+1] = ''; Before trim: "Hello return n; " } After trim: "Hello" int main() { char str[] = "Hello tn"; printf("Before trim: "%s"n", str); trim(str); printf("After trim: "%s"n", str); return 0; }

#include <stdio. h> 1 9 15 10 9 13 20 void Print. Positives(int v[], #include 1 9 15 10 9 13 20 void Print. Positives(int v[], int n) { int i; for (i = 0; i < n; i++) { if (v[i] < 0) /* пропуск отрицательных элементов */ continue; printf("%d ", v[i]); } } int main() { int array[] = {-76, 1, 9, -3, 15, -4, 10, 9, 13, 20}; const int ARRAY_LENGTH = sizeof(array) / sizeof(array[0]); Print. Positives(array, ARRAY_LENGTH); return 0; }

Инструкция goto позволяет осуществить переход на заданную метку внутри текущей функции Синтаксис: goto метка; Инструкция goto позволяет осуществить переход на заданную метку внутри текущей функции Синтаксис: goto метка; Как правило, использование инструкции goto усложняет структуру программы и без крайней необходимости ею пользоваться не стоит Если Вы все еще думаете об использовании этого оператора – использовать его все равно не стоит

Пример /* поиск совпадающих элементов в массивах */ for (i = 0; i < Пример /* поиск совпадающих элементов в массивах */ for (i = 0; i < n; ++i) { for (j = 0; j < m; ++j) { if (a[i] == b[i]) goto found; } } /* нет одинаковых элементов */. . . found: /* обнаружено совпадение: a[i] == b[i] */. . .

Указатели Указатели

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

Пример. . . e 8 03 00 00 int i = 1000; . . Пример. . . e 8 03 00 00 int i = 1000; . . . 0 f char a = 15; . . .

Что такое указатель? Указатель – это переменная, которая может хранить адрес другой переменной в Что такое указатель? Указатель – это переменная, которая может хранить адрес другой переменной в памяти заданного типа Указатели – мощное средство языка Си, позволяющее эффективно решать различные задачи Использование указателей открывает доступ к памяти машины, поэтому пользоваться ими следует аккуратно

Объявление указателя Указатель на переменную определенного типа объявляется следующим образом: <тип> *<идентификатор>; Например: int Объявление указателя Указатель на переменную определенного типа объявляется следующим образом: <тип> *<идентификатор>; Например: int *pointer. To. Int; Указатель, способный хранить адрес переменной любого типа имеет тип void*: void * pointer. To. Any. Type; Как и к обычным переменным, к указателям можно применять модификатор const: const int * pointer. To. Const. Int; char * const. Pointer. To. Char = &ch; const double * const. Pointer. To. Const. Double = &x; float * const. Pointer. To. Float = &y; const void * pointer. To. Const. Data;

Получение адреса переменной Для взятия адреса переменной в памяти служит унарный оператор & Этот Получение адреса переменной Для взятия адреса переменной в памяти служит унарный оператор & Этот оператор возвращает адрес переменной, который может быть присвоен указателю совместимого типа Оператор взятия адреса применим только к переменным. Его нельзя применять к константам, выражениям или регистровым переменным

Оператор косвенного доступа Для доступа к значению, на которое ссылается указатель, необходимо его разыменование Оператор косвенного доступа Для доступа к значению, на которое ссылается указатель, необходимо его разыменование (dereferencing), осуществляемое при помощи унарного оператора * int * p = &i; *p = 5;

Пример. . . p char c = ‘A’; char *p = &c; *p = Пример. . . p char c = ‘A’; char *p = &c; *p = ‘B’; ‘B’ ‘A’ c . . .

Инициализация указателей Значение неинициализированного указателя не определено Разыменование такого указателя приводит к неопределенному поведению Инициализация указателей Значение неинициализированного указателя не определено Разыменование такого указателя приводит к неопределенному поведению Лучше присвоить указателю нулевое значение (или символическую константу NULL), чтобы подчеркнуть, что он не ссылается ни на какую переменную: char * p 1 = 0; char * p 2 = NULL; Разыменование нулевого указателя также приводит к неопределенному поведению, однако появляется возможность проверки значения указателя: if (p != NULL) // или просто if (p)

Копирование указателей Как и в случае обычных переменных, значение одного указателя может быть присвоено Копирование указателей Как и в случае обычных переменных, значение одного указателя может быть присвоено другому при помощи оператора = Следует помнить, что в этому случае копируется адрес переменной, а не ее значение Для копирования значения переменной, на которую ссылается указатель, необходимо применить оператор разыменования * char a = ‘A’; char b = ‘B’; char c = ‘C’; char *pa = &a; char *pb = &b; char *pc = &c; pa = pb; // pa и pb теперь хранят адрес b *pa = *pc; // b теперь хранит значение ‘C’

Указатели и аргументы функций В языке Си параметры в функцию передаются по значению. Указатели Указатели и аргументы функций В языке Си параметры в функцию передаются по значению. Указатели – единственный способ изменить значение параметра изнутри функции В языке Си++ появилась возможность передачи параметров по ссылке void swap(int *pa, int *pb) { int tmp = *pa; *pa = *pb; *pb = tmp; } void swap(int &pa, int &pb) { int tmp = pa; pa = pb; pb = tmp; }

Указатели на функции В Си можно объявить указатель на функцию и работать с ним Указатели на функции В Си можно объявить указатель на функцию и работать с ним как с обычной переменной, сохраняя возможность вызова функции по указателю на нее Данная возможность позволяет иметь несколько реализаций алгоритма, имеющих общий интерфейс

#include <stdio. h> typedef int (*Ordered. Function)(int a, int b); void Bubble. Sort(int array[], #include typedef int (*Ordered. Function)(int a, int b); void Bubble. Sort(int array[], int size, Ordered. Function fn) { int sorted, i; do { sorted = 1; for (i = 0; i < size - 1; ++i) { if (!fn(array[i], array[i + 1])) { int tmp = array[i]; array[i] = array[i + 1]; array[i + 1] = tmp; sorted = 0; } } --size; } while(!sorted && (size > 1)); } int Is. Ordered(int a, int b) { return a <= b; } int main() { int arr[5] = {3, 5, 1, 7, 9}; Bubble. Sort(arr, 5, Is. Ordered); return 0; }

Массивы в Си и Си++ Массивы позволяют объявить несколько (один и более) последовательных объектов, Массивы в Си и Си++ Массивы позволяют объявить несколько (один и более) последовательных объектов, объединенных под одним именем, и осуществлять к ним индексированный доступ В качестве индексов используются целые числа, или типы, приводимые к целым Размер массива задается статически на этапе компиляции и не может быть изменен в ходе работы программы Индекс начального элемента массива равен нулю Есть возможность объявления многомерных массивов

// неинициализированный массив из 10 элементов с индексами от 0 до int a[10]; a[0] // неинициализированный массив из 10 элементов с индексами от 0 до int a[10]; a[0] = 5; // присвоить начальному элементу массива значение 5 a[9] = 10; // присвоить конечному элементу массива значение 10 a[10] = 0; // ошибка, индекс должен быть от 0 до 9 // объявляем и инициализируем массив из 3 элементов, int b[3] = {1, 2, 3}; // объявляем и инициализируем массив из 4 элементов int c[] = {100, 200, 300, 400}; // двумерный массив из 4 строк и 7 столбцов int matrix[4][7]; matrix[0][5] = 11; // доступ к 0 строке и 5 столбцу // заполнение элементов массива заданным значениемж void Fill. Array(int arr[], int size, int init) { int i; for (i = 0; i < size; ++i) arr[i] = init; }

Указатели и массивы в Си тесно связаны Имя массива является синонимом расположения его начального Указатели и массивы в Си тесно связаны Имя массива является синонимом расположения его начального элемента int arr[10]; int *p = arr; // эквивалентно int *p = &arr[0]; Индексация элементов массива возможна с помощью указателей и адресной арифметики

Адресная арифметика Если p – указатель на некоторый элемент массива, то p+1 – указатель Адресная арифметика Если p – указатель на некоторый элемент массива, то p+1 – указатель на следующий элемент p-1 – указатель на предыдущий элемент p+j – указатель на j-й элемент после p p[j] разыменовывает j-й элемент относительно p Если p и q – указатели на некоторые элементы одного массива, то p–q - равно количеству элементов после q, которое необходимо добавить, чтобы получить p p

Примеры int arr[10]; // получаем указатель на начальный элемент массива int *p = arr; Примеры int arr[10]; // получаем указатель на начальный элемент массива int *p = arr; // эквивалентно int *p = &arr[0]; // следующие две строки эквивалентны *(p + 4) = 5; arr[4] = 5; /* несмотря на то, что в массиве всего 10 элементов, допускается получать указатель на ячейку, следующую за последним элементом массива */ p = &a[10]; *(p – 1) = 3; // эквивалентно arr[9] = 3;

Указатели на char Строковые константы в Си – массивы символов с завершающим нулем Передача Указатели на char Строковые константы в Си – массивы символов с завершающим нулем Передача строковой константы в функцию (напр. printf) осуществляется путем передачи указателя на ее начальный элемент Присваивание символьных указателей, не копирует строки char * p = “Hello”; char * p 1 = p; // p и p 1 указывают на одно и то же место в памяти Символьный массив и символьный указатель – различные понятия char msg[] = “Hello”; // массив Символы внутри массива могут изменяться msg всегда указывает на одно и то же место в памяти char *pmsg = “Hello”; // указатель Попытка изменить символы через pmsg приведет к неопределенному поведению pmsg – указатель, можно присвоить ему другое значение в ходе работы программы

Массивы указателей Указатели, как и другие переменные можно группировать в массивы int main(int argc, Массивы указателей Указатели, как и другие переменные можно группировать в массивы int main(int argc, char* argv[]) const char * a[] = {“Hello”, “World!”}; printf(“%s %sn”, a[0], a[1]); a[0] = “Goodbye”; Массивы указателей могут использоваться как альтернатива двумерных массивов

#include <stdio. h> #include <string. h> /* swap: поменять местами v[i] и v[j] */ #include #include /* swap: поменять местами v[i] и v[j] */ void swap(const char *v[], int i, int j) { const char *temp = v[i]; v[i] = v[j]; } v[j] = temp; /* qsort: сортирует v[left]. . . v[right] по возрастанию */ void qsort(const char *v[], int left, int right) { int i, last; if (left >= right) /* ничего не делается, если в массиве */ return; /* менее двух элементов */ swap(v, left, (left+right)/2); last = left; for(i = left + 1; i <= right; i++) { if (strcmp(v[i], v[left]) < 0) swap(v, ++last, i); } swap(v, left, last); qsort(v, left, last - 1); qsort(v, last + 1, right); } int main() { int i; const char * strings[] = {"this", "a", "test"}; qsort(strings, 0, 3); for (i = 0; i < 4; ++i) printf("%sn", strings[i]); return 0; }

Указатели на указатели В Си возможны указатели, ссылающиеся на другие указатели char arr[] = Указатели на указатели В Си возможны указатели, ссылающиеся на другие указатели char arr[] = “Hello”; char *parr = arr; char **pparr = &parr; // pparr – хранит адрес указателя parr (*pparr)[0] = ‘h’; // arr = “hello” pparr[0][1] = ‘E’; // arr = “h. Ello”;

Инкремент и декремент указателя Когда указатель ссылается на определенный элемент массива, имеют смысл операции Инкремент и декремент указателя Когда указатель ссылается на определенный элемент массива, имеют смысл операции инкремента и декремента указателя char str[] = “Hello, world!”; char *p = str; // p указывает на символ H p++; // p указывает на символ e *p = ‘E’; // заменяем символ e на E

#include #include "stdio. h" // возвращаем адрес найденного символа в строке или NULL в случае отсутствия const char* Find. Char(const char str[], char ch) { const char * p = str; while (*p != ‘') { if (*p == ch) return p; ++p; } return NULL; } int main() { const char str[] = "Hello, world!n"; const char *pw = Find. Char(str, 'w'); if (pw != NULL) printf("%s", pw); return 0; } Output: world!

Указатели и динамическая память Часто возможны ситуации, когда размер и количество участков памяти, необходимых Указатели и динамическая память Часто возможны ситуации, когда размер и количество участков памяти, необходимых программе, не известны заранее В этом случае прибегают к использованию динамически распределяемой памяти Приложение может запрашивать блоки памяти необходимого размера из области, называемой кучей (heap) Как только блок памяти становится не нужен, его освобождают, возвращая память в кучу Стандартная библиотека языка Си предоставляет набор функций для работы с динамической памятью для использования этих функций необходимо подключить заголовочный файл malloc. h

Функция malloc (memory allocation) Выделяет непрерывную область памяти в куче заданного размера и возвращает Функция malloc (memory allocation) Выделяет непрерывную область памяти в куче заданного размера и возвращает указатель на начало этой области void* malloc(unsigned size); Указатель, возвращаемый данной функцией, обычно приводят к требуемому типу

Функция calloc Аналогична функции malloc, но дополнительно область памяти нулями void* calloc(unsigned size) Функция calloc Аналогична функции malloc, но дополнительно область памяти нулями void* calloc(unsigned size)

Функция realloc Служит для изменения размера ранее выделенного блока памяти void* realloc(void* memblock, unsigned Функция realloc Служит для изменения размера ранее выделенного блока памяти void* realloc(void* memblock, unsigned size) При изменении размера блока может произойти перенос блока памяти в другое место кучи – используйте возвращенное этой функцией значение адреса блока

Функция free Служит для возвращения блока памяти в кучу void free(void *memblock) В качестве Функция free Служит для возвращения блока памяти в кучу void free(void *memblock) В качестве параметра передается указатель на область памяти, ранее возвращенный одной из функций распределения памяти Обращение к ячейкам памяти блока после вызова free, как и многократный вызов этой функции с одним и тем же параметром, приведет к неопределенному поведению Необходимо освобождать блоки динамической памяти, которые стали ненужными. Пренебрежение этим правилом приводит к утечкам памяти

Функции memcpy, memset и memmove Функция memcpy осуществляет копирование блока памяти из одного адреса Функции memcpy, memset и memmove Функция memcpy осуществляет копирование блока памяти из одного адреса в другой void memcpy(void *dst, const void *src, unsigned count) Функция memmove аналогична memcpy, но корректно работает, если блоки перекрываются void memmove(void *dst, const void *src, unsigned count) Функция memset заполняет область памяти определенным значением типа char void memset(void *dst, int c, unsigned count)

Пример int n = 30; // выделяем память под n элементов типа int * Пример int n = 30; // выделяем память под n элементов типа int * arr = (int*)malloc(sizeof(int) * n); memset(arr, 1, sizeof(int) * n); arr[0] = 5; free(arr); arr = NULL;

Указатели на структуры и объединения Указатели на структуры объявляются аналогично указателям на другие типы Указатели на структуры и объединения Указатели на структуры объявляются аналогично указателям на другие типы Для доступа к элементам структуры может применяться оператор -> typedef struct tag. Point { int x, y; }Point; Point p = {10, 20}; Point *p. Point = &p; (*p. Point). x = 1; p. Point->y = 2;