- •Язык программирования Си
- •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.
- •Открытие потока.
- •Закрытие потока.
- •Предопределенные указатели потоков.
- •Функции ввода-вывода.
Указатели и одномерные массивы
В языке C понятие массива тесно связано с понятием указателя. Действительно, как было описано выше, имя массива представляет собой адрес области памяти, распределенной под этот массив, или иными словами адрес первого элемента массива. Пусть описаны следующие данные:
int a[100], *pa;
и осуществлено присваивание:
pa = a;
Оно является корректным, поскольку имя aобозначает адрес первого элемента массиваaи поэтому имеет тип указателя наint. После этого присваивания
pa[0]или*paбудет обозначать a[0];
pa[1] или *(pa+1) будет обозначать a[1];
pa[2] или *(pa+2) будет обозначать a[2] и т. д. И вообще обозначения вида *(pa+n)иpa[n]являются полностью эквивалентными. Точно также эквивалентны выражения*(a+i)иa[i].
На первый взгляд кажется, что массив и указатель полностью эквивалентны. Однако имеется два существенных отличия массива от указателя:
массиву при описании выделяется память для хранения всех его элементов, а указателю только для хранения адреса;
адрес массива навсегда закреплен за именем, то есть имя массива является адресной константой и выражение вида a = pa недопустимо.
Результат прибавления к указателю или вычитания из него целочисленной величины является указателем того же типа, значение которого отличается от значения исходного указателя на число байт, определяемое произведением целочисленной величины на размер данного, которое адресует указатель. Например, если имеются описания
int A[20], *pA = A;
double B[20], *pB = B;
то указатель (pA+3) будет иметь значение на 6 байт больше, чем pA, и будет адресовать элемент A[3] массива A. Указатель (pB+3) будет иметь значение на 24 байта больше, чем pB, и будет адресовать элемент B[3] массива B. С указателями типа void подобные операции выполнены быть не могут, поскольку компилятор не знает размера адресуемого данного.
Для указателей определены операции увеличения и уменьшения на целочисленную величину, как альтернативная форма записи выражений
pA = pA + i; эквивалентно pA += i;
pA = pA - i; эквивалентно pA -= i;
pA = pA + 1; эквивалентно pA++; или ++pA;
pA = pA - 1; эквивалентно pA--; или --pA; При этом, работа префиксных и постфиксных операций ++ и -- совпадает с их работой для арифметических данных.
Указатели допускается использовать в операциях сравнения. При этом всегда возможно сравнение указателя с нулем и сравнение двух однотипных указателей. Однако правильность результата последнего сравнения для 16-ти разрядного режима работы IBM PC гарантируется только в том случае, если сравниваемые указатели являются указателями на элементы одного и того же массива данных или если они предварительно подвергаются нормализации (см. ниже).
Разность двух однотипных указателей представляет собой целочисленную величину равную количеству элементов данных (не байт) между соответствующими адресами памяти. Правильность результата этой операции для 16-ти разрядного режима работы IBM PC тоже гарантируется только в том случае, если указатели имеют значение адресов элементов одного и того же массива данных или если они предварительно подвергаются нормализации (см. ниже).
В следующем фрагменте программы иллюстрируется использование вышеописанных операций
double A[100], *pA, *pA100;
int i;
/* Заполняем массив A. Работаем с массивом */
for (i=0; i<100; i++) A[i]=0;
/* Заполняем массив A. Работаем с указателями */
for (pA=A, pA100=pA+100; pA<pA100; pA++) *pA=11.9;
Последний вариант заполнения массива может оказаться более эффективным.