- •Язык программирования Си
- •7. Понятие о препроцессоре языка Си 29
- •8. Операторы языка Си и приемы программирования 30
- •9. Массивы. Адресная арифметика языка Си 51
- •Правила записи программы на языке Си
- •Правила формального описания синтаксиса языка программирования
- •Идентификаторы языка Си
- •Понятие о типах данных.
- •Системы счисления. Представление данных в эвм.
- •Основные типы данных языка Си
- •Правила записи констант различных типов
- •Беззнаковый тип для целых данных
- •Символьные строки
- •Понятие функции
- •Стандартная функция printf
- •Стандартная функция scanf
- •Операции и выражения
- •Простейшие арифметические операции
- •Операция присваивания
- •Оператор-выражение
- •Использование в выражениях операндов разных типов
- •Операции преобразования типов
- •Стандартные математические функции
- •Простейшие функции, определяемые программистом
- •Дополнительные арифметические операции
- •Дополнительные операции присваивания
- •Битовые операции
- •Операции отношения
- •Логические операции
- •Операция определения размера данных
- •Приоритеты операций
- •Понятие о препроцессоре языка Си
- •Операторы языка Си и приемы программирования
- •Оператор цикла while
- •Условный оператор и условная операция
- •1) Короткие операторы:
- •2) Группы коротких операторов:
- •3) Длинные группы операторов:
- •Запись алгоритмов с помощью диаграмм Несси - Шнейдермана (структограмм )
- •Некоторые приемы программирования
- •Оператор прерывания цикла
- •Оператор продолжения цикла
- •Пример организации простейшего меню
- •Множественный выбор. Оператор переключения
- •Оператор цикла do-while.
- •Перечисления. Работа с клавиатурой ibm pc
- •Пример организации светового меню
- •Массивы. Адресная арифметика языка Си
- •Описание массива
- •Ввод-вывод массива
- •Инициализация массива
- •Программа вычисления длины строки символов
- •Двумерные массивы (массивы массивов)
- •Адресная арифметика языка Си
- •Указатели и одномерные массивы
- •Указатели и двумерные массивы
- •Указатели и функции
- •Оператор typedef
- •Дополнительные описания указателей для ibm pc
- •Непосредственная работа с экранной памятью
- •Дополнительные сведения о функциях
- •Области видимости и глобальные данные
- •Время жизни переменных и классы памяти языка Си
- •Передача аргументов в функцию
- •Возврат значений из функций
- •Работа с динамической памятью
- •Стандартные функции управления динамической памятью
- •Пример использования динамической памяти
- •Особенности работы с двумерными массивами
- •Пересчет индексов вручную
- •Массивы с постоянной длиной строки
- •Общий случай двумерного массива
- •Особенности работы с массивами большого размера
- •Модульное программирование в системе Turbo c
- •Обеспечение корректной стыковки модулей
- •Создание библиотек функций
- •Некоторые библиотечные функции языка Си
- •Функции консольного ввода/вывода (уникальны для tc)
- •Функции обработки строк.
- •Функции распознавания вида символа
- •Функции преобразования данных
- •Структуры языка c.
- •Описание структуры
- •1 Способ
- •2 Способ
- •Трактовка имени структуры.
- •Доступ к элементу структуры.
- •Инициализация структур.
- •Структуры и функции.
- •Поля бит в структурах.
- •Объединения.
- •Дополнительные сведения о препроцессоре языка c.
- •Условное выражение.
- •Приоритеты и направления операций.
- •Динамические данные.
- •Линейные списки.
- •Организация данных в виде стека.
- •Организация данных в виде очереди.
- •Организация данных в виде деревьев.
- •Библиотека ввода-вывода языка c.
- •Открытие потока.
- •Закрытие потока.
- •Предопределенные указатели потоков.
- •Функции ввода-вывода.
Указатели и двумерные массивы
Пусть имеются следующие определения массивов и указателей:
int A[4][2], B[2];
int *p, (*pA)[4][2], (*pAstr)[2];
Здесь A представляет собой двумерный массив из четырех строк и двух столбцов, B - одномерный массив из двух элементов. Для каждого из этих массивов будет выделено соответствующее количество памяти, достаточное для хранения всех их элементов.
Указатель p представляет собой указатель на величину int, указатель pA - указатель на двумерный массив из четырех строк и двух столбцов, pAstr - указатель на одномерный массив из двух элементов. Все указатели имеют размер, равный размеру адреса для данных в используемой модели памяти. Память для хранения данных, естественно, не выделяется. Количество элементов данных из описания массивов будет использовано лишь для корректного изменения значения указателя при выполнении над ним допустимых арифметических операций.
Смысл трактовки этих указателей определяется направлением слева-направо для подряд следующих операций [], а также изменением приоритета операции * с помощью круглых скобок. Если не поставить круглых скобок, то следующее определение
int *pa[4][2];
рассматривается как определение двумерного массива из указателей на тип int.
Для вышеописанных указателей допустимы следующие операции присваивания, поскольку слева и справа от операции присваивания находятся указатели на один и тот же тип данных:
p = B;
p = &B[1];
p = &A[0][0];
p = A[2];
Следующее присваивание:
p = A; /* неверно */
является неверным, так как слева от операции присваивания находится указатель на тип int, а справа - указатель на первый элемент массива A, который (элемент) представляет собой массив из двух элементов типа int. В таких случаях компиляторы выдают предупреждающее сообщение о подозрительном преобразовании указателя.
Если программист уверен в своих действия, то он может использовать операцию явного приведения типа для устранения этого сообщения, но при этом компилятор снимает с себя всякую ответственность за корректность использования такого указателя. Так, после присваивания
p = (int *) A;
элементы, на которые ссылается указатель, и элементы массива A находятся в следующем соответствии:
p[0] эквивалентно A[0][0]
p[1] эквивалентно A[0][1]
p[2] эквивалентно A[1][0]
p[3] эквивалентно A[1][1]
p[4] эквивалентно A[2][0]
p[5] эквивалентно A[2][1]
p[6] эквивалентно A[3][0]
p[7] эквивалентно A[3][1]
Совершенно корректными являются следующие присваивания
pAstr = A;
после которого использование массива A и указателя pAstr совершенно эквивалентны:
pAstr[i][j] эквивалентно A[i][j]
Присваивание
pAstr = &A[2];
устанавливает следующее соответствие между элементами, на которые ссылается указатель pAstr и элементами массива A:
pAstr[0][0] эквивалентно A[2][0]
pAstr[0][1] эквивалентно A[2][1]
pAstr[1][0] эквивалентно A[3][0]
pAstr[1][1] эквивалентно A[3][1]
Следующие присваивания корректны
pA = &A; /* Указатель на двумерный массив */
pAstr = &B; /* Указатель на одномерный массив */
и устанавливают следующее соответствие элементов:
(*pA)[i][j] эквивалентно A[i][j]
(*pAstr)[i] эквивалентно B[i]
Массивы указателей удобны для хранения символьных строк:
char *str[] = {
"Строка 1",
"Строка 2",
"Длинная строка 3"
};
В этом случае каждый элемент массива представляет собой адрес соответствующей строки символов, а сами строки располагаются компилятором в статическом сегменте данных. Никакой лишней памяти, связанной с различной длиной строк, при этом не расходуется.