- •Материалы для подоговки к экзамену по дисциплине «основы программировния»
- •Тема №1 Основные понятия
- •Способы записи алгоритма
- •Тема №2 Переменные
- •Типы переменных
- •Типы с плавающей точкой
- •Переполнение переменных
- •Постфиксное обозначение типа
- •Шестнадцатеричный и восьмеричный формат
- •Экспоненциальная форма представления чисел
- •Объявление переменных
- •Начальное значение переменной
- •Область видимости переменной
- •Тема №3 Оператор присваивания
- •Ввод-вывод Форматированный вывод
- •Форматированный ввод
- •Непечатные символы
- •Тема №4 Ветвления и логические операторы
- •Оператор Switch
- •Логические операторы
- •Логическое отрицание
- •Логическое и
- •Логическое или
- •Пример: закон де-Моргана.
- •Порядок выполнения логических операторов
- •Тема №5 Циклы
- •Цикл с предусловием
- •Циклы с постусловием
- •Цикл for
- •Вложенные циклы
- •Тема №6 Одномерные массивы
- •Начальная инициализация массива.
- •Размер массива
- •Переполнение массива
- •Пример с одномерным массивом
- •Многомерные статические массивы
- •Пример с многомерным массивом
- •Тема №7 Строки в си. Введение
- •Чтение строк
- •Указатели
- •Определение
- •Арифметика указателей
- •Указатель на указатель
- •Указатели и приведение типов
- •Null pointer - нулевой указатель
- •Пример работы с указателями
- •Тема №8 Указатели и массивы
- •Многомерные массивы и указатели на многомерные массивы
- •Определение макросов
- •Тема №9 Тернарный оператор и оператор запятая
- •Оператор запятая.
- •Сегментация приложения на си
- •Тема №10 Динамическое выделение памяти
- •Освобождение памяти с помощью free
- •Работа с двумерными и многомерными массивами
- •Тема №11 Параметры командной строки
- •Функции
- •Параметры и аргументы
- •Передача аргументов По значению
- •По указателю (ссылке)
- •Передача массива в качестве аргумента
- •Тема №12 Битовые операции
- •Операции побитового сдвига
- •Примеры
- •Вопросы к экзамену по дисциплине «Основы программирования»
Переполнение массива
Пускай у вас есть такой код
int A[10];
int i;
for (i=0; i<=10; i++) {
A[i] = 1;
}
Здесь цикл for задан с ошибкой. В некоторых старых версиях компиляторов этот код зацикливался. Дело в том, что переменная i располагалась при компиляции сразу за массивом A. При выходе за границы массива счётчик переводился в 1.
Массивы небезопасны, так как неправильная работа с индексом может приводить к доступу к произвольному участку памяти (Теоретически. Современные компиляторы сами заботятся о том, чтобы вы не копались в чужой памяти).
Если вы работаете с массивами, то необходимо следить за тем, чтобы счётчик не превышал размер массива и не был отрицательным. Для этого, как минимум:
Используйте тип size_t для индексирования. Он обезопасит вас от отрицательных значений и его всегда хватит для массива любого размера.
Помните, что массив начинается с нуля.
Последний элемент массива имеет индекс (размер массива - 1)
Никаких полноценных способов проверки, вышли мы за пределы массива или нет, не существует. Поэтому либо мы точно знаем его размер, либо храним в переменной и считываем при надобности.
Пример с одномерным массивом
Теперь несколько типичных примеров работы с массивами
#include <conio.h>
#include <stdio.h>
//Это макрос. SIZE в коде будет заменено на 10u
#define SIZE 10u
void main() {
int A[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
unsigned i, j; //счётчики
unsigned half; //середина массива
unsigned tmp; //временная переменная для обмена значениями
half = SIZE / 2;
//Один счётчик идёт слева напрво, другой справа налево
for (i = 0, j = SIZE - 1; i < half; i++, j--) {
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
for (i = 0; i < SIZE; i++) {
printf("%d ", A[i]);
}
getch();
}
Здесь незнакомая для вас конструкция
#define SIZE 10u
макрос. Во всём коде препроцессор автоматически заменит все вхождения SIZE на 10u.
Многомерные статические массивы
В си, наряду с одномерными, существуют и многомерные массивы. Например, двумерный массив: его можно представлять как массив массивов, или как матрицу. Размерность массива может быть и больше: трёхмерные, четырёхмерные и т.д.
Синтаксис остаётся прежним, добавляется только новая размерность
<тип> <имя>[размерность1][размерность2]...;
Например, двумерный массив
int a[2][3];
Трёхмерный массив
int a[3][4][5];
Доступ до элементов массива осуществляется также, как и в одномерном массиве.
#include <conio.h>
#include <stdio.h>
#define SIZE 5
void main() {
int M[3][3];
unsigned i, j;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
M[i][j] = i * j;
}
}
do {
printf("enter indexes:\n");
scanf("%d", &i);
scanf("%d", &j);
if (i < 3 && j < 3) {
printf("M[%d][%d] == %d\n", i, j, M[i][j]);
} else {
break;
}
} while (1);
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf("\t%d", M[i][j]);
}
printf("\n");
}
getch();
}
Особенностью является то, что по своему строению многомерный массив является обыкновенным, "одномерным", массивом. Все элементы расположены друг за другом. Доступ до элемента a[i][j] – по существу сдвиг на i*число столбцов + j. В двумерном массиве, таким образом, элементы расположены "по рядам", в трёхмерном - "по слоям", внутри которых элементы расположены "по рядам" и т.д.
В связи с этим, при начальной инициализации опускать размерность можно только в первых квадратных скобках:
int a[][3] = {0};
int b[][5][25] = {0};
Компилятор будет знать в таком случае сдвиг, необходимый для доступа к элементу.
С этим связаны и особенности начальной инициализации. Так как многомерный массив по сути одномерный, то его начальную инициализацию можно провести так
int a[2][3] = {1, 2, 3, 4, 5, 6};
Можно опустить первую размерность
int a[][2][3] = {1, 2, 3, 34, 5, 6, 7, 8, 9, 10, 11, 12};
Можно с помощью фигурных скобок сделать данные более удобными для чтения
int a[2][3] = {{1, 2, 3}, {4, 5, 6}}
или
int a[][3][4] =
{{{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}},
{{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}},
{{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}}};
Также, как и в одномерных массивах, если заявлено данных больше, чем указано при инициализации, то оставшиеся заполняются нулями. Например, единичная матрица 3 на 3
int zero3[3][3] = {{1}, {0, 1}, {0, 0, 1}};
Из того, что многомерный массив является одномерным по структуре, вытекают некоторые интересные свойства. Например, доступ до элемента может быть осуществлён через его порядковый номер
a[i][j] === a[0][i*число столбцов + j] и т.д.
