Программирование на языке Си. Билеты и ответы
.pdfБИЛЕТ №16.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: АРГУМЕНТЫ, ПЕРЕДАВАЕМЫЕ ФУНКЦИИ ПО УМОЛЧАНИЮ.
При обращении к функции, можно опускать некоторые её аргументы. Аргументы по умолчанию должны быть заданы в прототипе функции, если она идет после main(), иначе при описании.
Если в функции несколько параметров, то параметры, которые опускаются должны находиться правее остальных. Таким образом, если опускается самый первый параметр функции, то все остальные параметры тоже должны быть опущены. Если опускается какой-то другой параметр, то все параметры, расположенные перед ним, могут не опускаться, но параметры, расположенные после него, должны быть опущены.
Пример на языке СИ
///Программа, вычисляющая расстояние между двумя точками
///A(x0, y0) и B(xk, yk) плоскости XY
#include <iostream>
#include <cmath> using namespace std;
/// Описание (сигнатура/прототип) функции
float sum(float, float, float x0 = 0, float y0 = 0);
/// Определение функции (семантика функции)
float sum(float xk, float yk, float x0, float y0){
return sqrtf(powf((xk - x0), 2) + powf((yk - y0), 2));
}
int main()
{
int x1 = 3, y1 = 4;
cout << sum(x1, y1) << endl; /// 5 cout << sum(x1, y1, 3) << endl; /// 4
cout << sum(x1, y1, 4, 3) << endl; /// корень из 2 return 0;
}
ЗАДАЧА: НАПИСАТЬ ФУНКЦИЮ, ВОЗВРАЩАЮЩУЮ НОМЕР ПРЕДПОСЛЕДНЕГО ОТРИЦАТЕЛЬНОГО ЭЛЕМЕНТА ОДНОМЕРНОГО МАССИВА. ПРОДЕМОНСТРИРОВАТЬ ЕЁ ИСПОЛЬЗОВАНИЕ В ПРОГРАММЕ.
Ответ на практическое задание билета №2 такой же.
СИ
#include <stdio.h>
///Функция, возвращающая номер (индекс) предпоследнего отрицательного элемента одномерного массива
///Если такого элемента в массиве нет, то возвращается значение -1
///arr — массив, n — количество элементов в массиве
///Сложность алгоритма: T(n) = O(n)
int bilet2(double *arr, int n){
int i, j = 0, k = -1; /// k — позиция искомого элемента
for (i = n - 1; i >= 0; i--) /// Двигаемся от конца к началу
if (arr[i] < 0) { /// Если значение очередного элемента < 0, то
if (j == 0) /// Если первого отрицательного элемента ещё не было найдено, то j = 1; /// Мы нашли первый отрицательный элемент
else if (j == 1) { /// Если первый отрицательный был найден ранее, то
k = i; /// Мы нашли второй отрицательный элемент, который является искомым break; /// Смысла продолжать поиск нет, поэтому выход из цикла
}
}
return k; /// Возвращаем найденную позицию (индекс) элемента
}
int main()
{
double arr[] = {1.5, 3.9, 4.2, 5.0, -6.7}; /// Массив с 5-тью элементами printf("%d\n", bilet2(arr, 5)); /// Вызов функции и вывод результата на экран: –1 return 0;
}
БИЛЕТ №17.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: ПРОЕКТЫ.
Процесс создания программы из исходных файлов называется сборкой (building). Сборка включает в себя две стадии: компиляцию (compiling) и связывание (linking, другой перевод — компоновка).
Во время компиляции происходит создание объектных файлов (обычно с расширением .obj) из исходных (с расширением .cpp или .c) и заголовочных (с расширением .h).
После того как скомпилировались объектные файлы в дело вступает компоновщик и связывает объектные и библиотечные файлы (cо стандартным расширением .lib). В конце сборки, если ни компилятор, ни компоновщик не выдали ошибок, мы получим от компоновщика исполняемый файл (с расширением .exe).
NetBeans-проекты состоят из следующих типов файлов:
1.Исходные файлы (файлы .cpp, .c);
2.Файлы заголовков (файлы .h);
3.Файлы ресурсов (могут быть различные расширения);
4.Файлы тестов (файлы .cpp, .c).
5.Важные файлы (могут быть различные расширения).
Пример проекта
main.c |
funcLib.h |
funcLib.c |
#include <stdio.h> |
|
|
#include "funcLib.h" |
/// #include "funcLib.c" |
|
/// двойные кавычки, т. к. находится в папке проекта |
/// ^ верхняя строчка не |
float c; /// глобальная |
extern float c; /// берем глобальную переменную |
требуется |
переменная |
int main() |
/// т. к. в проекте все |
int sum_Int(int a, int b) { |
{ |
нужные файлы уже лежат |
return a + b; |
int a = 12, b = 45; |
/// IDE об этом знает |
} |
c = 1.1; /// используем её |
int sum_Int(int a, int |
|
float d = 1.3; |
b); |
float sum_Float(float a, float b) |
printf("%d %f\n", sum_Int(a, b), sum_Float(c, d)); |
|
{ |
/// 57 2.4 |
float sum_Float(float a, |
return a + b; |
return 0; |
float b); |
} |
} |
|
|
ЗАДАЧА: НАПИСАТЬ ФУНКЦИЮ, ВОЗВРАЩАЮЩУЮ ЧИСЛО ЭЛЕМЕНТОВ ОДНОМЕРНОГО МАССИВА, КРАТНЫХ 2. ПРОДЕМОНСТРИРОВАТЬ ЕЁ ИСПОЛЬЗОВАНИЕ В ПРОГРАММЕ.
Ответ на практическое задание билета №3 такой же.
СИ
#include <stdio.h>
///Функция, возвращающая число элементов одномерного массива, кратных 2
///arr — массив, n — количество элементов в массиве
///Сложность алгоритма: T(n) = O(n)
int bilet3(int *arr, int n){ int i, k = 0;
for (i = 0; i < n; i++) /// От начала к концу
if ((arr[i] % 2) == 0) /// Если очередной элемент массива делится нацело на 2, то k++; /// Увеличиваем счетчик
return k; /// Возвращаем количество элементов, кратных 2
}
int main()
{
int arr[] = {-1, 3, 4, -5, -6}; /// Массив с 5-тью элементами
printf("%d\n", bilet3(arr, 5)); /// Вызов функции и вывод результата на экран: 2 return 0;
}
БИЛЕТ №18.
ТЕОРЕТИЧЕСКИЙ ВОПРОС: ПРЕПРОЦЕССОР.
Препроцессор — это компьютерная программа, принимающая данные на входе и выдающая данные, предназначенные для входа другой программы (например, компилятора). О данных на выходе препроцессора говорят, что они находятся в препроцессированной форме, пригодной для обработки последующими программами (компилятор).
Препроцессор С/С++ (англ. pre processor, предобработчик) — программа, подготавливающая код программы на языке C/C++ к компиляции.
Препроцессор СИ удаляет из кода комментарии, преобразует код в соответствии с макросами и выполняет иные директивы, начинающиеся с символа «#» (такие как #include, #define, разнообразные директивы типа #pragma).
Этапы работы препроцессора СИ:
1.Лексический анализ кода C/C++ (синтаксический анализ не выполняется);
2.Обработка директив;
3.Выполнение подстановок.
Директивой (командной строкой) препроцессора называется строка в исходном коде, имеющая следующий формат:
#<keyword> <parameters>
Ключевое |
Параметры |
|
Пример |
|
слово |
Описание |
|
||
(parameters) |
|
|||
(keyword) |
|
|
||
|
|
|
||
|
|
|
Константа препроцессора: |
|
|
|
Создание нового |
#define A 5 |
|
|
|
Макрос препроцессора: |
||
|
|
определения <name> со |
||
|
<name> <value> |
#define max( a, b ) ( (a) > (b) ? (a) : (b) ) |
||
#define |
значением <value>. |
|||
or others |
Вызов макроса: int z = max( x, y ); |
|||
|
Играет роль константы или |
|||
|
|
Оператор #: |
||
|
|
макроса препроцессора. |
||
|
|
Оператор # перед параметром макроса обрамляет |
||
|
|
|
||
|
|
|
его в двойные кавычки. |
Пример:
#define make_str( bar ) # bar
…
printf( make_str( 42 ) );
Препроцессор преобразует в: printf( "42" );
Оператор ##:
Оператор ## в макросах объединяет две лексемы
Пример:
#define MakePosition( x ) x##X, x##Y, x##Width, x##Height
…
int MakePosition( Object );
Препроцессор преобразует в: int ObjectX, ObjectY, ObjectWidth,
ObjectHeight;
Пример:
#define cat( x, y ) х ## у
…
cat( cat( 1, 2 ), 3 );
Препроцессор обращает внимание на внешние скобки,
из-за чего получаем результат обработки: cat(1, 2)3
Ответ не обрадовал. Добавляем:
#define xcat( x, y ) cat( x, y )
Переделываем:
cat( cat( 1, 2 ), 3 ) меняем на xcat( xcat(
1, 2 ), 3 )
Теперь результат:
123
Константы define:
__LINE__ заменяется на номер текущей строки; номер текущей строки может быть переопределен директивой #line; используется для отладки;
__FILE__ заменяется на имя файла; имя файла тоже может быть переопределено с помощью директивы #line;
__DATE__ заменяется на текущую дату (на момент обработки кода препроцессором);
__TIME__ заменяется на текущее время (на момент обработки кода препроцессором);
__TIMESTAMP__ заменяется на текущие дату и время (на момент обработки кода препроцессором); __COUNTER__ заменяется на уникальное число,
начиная от 0; после каждой замены число увеличивается на единицу;
__STDC__ заменяется на 1, если компиляция происходит в соответствии со стандартом языка
C;
__STDC_HOSTED__ определена в C99 и выше; заменяется на 1, если выполнение происходит под управлением ОС.
Ими можно пользоваться (подставлять в вывод функции printf() и др.).
#undef |
<name> |
Препроцессор "забывает" |
#undef A |
|
определение <name> |
||||
|
|
|
||
|
|
Вставка файла. |
|
|
|
|
"name" |
|
|
|
|
Поиск файла выполняется в |
|
|
|
|
текущей папке и папках, |
|
|
|
|
указанных в командной |
|
|
#include |
<name> |
строке компилятора. |
#include <stdio.h> |
|
"name" |
<name> |
#include "funcLib.h" |
||
|
||||
|
|
Поиск файла выполняется в |
|
|
|
|
папках, содержащих файлы |
|
|
|
|
стандартной библиотеки |
|
|
|
|
(пути к этим папкам зависят |
|
|
|
|
от реализации компилятора) |
|
|
|
|
|
#define MAX 100 |
|
#if |
<expression> |
Начало условного блока |
#if MAX == 100 |
|
<command> |
#error MAX==100!!! /// YES |
|||
|
|
|||
|
|
|
#endif |
|
|
|
if defined |
#ifdef A |
|
|
<name> |
Начало "условного блока |
||
#ifdef |
#error A объявлена! |
|||
<command> |
проверки на |
|||
|
#endif |
|||
|
|
существование" |
||
|
|
|
||
|
<name> |
if not defined |
#ifndef A |
|
#ifndef |
Начало "условного блока |
#error Ошибка! A не объявлена! |
||
<command> |
||||
|
проверки на отсутствие" |
#endif |
||
|
|
|||
|
|
|
#if MAX==101 |
|
|
|
|
#error MAX=100!!! |
|
#else |
<command> |
Блок "иначе" |
#else |
|
|
|
|
#define X 200 |
|
|
|
|
#endif |
|
|
|
#define MAX 102 |
|
|
|
|
#if MAX==101 |
|
#elif |
<expression> |
else if |
#error MAX=100!!! |
|
<command> |
Блок "иначе если" |
#elif MAX==102 |
||
|
||||
|
|
|
#define X 202 |
|
|
|
|
#endif |
|
#endif |
— |
Конец условного блока |
См. предыдущие примеры |
|
|
|
|
#include <iostream> |
|
|
|
|
using namespace std; |
|
|
|
|
#line 200 /// Устанавливаем счетчик строк |
|
|
|
Изменяет содержимое |
равным 200 |
|
|
<number> |
псевдопеременных |
int main() /// Эта строка сейчас имеет номер |
|
#line |
__LINE__ и __FILE__ |
200 |
||
<filename> |
||||
|
<filename> — |
{ /// Номер этой строки равен 201 |
||
|
|
|||
|
|
необязательный параметр |
cout << __LINE__; /// Здесь выводится |
|
|
|
|
номер 202 |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
Информационное |
|
|
|
|
сообщение об ошибке. |
|
|
#error |
<message> |
Дает указание компилятору |
См. предыдущие примеры |
|
остановить компиляцию. |
||||
|
|
|
||
|
|
Она используется в |
|
|
|
|
основном для отладки. |
|
|
|
|
Информационное |
#define A 100 |
|
#warning |
<message> |
предупреждающее |
#ifdef A |
|
сообщение. |
#warning A существует |
|||
|
|
|||
|
|
Используется для отладки. |
#endif |
|
|
|
Работа |
|
|
#pragma |
<name> |
директивы #pragma зависит |
— |
|
|
|
от конкретной реализации |
|