- •Часть 1
- •Общие сведения Сведения об эумк
- •Методические рекомендации по изучению дисциплины
- •Рабочая учебная программа
- •Часть 2 184
- •Пояснительная записка
- •Содержание дисциплины
- •Индивидуальные практические работы, их характеристика
- •Контрольные работы, их характеристика
- •Литература
- •Основная
- •Дополнительная
- •Перечень компьютерных программ, наглядных и других пособий, методических указаний и материалов и технических средств обучения
- •Учебно-методические пособия
- •Алфавит языка
- •Лексемы
- •Идентификаторы
- •Ключевые слова
- •Знаки операций
- •Константы
- •Комментарии
- •Тема 2. Типы данных Концепция типа данных.
- •Простые типы данных
- •Целый тип int
- •Символьный тип char
- •Типы с плавающей точкой: float, double, long double
- •Тема 3. Выражения
- •Переменные
- •Именованные константы
- •Операции
- •Операции присваивания
- •Инкремент и декремент
- •Унарный плюс и унарный минус (строка 2)
- •Явное преобразование типа
- •Операция определения размера sizeof
- •Деление и остаток от деления
- •Логические операции не, и, или (!, &&, ||)
- •Условная операция (?:)
- •Операция запятая (,)
- •Операции взятия адреса и разадресации
- •Тема 4. Операторы
- •Структура программы
- •Тема 5. Базовые конструкции структурного программирования
- •Операторы ветвления
- •1. Условный оператор if
- •2. Оператор switch
- •Операторы цикла
- •1. Цикл с предусловием while
- •2. Цикл с постусловием do-while
- •3. Цикл с параметром for
- •Тема 6. Массивы
- •Тема 7. Указатели и массивы
- •Тема 8. Строки символов
- •Тема 9. Структуры
- •Массивы структур
- •Битовые поля
- •Объединения
- •Перечисления
- •Тема 10. Функции
- •Глобальные, локальные и статические переменные
- •Параметры функции
- •Передача массивов в качестве параметров функции
- •Функция main, ее параметры
- •Функции стандартной библиотеки
- •Функции форматного вывода и ввода printf и scanf
- •Тема 11. Файлы
- •Тема 12. Работа с динамической памятью
- •Тема 13. Динамические структуры данных
- •Очереди
- •Линейные списки
- •Бинарные деревья
- •Практический раздел Общие указания Указания по выбору варианта
- •Порядок оформление итогового отчета
- •Индивидуальные практические работы Индивидуальная практическая работа 1 Методические указания
- •Варианты заданий.
- •Индивидуальная практическая работа 2 Методические указания
- •Варианты заданий
- •Контрольные работы Контрольная работа 1 Методические указания
- •Варианты заданий
- •Контрольная работа 2 Методические указания
- •Варианты заданий
Тема 7. Указатели и массивы
В языке С существует очень тесная связь между указателями и массивами: любой доступ к элементу массива по его индексу может быть выполнен при помощи указателя, причем последний вариант работает быстрее и, следовательно, более предпочтителен.
Рассмотрим следующие операторы:
int mas[N];
int *p;
Первый из них описывает целочисленный массив размерностью N, а второй – указатель на целочисленную переменную, который пока ни на что не указывает. Если выполнить присваивание
p = &mas[0];
то теперь указатель p будет содержать адрес начального элемента массива mas, или, другими словами, будет указывать на элемент mas[0] (точнее, на первый байта элемента mas[0], т.к. значение типа int хранится в 4-х байтах).
Как только такое присваивание выполнено, можно применять правила адресной арифметики над указателями, суть которых заключается в том, что, если указатель p указывает на некоторый элемент массива, то p, увеличенный на единицу, будет указывать на следующий элемент, а p, увеличенный на i, будет указывать на i-й элемент по отношению к элементу, на который он указывал вначале.
p |
mas[0] |
p + 1 |
mas[1] |
p + 2 |
mas[2] |
. . . |
. . . |
p+N-1 |
mas[N-1] |
Так как операция разадресации (*) позволяет получить значение элемента массива, на который указывает указатель, то можно записать следующее:
*p = mas[0];
*(p+1) = mas[1];
*(p+2) = mas[2];
. . .
*(p+N-1) = mas[N-1];
С другой стороны, имя массива в языке С есть не что иное, как адрес его начального элемента, поэтому присваивание
p = &mas[0];
можно заменить на
p = mas;
С учетом этого можно записать, что:
*mas = mas[0];
*(mas +1) = mas[1];
*(mas +2) = mas[2];
. . .
*(mas +N-1) = mas[N-1];
Между указателем p и именем массива mas существует одно существенное различие. Указатель p – это переменная, предназначенная для хранения любых адресов, поэтому можно, например, написать:
p++;
p += i;
Но имя массива mas не является переменной, это указатель-константа на начальный элемент массива, и записи типа:
mas++;
mas += i;
недопустимы.
Пример 1: вывести на экран значения всех элементов массива, введенных с клавиатуры.
#include <stdio.h>
void main()
{
const int N = 10;
int i, mas[N];
int *p;
p = mas;
//Ввод (один из вариантов)
for (i = 0; i < N; i++)
scanf(“%d”, p+i);
//Вывод: вариант 1
for (i = 0; i < N; i++)
printf(“%d ”, *(p+i));
//Вывод: вариант 2
for (i = 0; i < N; i++)
{
printf(“%d ”, *p);
p++;
}
//Вывод: вариант 3
p = mas;
for (i = 0; i < N; i++)
printf(“%d ”, *p++);
//Вывод: вариант 4
p = mas;
for (i = 0; i < N; p++, i++)
printf(“%d ”, *p);
//Вывод: вариант 5
for (i = 0; i < N; i++)
printf(“%d ”, *(mas+i));
//Вывод элементов массива в обратном порядке (один из вариантов)
p = &mas[N-1];
for (i = 0; i < N; i++)
printf(“%d ”, *(p-i));
}
Пример 2: вывести на экран все значения элементов двумерного массива.
#include <stdio.h>
void main()
{
const int N = 2, M = 4;
int mas[N ][M], *p, i, j;
p = &mas[0][0]; //можно p = mas[0] или p = *mas;
//Ввод (один из вариантов)
for (i = 0; i < N*M; i++)
scanf(“%d”, p+i);
//Вывод: вариант 1
for (i = 0; i < N*M; i++)
printf("%d%c", *p++, (i+1)%M ? ' ' : '\n');
//Вывод: вариант 2
p = mas[0];
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
printf("%d ", *(p+i*M+j));
printf("\n");
}
//Вывод: вариант 3
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
printf("%d ", *(mas[i]+j));
printf("\n");
}
//Вывод: вариант 4
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
printf("%d ", *(*(mas+i)+j));
printf("\n");
}
}
Эти варианты программы основаны на следующей схеме взаимосвязей между указателями и элементами двумерного массива:
p = mas[0] = *mas |
mas[0][0] |
p+1 = mas[0]+1 = *mas+1 |
mas[0][1] |
p+2 = mas[0]+2 = *mas+2 |
mas[0][2] |
p+3 = mas[0]+3 = *mas+3 |
mas[0][3] |
p+4 = mas[1] = *(mas+1) |
mas[1][0] |
p+5 = mas[1]+1 = *(mas+1)+1 |
mas[1][1] |
p+6 = mas[1]+2 = *(mas+1)+2 |
mas[1][2] |
p+7 = mas[1]+3 = *(mas+1)+3 |
mas[1][3] |