- •Функции.
- •Вызов функции с переменным числом параметров
- •Функция main и её параметры.
- •Директивы препроцессора (прекомпилера).
- •Объявление указателей.
- •Модификатор const.
- •Операции.
- •Указатели на различные типы.
- •Указатель на void.
- •Применение указателей для передачи данных между функциями.
- •Массивы.
- •Индексация массивов.
- •Хранение массива в памяти. Адреса элементов. Хранение массива в памяти.
- •Массивы и константные указатели.
- •Статическое и динамическое выделение памяти.
- •Функции calloc, malloc, free
- •Функция realloc
- •Передача массивов в качестве аргументов функции.
- •Указатели на функции.
- •Библиотеки функций.
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Работа со строковыми данными (стрингами). Представление строковых данных в языке c.
- •Функции работы со строками.
- •Потоковый ввод-вывод
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Функции работы с файлами.
- •Потоковый ввод-вывод
- •Работа с потоками
- •Курсор.
- •Ввод-вывод отдельных символов и строк.
- •Форматированный ввод-вывод информации в файл.
- •Блочный потоковый ввод-вывод
- •Смена текущей позиции в файле. Проверка конца файла.
- •Функции доступа к файлам нижнего уровня.
- •Методы сортировки данных.
- •Введение
- •Сравнение методов сортировки
- •Программная реализация алгоритмов сортировки
- •Метод пузырька.
- •Метод обмена.
- •Метод вставки.
- •Метод Шелла.
- •Метод кучи (бинарной кучи).
- •Очередь
- •Линейный список
- •Физическое (машинное) представление линейных списков
- •Программные реализации структур данных. Стек. Реализация в виде массива.
- •Стек. Связанное представление.
- •Очереди. Реализация в виде массива.
- •Дерево. Связанное представление.
- •Рекурсивный вызов функций.
- •Структуры. Объединения. Перечисления.
- •Перечисление (enum).
- •Производные типы данных.
- •Структура (struct).
- •Побитовое описание полей структуры.
- •Объявление переменных, реализующих структуру.
- •Доступ к элементам структуры.
- •Объединение (union).
- •Вложенное описание структур и объединений.
- •Описание структур и объединений в виде пользовательского типа.
- •Передача структур и объединений в виде параметров функции.
- •Инициализация структур и объединений.
- •Выгода от использования структур
Массивы.
Массив - это непрерывный (по расположению в памяти) набор однотипных объектов (данных).
Другое определение массива - это конечная совокупность данных одного типа
Можно говорить о массивах целых чисел, массивах символов и т.д. можно даже определить массив, элементы которого массивы.
Когда нам требуется для работы массив, мы сообщаем об этом компилятору при помощи оператора описания, в котором определяется класс памяти, тип данных и количество элементов массива.
Синтаксис оператора описания:
Класс_памяти тип_данных имя[];
После имени массива добавляются квадратные скобки[]. Массивы могут иметь любой класс хранения, кроме класса register.
Например:
int a[10]; // массив 10 целых чисел,
int x[2][5]; // двумерный массив х размерностью 2х5.
Такое описание можно трактовать как матрицу из 2 строк и 5 столбцов.
int x[2][5][6]; // трёхмерный массив х размерностью 2х5x6.
Примеры описания массивов c классами памяти:
int temp[365];/*внешний массив из 365 целых чисел*/
main()
{
float rain[365]; /*автоматический массив из 365 чисел типа float*/
static char code[12]/*статический массив из 12 символов*/
extern temp[]; /*внешний массив, размер указан выше*/
…
}
При использовании класса памяти extern размер массива можно не указывать – компилятор его всё равно читать не будет. Тем не менее, размер массива должен быть указан при объявлении массива как внешней переменной, т.е. в том месте, где глобальный массив с таким же именем определяется без модификатора extern.
Индексация массивов.
Для обращения к некоторому элементу массива применяют операцию индексации []. Можно также считывать элементы напрямую из памяти, получив указатель на массив (но об этом позже).
Индексация элементов массивов в Си всегда начинается с 0, а не с 1, как в некоторых языках, т.е. описание int x[5]; создаёт массив, состоящий из 5 элементов целого типа. Этот массив будет содержать элементы x[0], x[1], x[2], x[3], x[4].
Индекс, указываемый в операции индексации, может быть не только целой константой или целой переменной, но и любым выражением целого типа. Не следует путать этот индекс с размером массива, указываемым при описании массива.
Элемент массива в программе используется наравне с простой переменной. Элементам массива можно присваивать значения, как простым переменным. Например, в приведенном ниже фрагменте программы присваиваются четные числа элементам автоматического массива:
/*присваивание значений массиву */
main()
{
int evens[50]; // Объявляем массив, в качестве аргумента,
// стоящего в скобках может быть только
// константное целое выражение
int counter;
for (counter=0; counter<50; counter++)
evens[counter]=2*counter; // Операция индексации,
// здесь могут
// использоваться переменные.
}
Хранение массива в памяти. Адреса элементов. Хранение массива в памяти.
Массив хранится в памяти в виде непрерывного блока данных размером
(x0*x1*x2*…*xn-1)*TypeSize байт, где
n – размерность массива,
x1… xn – количество элементов массива в каждом измерении,
TypeSize – размер типа данных одного элемента массива.
Например, массив int arr[2][6]; будет занимать в памяти 2*6*4=48 байт.
Массив хранится в памяти построчно, т.е. самый правый индекс в наборе индексов массива меняется наиболее быстро:
-
0й байт
Arr[0][0]
Arr[0][1]
Arr[0][2]
Arr[0][3]
Arr[0][4]
Arr[0][5]
24й байт
Arr[1][0]
Arr[1][1]
Arr[1][2]
Arr[1][3]
Arr[1][4]
Arr[1][5]
Поскольку адресация памяти компьютера линейная, то вышеприведенный рисунок надо понимать так: строки массива в памяти хранятся линейно, одна за другой Аналогично хранятся и массивы больших размерностей.
Таким образом, если у нас есть N-мерный массив Arr, с количеством элементов в каждом измерении x0 … xN-1 и размером каждого элемента в TypeSize байт (определяемого типом элемента), то элемент Arr[i0][i1]…[iN-1] будет иметь линейный номер, вычисляемый по формуле:
,
Эту формулу можно использовать для перевода индексов многомерного массива в индексы одномерного массива, для тех случаев, когда создание многомерного массива сложно или невозможно.
Номер первого байта элемента будет подсчитываться по формуле:
ByteNum=Num*TypeSize .
Память под массив выделяется при его объявлении, например, при объявлениях:
char ac[22][10];
long al[50];
будет выделено 220 байт под массив ac, и 200 байт под массив al. Такое выделение памяти называют статическим, а сами массивы – статическими массивами. Размер выделяемой памяти известен ещё на этапе компиляции, и процедуры выделения и освобождения памяти автоматически расставляются в программе в процессе компиляции. В ходе программы размер массива не может быть изменён. Время жизни массива аналогично времени жизни обычных переменных – память из под локальных массивов освобождается при выходе из блока операторов или функции, в случае же глобальных массивов – при окончании программы.