- •Материалы для подоговки к экзамену по дисциплине «основы программировния»
- •Тема №1 Основные понятия
- •Способы записи алгоритма
- •Тема №2 Переменные
- •Типы переменных
- •Типы с плавающей точкой
- •Переполнение переменных
- •Постфиксное обозначение типа
- •Шестнадцатеричный и восьмеричный формат
- •Экспоненциальная форма представления чисел
- •Объявление переменных
- •Начальное значение переменной
- •Область видимости переменной
- •Тема №3 Оператор присваивания
- •Ввод-вывод Форматированный вывод
- •Форматированный ввод
- •Непечатные символы
- •Тема №4 Ветвления и логические операторы
- •Оператор Switch
- •Логические операторы
- •Логическое отрицание
- •Логическое и
- •Логическое или
- •Пример: закон де-Моргана.
- •Порядок выполнения логических операторов
- •Тема №5 Циклы
- •Цикл с предусловием
- •Циклы с постусловием
- •Цикл for
- •Вложенные циклы
- •Тема №6 Одномерные массивы
- •Начальная инициализация массива.
- •Размер массива
- •Переполнение массива
- •Пример с одномерным массивом
- •Многомерные статические массивы
- •Пример с многомерным массивом
- •Тема №7 Строки в си. Введение
- •Чтение строк
- •Указатели
- •Определение
- •Арифметика указателей
- •Указатель на указатель
- •Указатели и приведение типов
- •Null pointer - нулевой указатель
- •Пример работы с указателями
- •Тема №8 Указатели и массивы
- •Многомерные массивы и указатели на многомерные массивы
- •Определение макросов
- •Тема №9 Тернарный оператор и оператор запятая
- •Оператор запятая.
- •Сегментация приложения на си
- •Тема №10 Динамическое выделение памяти
- •Освобождение памяти с помощью free
- •Работа с двумерными и многомерными массивами
- •Тема №11 Параметры командной строки
- •Функции
- •Параметры и аргументы
- •Передача аргументов По значению
- •По указателю (ссылке)
- •Передача массива в качестве аргумента
- •Тема №12 Битовые операции
- •Операции побитового сдвига
- •Примеры
- •Вопросы к экзамену по дисциплине «Основы программирования»
Циклы с постусловием
Цикл с постусловием отличается от цикла while тем, что условие в нём проверяется после выполнения цикла, то есть этот цикл будет повторён как минимум один раз (в отличие от цикла while, который может вообще не выполняться). Синтаксис цикла
do {
тело цикла
} while(условие);
Предыдущий пример с использованием цикла do будет выглядеть как
int i = 0;
do {
printf("%d\n", i);
i++;
} while(i < 10);
Давайте рассмотрим пример использования цикла с постусловием и предусловием. Пусть нам необходимо проинтегрировать функцию.
Интеграл - это сумма бесконечно малых. Мы можем представить интеграл как сумму, а бесконечно малые значения просто заменить маленькими значениями.
Мы на самом деле разбиваем площадь под графиком функции одного аргумента на множество прямоугольников, где высота прямоугольника - это значение функции в точке, а ширина - это наш шаг. Сложив площади всех прямоугольников, мы тем самым получим значение интеграла с некоторой погрешностью.
Пусть искомой функцией будет x2. Нам понадобятся следующие переменные.
Во-первых, аккумулятор sum для хранения интеграла.
Во-вторых, левая и правая границы a и b.
В третьих - шаг h.
Также нам понадобится текущее значение аргумента функции x.
Для нахождения интеграла необходимо пройти от a до b с некоторым шагом h, и прибавлять к сумме площадь прямоугольника со сторонами f(x) и h.
#include<conio.h>
#include<stdio.h>
int main() {
double sum = 0.0;
double a = 0.0;
double b = 1.0;
double h = 0.01;
double x = a;
while (x < b) {
sum += x*x * h;
x += h;
}
printf("%.3f", sum);
getch();
}
Программа выводит 0.328.
Решение
1/3 ≈ 0.333
Если посмотреть на график функции, то видно, что каждый раз мы находим значение функции в левой точке. Поэтому такой метод численного интегрирования называют методом левых прямоугольников. Аналогично, можно взять правое значение. Тогда это будет метод правых прямоугольников.
while (x < b) {
x += h;
sum += x*x * h;
}
Сумма в этом случае будет равна 0.338. Метод левых и правых прямоугольников не очень точен. Мы фактически аппроксимировали (приблизили) гладкий график монотонно возрастающей функции гистограммой. Если немного подумать, то аппроксимацию можно проводить не только суммируя прямоугольники, но и суммируя трапеции.
Приближение с помощью трапеций на самом деле является кусочной аппроксимацией кривыми первого порядка (ax+b). Мы соединяем точки на графике с помощью отрезков. Можно усложнить, соединяя точки не отрезками, а кусками параболы, тогда это будет метод Симпсона. Если ещё усложнить, то придём к сплайн интерполяции, но это уже другой, очень долгий разговор.
Вернёмся к теме нашей лекции. Рассмотрим 4 цикла.
int i = 0;
while ( i++ < 3 ) {
printf("%d ", i);
}
int i = 0;
while ( ++i < 3 ) {
printf("%d ", i);
}
int i = 0;
do {
printf("%d ", i);
} while(i++ < 3);
int i = 0;
do {
printf("%d ", i);
} while(++i < 3);
Если выполнить эти примеры, то будет видно, что циклы выполняются от двух, до четырёх раз. На это стоит обратить внимание, потому что неверное изменение счётчика цикла часто приводит к ошибкам.
break
Часто случается, что нам необходимо выйти из цикла, не дожидаясь, пока будет поднят какой-то флаг, или значение переменной изменится. Для этих целей служит оператор break, который заставляет программу выйти из текущего цикла.
Давайте решим простую задачу. Пользователь вводит числа до тех пор, пока не будет введено число 0, после этого выводит самое большое из введённых. Здесь есть одна загвоздка. Сколько чисел введёт пользователь не известно. Поэтому мы создадим бесконечный цикл, а выходить из него будем с помощью оператора break. Внутри цикла мы будем получать от пользователя данные и выбирать максимальное число.
#include<conio.h>
#include<stdio.h>
int main() {
int num = 0;
int max = num;
printf("To quit, enter 0\n");
/*бесконечный цикл*/
while (1) {
printf("Please, enter number: ");
scanf("%d", &num);
/*условие выхода из цикла*/
if (num == 0) {
break;
}
if (num > max) {
max = num;
}
}
printf("max number was %d", max);
getch();
}
Напомню, что в си нет специального булевого типа. Вместо него используются числа. Ноль - это ложь, все остальные значения – это истина. Цикл while(1) будет выполняться бесконечно. Единственной точкой выхода из него является условие
if (num == 0)
В этом случае мы выходим из цикла с помощью break; Для начала в качестве максимального задаём 0. Пользователь вводит число, после чего мы проверяем, ноль это или нет. Если это не ноль, то сравниваем его с текущим максимальным.
Бесконечные циклы используются достаточно часто, так как не всегда заранее известны входные данные, либо они могут меняться во время работы программы.
Когда нам необходимо пропустить тело цикла, но при этом продолжить выполнение цикла, используется оператор continue. Простой пример: пользователь вводит десять чисел. Найти сумму всех положительных чисел, которые он ввёл.
#include<conio.h>
#include<stdio.h>
int main() {
int i = 0;
int positiveCnt = 0;
float sum = 0.0f;
float input;
printf("Enter 10 numbers\n");
while (i < 10) {
i++;
printf("%2d: ", i);
scanf("%f", &input);
if (input <= 0.0) {
continue;
}
sum += input;
positiveCnt++;
}
printf("Sum of %d positive numbers = %f", positiveCnt, sum);
getch();
}
Пример кажется несколько притянутым за уши, хотя в общем он отражает смысл оператора continue. В этом примере переменная positiveCnt является счётчиком положительных чисел, sum сумма, а input - временная переменная для ввода чисел.
Вот ещё один пример. Необходимо, чтобы пользователь ввёл целое число больше нуля и меньше 100. Пока необходимое число не будет введено, программа будет продолжать опрос.
do {
printf("Please, enter number: ");
scanf("%d", &n);
if (n < 0 || n>100) {
printf("bad number, try again\n");
continue;
} else {
break;
}
} while (1);
