- •Материалы для подоговки к экзамену по дисциплине «основы программировния»
- •Тема №1 Основные понятия
- •Способы записи алгоритма
- •Тема №2 Переменные
- •Типы переменных
- •Типы с плавающей точкой
- •Переполнение переменных
- •Постфиксное обозначение типа
- •Шестнадцатеричный и восьмеричный формат
- •Экспоненциальная форма представления чисел
- •Объявление переменных
- •Начальное значение переменной
- •Область видимости переменной
- •Тема №3 Оператор присваивания
- •Ввод-вывод Форматированный вывод
- •Форматированный ввод
- •Непечатные символы
- •Тема №4 Ветвления и логические операторы
- •Оператор Switch
- •Логические операторы
- •Логическое отрицание
- •Логическое и
- •Логическое или
- •Пример: закон де-Моргана.
- •Порядок выполнения логических операторов
- •Тема №5 Циклы
- •Цикл с предусловием
- •Циклы с постусловием
- •Цикл for
- •Вложенные циклы
- •Тема №6 Одномерные массивы
- •Начальная инициализация массива.
- •Размер массива
- •Переполнение массива
- •Пример с одномерным массивом
- •Многомерные статические массивы
- •Пример с многомерным массивом
- •Тема №7 Строки в си. Введение
- •Чтение строк
- •Указатели
- •Определение
- •Арифметика указателей
- •Указатель на указатель
- •Указатели и приведение типов
- •Null pointer - нулевой указатель
- •Пример работы с указателями
- •Тема №8 Указатели и массивы
- •Многомерные массивы и указатели на многомерные массивы
- •Определение макросов
- •Тема №9 Тернарный оператор и оператор запятая
- •Оператор запятая.
- •Сегментация приложения на си
- •Тема №10 Динамическое выделение памяти
- •Освобождение памяти с помощью free
- •Работа с двумерными и многомерными массивами
- •Тема №11 Параметры командной строки
- •Функции
- •Параметры и аргументы
- •Передача аргументов По значению
- •По указателю (ссылке)
- •Передача массива в качестве аргумента
- •Тема №12 Битовые операции
- •Операции побитового сдвига
- •Примеры
- •Вопросы к экзамену по дисциплине «Основы программирования»
Определение макросов
Перед тем как программа будет скомпилирована (или не будет, если найдены ошибки), текст программы обрабатывается препроцессором. Препроцессор позволяет изменять текст программы, используя специальные директивы.
Директива #define определяет новый макрос. Макрос, или макроподстановка, будет заменена в коде программы своим телом. Например, мы часто пользовались макросом
#define SIZE 20
и после этого использовали SIZE вместо размера массива.
Макрос может иметь любое допустимое имя и обычно его пишут прописными буквами для того, чтобы отличать от переменных и констант.
#define BREAK_WORD "end"
Макрос подставляется непосредственно в текст вашей программы. То есть, если у вас был код
#include <conio.h>
#include <stdio.h>
#define LENGTH 128
void main() {
char buffer[LENGTH];
scanf("%127s", buffer);
printf("%s", buffer);
getch();
}
то он будет заменён на код
#include <conio.h>
#include <stdio.h>
void main() {
char buffer[128];
scanf("%127s", buffer);
printf("%s", buffer);
getch();
}
Иными словами, макроподстановка - это просто подмена одного куска текста на другой.
Макросы могут иметь аргументы.
#define MAX (a, b) a > b ? a: b
Например
#include <conio.h>
#include <stdio.h>
#define MAX(x, y) x > y ? x: y
void main() {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
printf("max number is %d", MAX(a, b));
getch();
}
Несмотря на то, что этот код работает, в нём есть ошибки. Макроподстановка – это именно подстановка:
#include <conio.h>
#include <stdio.h>
#define MAX(x, y) x > y ? x: y
void main() {
int a = 10;
int b = 10;
printf("max number is %d\n", MAX(a++, b++));
printf("a = %d\n", a);
printf("b = %d\n", b);
getch();
}
Будет выведено
max number is 11
a = 11
b = 12
Это связано с тем, что код будет подменён следующим образом
("max number is %d\n", a++ > b++ ? a++: b++);
В данном случае возвращаемое значение будет ещё раз инкрементировано.
Теперь рассмотрим макрос.
#include <conio.h>
#include <stdio.h>
#define SPHERE_VOLUME(r) 4.18879020 * (r) * (r) * (r)
void main() {
float halfA = 10.f, halfB = 20.f;
printf("Volume of sphere is %.3f", SPHERE_VOLUME(halfA + halfB));
getch();
}
С одной стороны, этот макрос должен делать программу быстрее, если заменить им вызов функции. Но на деле работать он будет медленнее. Макрос развернётся в следующий код
4,18879020 * (halfA + halfB) * (halfA + halfB) * (halfA + halfB)
итого, три раза будет вызвано сложение. Вот ещё пример ошибки
#include <conio.h>
#include <stdio.h>
#define MUL(x, y) x * y
void main() {
printf("(2 + 3) * (4 + 5) %d\n", MUL(2 + 3, 4 + 5));
getch();
}
В данном случае будет выведено 19 вместо 45, так как макрос будет раскрыт в выражение
2 + 3 * 4 + 5 == 2 + 12 + 5 == 19
Решением будет следующий макрос:
#include <conio.h>
#include <stdio.h>
#define MUL(x, y) (x) * (y)
void main() {
printf("(2 + 3) * (4 + 5) %d\n", MUL(2 + 3, 4 + 5));
getch();
}
И ещё одна ошибка, которая также встречается очень часто. Давайте напишем макрос, который будет выводить на печать массив. Мы воспользуемся им в сортировке пузырьком, чтобы видеть, как изменяется массив во время сортировки.
#include <conio.h>
#include <stdio.h>
#define DISPLAY_ARRAY(arr, size) \
for (i = 0; i < size; i++) {\
printf("%d ", arr[i]);\
}\
printf("\n");
#define SIZE 10
void main() {
int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int tmp;
char flag, i;
do {
flag = 0;
//Проходим по массиву. Если следующий элемент больше предыдущего, то
//меняем их местами и по новой проверяем массив
for (i = 1; i < SIZE; i++) {
if (a[i] > a[i - 1]) {
tmp = a[i];
a[i] = a[i - 1];
a[i - 1] = tmp;
flag = 1;
}
DISPLAY_ARRAY(a, SIZE);
}
} while(flag);
getch();
}
Этот пример работать не будет. Дело в том, что он использует переменную i, которая уже занята. Для корректной работы необходимо локализовать переменную. Для этого тело макроса нужно обернуть фигурными скобками и внутри задать переменную
#include <conio.h>
#include <stdio.h>
#define DISPLAY_ARRAY(arr, size) {\
int i;\
for (i = 0; i < size; i++) {\
printf("%d ", arr[i]);\
}\
printf("\n");\
}
#define SIZE 10
void main() {
int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int tmp;
char flag, i;
do {
flag = 0;
//Проходим по массиву. Если следующий элемент больше предыдущего, то
//меняем их местами и по новой проверяем массив
for (i = 1; i < SIZE; i++) {
if (a[i] > a[i - 1]) {
tmp = a[i];
a[i] = a[i - 1];
a[i - 1] = tmp;
flag = 1;
}
DISPLAY_ARRAY(a, SIZE);
}
} while(flag);
getch();
}
Да, кстати, заметьте, как пишется многострочный макрос - каждая строка оканчивается обратным слешем.
Поэтому, при работе с параметризованными макросами
Всегда окружайте параметры круглыми скобками
Старайтесь передавать параметры явно и не передавать выражения, которые должны быть вычислены. Это будет приводить к неявным побочным эффектам и замедлению работы за счёт повторного выполнения кода.
Тело сложного макроса заносите под фигурные скобки.
