Программирование на языке Си. Билеты и ответы
.pdfБИЛЕТ №7.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: ПОДПРОГРАММЫ, ПРАВИЛА ПЕРЕДАЧИ ПАРАМЕТРОВ.
ПОДПРОГРАММЫ В СИ Функция — это самостоятельная единица программы, которая спроектирована для реализации конкретной
подзадачи.
Подпрограмма — поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы.
Функция является подпрограммой, которая может содержаться в основной программе, а может быть создана отдельно (в библиотеке). Каждая функция выполняет в программе определенные действия.
«Процедуры» в СИ — функции, не возвращающие значение (тип — void, что переводится как «пустота»).
Функция
1.Описание функции (сигнатура/прототип функции) определяет правила использования функции.
Описание необязательно, если стоит перед функцией main().
<type> <name> (<parameters>);
Пример: int max (int, int);
2.Определение функции (семантика функции) представляет собой описание инструкций, выполняемых функцией (тело функции).
<type> <name> (<parameters>) {<body>}
Пример:
int max (int a, int b) { return (a > b) ? a : b;
}
3.Вызов функции.
<name>(<parameters>);
Пример: max(4, 5); /// 5
ФАКТИЧЕСКИЕ И ФОРМАЛЬНЫЕ ПАРАМЕТРЫ Фактические параметры — параметры, указываемые при вызове подпрограммы. Формальные параметры — параметры, указываемые при описании подпрограммы.
Т. е. фактические параметры — те, что передаются в функцию, а формальные параметры — те, что находятся в описании (заголовке) функции.
Список фактических параметров подпрограммы должен совпадать по количеству и типам со списком формальных параметров.
ПЕРЕДАЧА ПАРАМЕТРОВ В ФУНКЦИЮ
В языке СИ точного разделения на параметры-значения и параметры-переменные нет (в ЯП Pascal
есть разделение).
Однако знать, что это и как это понимается в языке СИ, надо.
Параметры-значения используются только для передачи (копирования) в функцию исходных данных из основной программы.
Параметры-переменные используются для того, чтобы изменять исходные данные основной программы в функции.
Различные способы передачи параметров в СИ позволяют организовать и тот, и другой тип передачи, но в немного другом понимании.
Передача параметров в функцию
Передача по значению |
Передача по указателю |
Передача по ссылке |
|
(C, C++) |
(C, C++) |
(только C++) |
|
|
|
|
|
|
#include <stdio.h> |
#include <cstdio> /// аналог <stdio.h> |
|
#include <stdio.h> |
void swap (int *a, int *b){ |
void swap (int &a, int &b){ |
|
int c; |
int c; |
||
int max (int a, int b){ |
|||
c = *a; /// но не c = a! |
c = a; |
||
return (a > b) ? a : b; |
|||
*a = *b; /// но не a = b! |
a = b; |
||
} |
|||
*b = c; /// но не b = c! |
b = c; |
||
int main() |
|||
} |
} |
||
{ |
|||
int main() |
int main() |
||
int a = 3, b = 5, c; |
|||
{ |
{ |
||
c = max(a, b); |
|||
int a = 3, b = 5; |
int a = 3, b = 5; |
||
/// Максимум |
|||
swap(&a, &b); |
swap(a, b); |
||
printf("max: %d\n", c); |
|||
/// Меняем местами |
/// Тоже меняем местами |
||
return 0; |
|||
printf("%d %d\n", a, b); |
printf("%d %d\n", a, b); |
||
} |
|||
return 0; |
return 0; |
||
|
|||
|
} |
} |
|
Следует знать то, что в СИ имя массива без индекса обозначает указатель на первый (нулевой по |
|||
индексу) элемент этого массива. |
|
ЗАДАЧА: НАПИСАТЬ ФУНКЦИЮ, МЕНЯЮЩУЮ МЕСТАМИ ПОСЛЕДНИЙ И ПРЕДПОСЛЕДНИЙ СТОЛБЕЦ ДВУМЕРНОГО МАССИВА. ПРОДЕМОНСТРИРОВАТЬ ЕЁ ИСПОЛЬЗОВАНИЕ В ПРОГРАММЕ.
СИ
#include <stdio.h>
///Функция, меняющая местами последний и предпоследний столбец двумерного массива
///arr — массив, n — количество строк, m — количество столбцов
///Сложность алгоритма: T(n) = O(n)
void bilet7(double *arr, int n, int m){ int i; double d;
int wm1 = m - 1; int wm2 = m - 2; for (i = 0; i < n; i++){
d = arr[i*m + wm1];
arr[i*m + wm1] = arr[i*m + wm2]; arr[i*m + wm2] = d;
}
}
int main()
{
int i, j; /// Счетчики циклов
double arr[3][4] = {{-1.5, 3.9, 4.2, 41.0}, {-5.4, -1.0, 56.6, 42.2}, {-3.8, 1.9, 6.2, 96.8}};
/// Массив размером 3 x 4 (3 строки, 4 столбца) bilet7(&arr[0][0], 3, 4); /// Обработка
for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++)
printf("%lf ", arr[i][j]); /// Вывод printf("\n");
}
return 0;
}
БИЛЕТ №8.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: СТАТИЧЕСКИЕ И АВТОМАТИЧЕСКИЕ ПЕРЕМЕННЫЕ, КОНСТАНТЫ. ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ.
СТАТИЧЕСКИЕ И АВТОМАТИЧЕСКИЕ ПЕРЕМЕННЫЕ
static. Статические переменные — это локальные переменные, которые создаются при первом входе в подпрограмму и не уничтожаются при выходе из неё.
Статическая переменная, описанная вне любой функции, становится внешней статической. Разница между внешней переменной и внешней статической переменной заключается в области их действия. Обычная внешняя переменная может использоваться функциями в любом файле, а внешняя статическая переменная может использоваться только функциями того файла, в котором объявлена, причем после определения переменной.
auto. Автоматические переменные — это локальные переменные, которые создаются каждый раз при входе в подпрограмму и уничтожаются при выходе из неё.
Обратите внимание на то, что все создаваемые переменные по умолчанию — автоматические.
Статические переменные |
|
Автоматические переменные |
static |
|
auto |
#include <stdio.h> |
|
#include <stdio.h> |
int main() |
|
int main() |
{ |
|
{ |
int i; |
|
int i; |
for (i = 0; i < 5; i++) { |
|
for (i = 0; i < 5; i++) { |
static int n = 0; |
|
int n = 0; /// то же, что и "auto int n = 0" |
printf("%d ", ++n); /// 1 2 3 4 5 |
|
printf("%d ", ++n); /// 1 1 1 1 1 |
} |
|
} |
return 0; |
|
return 0; |
} |
|
} |
|
КОНСТАНТЫ |
1.Ключевое слово const.
Использование: const <type> <name> = <value>;
2.Директива препроцессора #define.
Использование: #define <name> <value>
Преимущества использования const:
Явное указание типа величины.
Имеется возможность создавать константы с различной областью видимости.
|
const |
|
#define |
#include <stdio.h> |
#include <stdio.h> |
||
int main() |
|
#define n 5 |
|
{ |
|
int main() |
|
int i; |
|
{ |
|
const int n = 5; |
int i; |
|
|
for (i |
= 1; i <= n; i++) { |
for (i |
= 1; i <= n; i++) { |
printf("%d ", i); /// 1 2 3 4 5 |
printf("%d ", i); /// 1 2 3 4 5 |
||
} |
|
} |
|
return |
0; |
return |
0; |
} |
|
} |
|
ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ
Глобальные объекты — объекты, объявление которых дано вне функции (вне main и других). Они доступны (видимы) во всем файле, в котором они объявлены. В течение всего времени выполнения программы с глобальным объектом ассоциирована некоторая ячейка памяти. Например, можно объявить int a = 4; вне функции main.
Локальные объекты — объекты, объявление которых дано внутри блока или функции. Эти объекты доступны только внутри того блока, в котором они объявлены. Объектам с локальным временем жизни выделяется новая ячейка памяти каждый раз при осуществлении описания внутри блока. Когда выполнение блока завершается, память, выделенная под локальный объект, освобождается, и объект теряет своё значение.
Модификатор extern предназначен для использования в одном программном модуле объекта, который объявлен в другом программном модуле. Пример работы модификатора приведен в 17 билете.
Модификатор register предназначен для того, чтобы поместить переменную в один из регистров общего назначения центрального процессора при наличии свободного регистра. Благодаря этому повышается скорость
работы с данными, однако получить адрес такой переменной не получится, так как она хранится не в оперативной памяти (ОЗУ), а в регистре процессора (ЦП). Это необходимо для создания управляющих
программ, где требуется высокая скорость обработки данных. Пример: register int a = 4. Дальше работаем почти как с обычной переменной.
ЗАДАЧА: НАПИСАТЬ ФУНКЦИЮ, ВОЗВРАЩАЮЩУЮ СУММУ ЭЛЕМЕНТОВ ОДНОМЕРНОГО МАССИВА, БЕЗ УЧЕТА ВТОРОГО И ПРЕДПОСЛЕДНЕГО. ПРОДЕМОНСТРИРОВАТЬ ЕЁ ИСПОЛЬЗОВАНИЕ В ПРОГРАММЕ.
СИ
#include <stdio.h>
///Функция, возвращающая сумму элементов одномерного массива, без учета второго и предпоследнего
///arr — массив, n — количество строк в массиве
///Сложность алгоритма: T(n) = O(n)
double bilet8(double *arr, int n){ int i, wn = n - 2;
double sum = arr[0]; /// Первый элемент for (i = 2; i < wn; i++)
sum += arr[i]; /// Между вторым и предпоследним sum += arr[n-1]; /// Последний элемент
return sum;
}
int main()
{
double arr[7] = {-1.5, 3.9, 4.2, 0.3, 1.5, 41.0, 6.1}; /// 7 элементов printf("%lf\n", bilet8(arr, 7)); /// 10.600000
return 0;
}
БИЛЕТ №9.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: ОПЕРАТОРЫ RETURN, BREAK, CONTINUE.
ОПЕРАТОР RETURN
Оператор return (возврат) завершает выполнение функции, в которой он задан, и возвращает управление в вызывающую функцию, в точку, непосредственно следующую за вызовом.
ОПЕРАТОР BREAK
Оператор break (разрыв) вызывает немедленный выход из циклов, организуемых с помощью операторов for, while, do-while, а также прекращение оператора switch.
ОПЕРАТОР CONTINUE
Оператор continue (продолжить) тоже предназначен для прерывания циклического процесса, организуемого операторами for, while, do-while. Но в отличии от оператора break, он не прекращает дальнейшее выполнение цикла, а только немедленно переходит к следующей итерации того цикла, в теле которого он оказался.
ПРИМЕРЫ
|
return |
break |
continue |
#include <stdio.h> |
#include <stdio.h> |
#include <stdio.h> |
|
int main() |
|
int main() |
int main() |
{ |
|
{ |
{ |
int i; |
|
int i; |
int i; |
for (i |
= 1; i <= 10; i++) { |
for (i = 1; i <= 10; i++) { |
for (i = 1; i <= 10; i++) { |
printf("%d ", i); |
printf("%d ", i); |
if (i % 5 == 0) |
|
/// 1 2 3 4 5 |
/// 1 2 3 4 5 |
continue; |
|
if |
(i % 5 == 0) |
if (i % 5 == 0) |
printf("%d ", i); |
|
return 0; |
break; |
/// 1 2 3 4 6 7 8 9 |
} |
|
} |
} |
printf("I = %d", i); |
printf("I = %d", i); |
printf("I = %d", i); |
|
/// не |
выведется |
/// I = 5 |
/// I = 11 |
return |
0; |
return 0; |
return 0; |
} |
|
} |
} |
ЗАДАЧА: НАПИСАТЬ ФУНКЦИЮ, ВОЗВРАЩАЮЩУЮ ПРОИЗВЕДЕНИЕ ПОСЛЕДНИХ 5-ТИ ЭЛЕМЕНТОВ ОДНОМЕРНОГО МАССИВА. ПРОДЕМОНСТРИРОВАТЬ ЕЁ ИСПОЛЬЗОВАНИЕ В ПРОГРАММЕ.
СИ
#include <stdio.h>
///Функция, возвращающая произведение последних 5-ти элементов одномерного массива
///arr — массив, n — количество строк в массиве
///Сложность алгоритма: T(n) = O(n)
double bilet9(double *arr, int n){ int i, wn = n - 6;
double p = arr[n-1]; /// Последний элемент for (i = n - 2; i > wn; i--)
p *= arr[i]; return p;
}
int main()
{
double arr[7] = {-1.5, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0}; /// 7 элементов printf("%lf\n", bilet9(arr, 7)); /// 32.000000
return 0;
}
БИЛЕТ №10.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: ОБРАБОТКА ОДНОМЕРНЫХ МАССИВОВ.
МАССИВ Массив — это непрерывный участок памяти, содержащий последовательность объектов одинакового типа,
обозначаемый одним именем.
<type> <name> [<dimension>] = {<value1>, <value2>…}; // (dimension — размерность)
Указывать размерность необязательно, если указаны значения <value> в фигурных скобках. Указать размерность необходимо, если значения <value> в скобках не указаны.
Элемент массива (значение элемента массива) – значение, хранящееся в определенной ячейке памяти, расположенной в пределах массива, а также адрес этой ячейки памяти.
Каждый элемент массива характеризуется:
Адресом элемента — адресом начальной ячейки памяти, в которой расположен этот элемент;
Индексом элемента (порядковым номером элемента в массиве);
Значением элемента.
Адрес массива — адрес начального элемента массива.
Имя массива — идентификатор, используемый для обращения к элементам массива. Размер массива — количество элементов массива.
Размер элемента — количество байт, занимаемых одним элементом массива.
ПЕРЕДАЧА МАССИВА В ФУНКЦИЮ. ВВОД ДАННЫХ, ОБРАБОТКА ДАННЫХ, ВЫВОД ДАННЫХ
Главная функция |
Ввод данных |
#define N 5 |
|
int main() |
|
{ |
void input_array(int * arr, int n){ |
int arr[N]; |
int i; |
input_array(arr, N); |
for (i = 0; i < n; i++) |
array_processing(arr, N); |
scanf("%d", &arr[i]); |
output_array(arr, N); |
} |
return 0; |
|
} |
|