
- •Л. Б. Бузюков, о. Б. Петрова
- •Учебное пособие
- •Предисловие
- •Глава 1. Введение в язык с
- •1.1. История создания и особенности языка с
- •1.3. Элементы языка с
- •1.3.1. Основные символы
- •1.3.2. Ключевые слова
- •1.3.3. Идентификаторы
- •1.3.4. Константы
- •1.3.5. Лексемы
- •1.3.6. Комментарии
- •Глава 2. Типы данных языка c
- •2.1. Числовые типы данных
- •2.2. Объявление переменных
- •2.3. Данные целого типа
- •2.4. Данные вещественного типа
- •Глава 3. Выражения
- •3.1. Операции
- •3.1.1. Арифметические операции
- •3.1.2. Операция присваивания
- •Глава 4. Составление простейших программ
- •4.1. Препроцессор и его функции
- •4.2. Основные директивы препроцессора
- •4.2.1. Директива include
- •4.2.2. Директива define
- •4.2.3. Директива undef
- •4.3. Структура и правила составления программ
- •4.3.1. Структура функции
- •4.3.2. Функция main()
- •4.3.3. Структура простой программы
- •4.3.4. Правила записи объявлений, операторов и комментариев
- •4.3.5. Пример простейшей программы
- •Глава 5. Средства ввода/вывода
- •5.1. Общие замечания
- •5.2. Функция форматированного вывода printf()
- •5.2.1. Основные форматы
- •5.2.2. Модификации форматов
- •5.3. Функция форматированного ввода scanf()
- •Глава 6. Управляющие операторы
- •6.1. Условные операторы
- •6.1.1. Логические выражения
- •6.1.2. Формы оператора if
- •6.1.3. Оператор выбора switch
- •6.2. Операторы цикла
- •6.2.1. Оператор while
- •6.2.2. Оператор for
- •6.2.3. Оператор do-while
- •6.3. Операторы перехода
- •6.3.1. Оператор break
- •6.3.2. Оператор continue
- •6.3.3. Оператор return
- •6.3.4. Применение оператора goto и меток
- •Глава 7. Функции
- •7.1. Основные понятия
- •7.2. Определение функции
- •7.3. Прототип функции
- •7.4. Вызов функции
- •Глава 8. Классы памяти
- •8.1. Логическаяструктура памяти программы
- •8.2. Особенности классов памяти
- •8.3. Объявления переменных
- •8.4. Объявления функций
- •8.5. Время жизни и область видимости программных объектов
- •8.6. Инициализация глобальных и локальных переменных
- •Глава 9. Указатели
- •9.1. Операция получения адреса
- •9.2. Операции над указателями
- •Глава 10. Массивы
- •10.1. Общие сведения о массивах
- •10.2. Одномерные массивы
- •10.3. Двумерные массивы
- •10.4. Массивы и указатели
- •10.5. Массивы и функции
- •Глава 11. Строки
- •11.1. Представление символьной строки при помощи одномерного массива
- •11.2. Указатель на символьную строку
- •11.3. Ввод/вывод символьных строк
- •11.4. Массивы символьных строк
- •11.5. Функции работы состроками
- •Глава 12. Структуры
- •12.1. Определение структуры
- •12.2. Структуры и функции
- •12.3. Указатели на структуру
- •12.4. Массивы структур
- •12.5. Вложенные структуры
- •12.6. Использование синонима типа
- •12.7. Объединения
- •Глава 13. Файлы
- •13.1. Работа с файлами
- •13.2. Функции ввода/вывода
- •Глава 14. Динамическая память
- •14.1. Распределение памяти
- •14.2. Функции управление памятью
- •Глава 15. Проект
- •15.1. Основы создания проекта
- •15.2. Пример создания проекта
- •Глава 17. Основы объектно-ориентированного программирования
- •17.1. Объектно-ориентированный подход
- •17.3. Конструкторы и деструкторы
- •17.4. Инкапсуляция
- •17.5. Полиморфизм
- •17.6. Наследование
- •17.7. Виды взаимодействия классов
- •17.8. Способы графического представления объектно-ориентированной задачи
- •18.2. Библиотека Win32 api
- •18.3. Библиотека owl
- •18.4. Библиотека vcl
- •18.5. Библиотека clx
- •18.6. Библиотека mfc
- •18.7. Библиотека OpenGl
- •19.3. Создание проекта
- •19.4. Редактирование проекта
- •19.5. Компиляция и выполнение программы
- •19.6. Файловая структура проекта
- •19.7. Создание консольного приложения
- •Глава 20. Разработка приложений для операционных систем windows
- •20.1. Взаимодействие программы и Windows
- •20.2. Компоненты библиотеки Win32 api
- •20.3.Функция WinMain()
- •20.4. Оконная процедура
- •20.5. Структура программы для ос Windows
- •20.6. Ресурсы Windows
- •20.7. Взаимодействие прикладной программы и устройств в Windows
- •Глава 21. Создание приложений для ос windows на основе библиотеки mfc
- •21.1. Обзор классов библиотеки mfc
- •21.2. Класс cString
- •21.3. Класс cFile
- •21.4. Класс cPoint
- •21.5. Класс cRect
- •21.7. Приложение, основанное на диалоге
- •21.8. Использование в приложении элементов управления
- •21.9. Мастер классов mfc ClassWizard
- •21.10. Установка начального значения элементам управления
- •21.11. Элементы управления Picture
- •21.12. Элемент управления Group Box
- •21.13. Элемент управления Radio Button
- •21.14. Элемент управления Check Box
- •21.15. Элемент управления List Box
- •21.16. Создание меню
- •21.17. Приложение с двумя диалоговыми панелями
- •21.18. Приложение sdi
- •21.19. Создание панели инструментов
- •21.20. Приложение mdi
- •21.21. Контекстыустройств в mfc
- •21.22. Графические объекты Windows в mfc
- •21.23. Графические операции в mfc
- •П.1. Основы методологии конструирования программ
- •П.1.1. Основные понятия. Программа и алгоритм
- •П.1.2. Этапы разработки программ
- •П.2. Алгоритмы
- •П.2.1. Алгоритм и его свойства
- •П.2.2. Способы описания алгоритмов
- •П.2.3. Средства графического изображения алгоритмов Схемы алгоритмов
- •Псевдокоды
- •Структурограммы
- •П.3. Основные приемы программирования
- •П.3.1. Разновидности структур программирования
- •П.3.2. Программирование линейных и разветвляющихся процессов
- •П.3.3. Программирование циклических процессов
- •Арифметический цикл (цикл с параметром)
- •Итерационный цикл
- •Вложенный цикл
- •Литература
10.3. Двумерные массивы
Стандартом C определены многомерные массивы. Простейшая форма многомерного массива – двумерный массив, т. е. массив одномерных массивов.
Описание двумерного массива выглядит следующим образом:
<класс> тип имя [N1] [N2];
где N1,N2 – количество строк и столбцов.
Массив в памяти располагается по строкам:
ID[0][0],…,ID[0][N2–1],
…
ID[N1–[0],…,ID[N1–1][N2–1], где ID – имя массива.
Как и в случае одномерных массивов, возможна инициализация двумерных массивов:
int a[2][3]=
{
{1,–2,7},
{2,–3,9}
};
Пример программы
Что напечатает ЭВМ?
# include <stdio.h>
int main()
{
int a[2][3]=
{
{6,–1},
{–3,2}
};
int i,j;
for (i=0;i<2;++i)
for (j=0;j<3;++j)
printf("\n a[%d,%d]=%d",i,j,a[i][j]);
}
Ответ: a[0,0]=6, a[0,1]=–1, a[0,2] = 0, a[1,0]=–3, a[1,1]=2, a[1,2]=0.
10.4. Массивы и указатели
В языке C массивы и указатели тесно связаны друг с другом. Например, когда объявляется массив в виде int a[25], то при этом не только выделяется память для 25 элементов массива, но и формируется указатель с именем a, значение которого равно адресу первого по счету (нулевого) элемента массива. Доступ к элементам массива может осуществляться через указатель с именем a. С точки зрения синтаксиса языка указатель a является константой, значение которой можно использовать в выражениях, но изменить это значение нельзя.
Поскольку имя массива является указателем-константой, допустимо, например, такое присваивание:
int a[25];
int *ptr;
ptr=a;
В этом примере в переменную-указатель ptr записывается адрес начала массива a, т. е. адрес первого элемента массива.
Также справедливы следующие соотношения: например, имеется массив a[N], тогда истинными будут следующие сравнения:
a==&a[0];
*a==a[0].
Указатели можно увеличивать или уменьшать на целое число:
ptr=a+1;
Теперь указатель ptr будет указывать на второй элемент массива a, что эквивалентно &a[1].
При увеличении указателя на единицу адрес, который он представляет, увеличивается на размер объекта связанного с ним типа, например:
int a[25];
int *ptr=a;
ptr+=3;
Первоначально указатель ptr указывал на начало массива a. После прибавления к переменной ptr числа 3 значение указателя увеличилось на 3*sizeof(int), а указатель ptr теперь будет указывать на четвертый элемент массива a. Указатель можно индексировать точно так же, как и массив. На самом деле компилятор преобразует индексацию в арифметику указателей, например, ptr[3]=10 представляется как *(ptr+3)=10.
К указателям типа void арифметические операции применять нельзя, так как им не ставится в соответствие размер области памяти.
Таким образом, в языке C для доступа к элементам массива существует два различных способа. Первый способ связан с использованием обычных индексных выражений в квадратных скобках, например, a[7]=3 или a[i+2]=5. При таком способе доступа записываются два выражения, причем второе выражение заключается в квадратные скобки. Первое из этих выражений должно быть указателем, а второе – выражением целого типа. Указатель, используемый в индексном выражении, не обязательно должен быть константой, указывающей на какой-либо массив, это может быть и переменная-указатель. В частности, после выполнения присваивания ptr=a доступ к седьмому элементу массива можно получить как с помощью константы-указателя a в форме a[7], так и переменной-указателя ptr в форме ptr[7].
Второй способ доступа к элементам массива связан с использованием адресных выражений и операции косвенной адресации в форме *(a+3)=10 или *(a+i+2)=5.
При реализации на компьютере первый способ приводится ко второму, т. е. индексное выражение приводится к адресному. Для приведенных примеров обращение к элементу массива a[3] преобразуется в *(a+3).
Для доступа к начальному элементу массива, т. е. к элементу с нулевым индексом, можно использовать просто значение указателя a или ptr, поэтому любое из присваиваний
*a=2;
a[0]=2;
*(a+0)=2;
*ptr=2;
ptr[0]=2;
*(ptr+0)=2;
присваивает начальному элементу массива значение 2.
Многомерные массивы в языке C – это массивы массивов, т. е. массивы, элементами которых, в свою очередь, являются массивы. При объявлении таких массивов в памяти компьютера создается несколько различных объектов. Например, при выполнении объявления двумерного массива int a2[4][3] в программе создается указатель a2, который определяет в памяти местоположение первого элемента массива и, кроме того, является указателем на массив из четырех указателей. Каждый из этих четырех указателей содержит адрес одномерного массива, представляющего собой строку двумерного массива и состоящего из трех элементов типа int, и позволяет обратиться к соответствующей строке массива.
Таким образом, объявление a2[4][3] порождает в программе три разных объекта: указатель с идентификатором a2, безымянный массив из четырех указателей и безымянный массив из двенадцати чисел типа int. Для доступа к безымянным массивам используются адресные выражения с указателем a2. Доступ к элементам массива указателей осуществляется с указанием одного индексного выражения в форме a2[2] или *(a2+2). Для доступа к элементам двумерного массива чисел типа int должны быть использованы два индексных выражения в форме a2[1][2] или эквивалентных ей *(*(a2+1)+2) и (*(a2+1))[2]. Следует учитывать, что с точки зрения синтаксиса языка C указатель a2 и указатели a2[0], a2[1], a2[2], a2[3] являются константами, и их значения нельзя изменять во время выполнения программы.
Размещение трехмерного массива происходит аналогично. Так, например, объявление float a3[3][4][5] порождает в программе, кроме самого трехмерного массива из 60 чисел типа float, массив из четырех указателей на тип float, массив из трех указателей на массив указателей на float и указатель на массив массивов указателей на float.
При размещении элементов многомерных массивов они располагаются в памяти подряд по строкам, т. е. быстрее всего изменяется последний индекс, а медленнее – первый. Такой порядок дает возможность обращаться к любому элементу многомерного массива, используя адрес его начального элемента и только одно индексное выражение.
Например, обращение к элементу a2[1][2] можно осуществить при помощи указателя ptr2, объявленного в форме int *ptr2=a2[0], как обращение ptr2[1×3+2] (здесь 1 и 2 – это индексы используемого элемента, а 3 – число элементов в строке) или как ptr2[5]. Заметим, что внешне похожее обращение a2[6] выполнить невозможно, так как указателя с индексом 6 не существует.
Для обращения к элементу a3[2][3][4] из трехмерного массива тоже можно использовать указатель, описанный как float *ptr3=a3[0][0], с одним индексным выражением в форме ptr3[2×20+3×5+4] или ptr3[59].