Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
КОНСПЕКТЫ ОТВЕТОВ НА ТИПОВЫЕ ВОПРОСЫ К ЭКЗАМЕНУ ПО ПРОГРАММИРОВАНИЮ
№ |
Вопрос |
Краткое изложение |
Подробное изложение |
1 |
Этапы получения исполняемого файла из исходного кода. Опции компилятора и компоновщика. |
|
В итоге должен был бы появиться файл *.i, полученный из *.с.
В действительности первые три этапа выполняются компилятором GNU (MinGW) с помощью одной команды gcc [compiler options] c src_name.c , и если ошибки не будут найдены, в папке, содержащей src_name.c, появится объектный модуль src_name.o (если не указано иное опцией компилятора “-o obj_name.o”).
|
|
|
||
2 |
Функция main. Возвращаемое значение. Аргументы функции main. Внутренняя организация исполняемого файла. Превращение исполняемого файла в процесс. |
|
|
|
Исполняемый файл имеет расширение .exe.
|
3 |
Многофайловая организация проекта. Компиляция и компоновка многофайлового проекта. Каноническое оформление заголовочных файлов. |
|
|
|
|
||
|
|
||
|
|
||
4 и 5 |
Автоматизация сборки проекта, утилита make. Сценарий сборки проекта. Простой сценарий сборки. Использование переменных и комментариев. Сборка программы с разными параметрами компиляции. Автоматические переменные. Шаблонные правила. |
|
|
|
|
||
|
|
6 и 7 |
Указатели, операции над указателями, массивы, адресная арифметика. Указатель void*, указатели на функции |
|
Получение адреса: ptr2_name = ¬_ptr_name; |
|
|
||
|
|
||
8 |
Статические массивы |
|
|
|
|
||
|
|
||
9 |
Динамические массивы |
|
Динамические массивы требуют отдельного выделения динамической памяти в куче.
|
|
№ способа Достоинства Недостатки 1
2
3
|
||
10 |
Строки. Инициализация строковых переменных. Массив символов и указатель на строковый литерал. Ввод/вывод строк. Особенности обработки строк. |
|
|
|
|
||
|
Выход за пределы выделенного буфера строки крайне нежелательный эффект, не отслеживается компилятором и ложится на плечи программиста. Терминирующий нуль при преобразованиях строк необходимо сдвигать, а также обеспечивать его нахождение в буфере Пробег по строке с помощью указателей также должен быть аккуратным, использование вне пределов буфера чревато последствиями. |
11 |
Время жизни, область видимости переменных |
|
|
|
|
||
12 |
Журналирование |
|
Журналирование процесс записи информации о происходящих с каким-то объектом (или в рамках какого-то процесса) событиях в журнал (например, в файл). Этот процесс часто называют также аудитом. Файловую переменную для журнала определяют глобальной и объявляют во всех файлах реализации проекта. Это позволяет вызывать функции записи в файл для журналирования отовсюду. Для записи в журнал можно написать собственные функции, где переменная-указатель на файл с журналом может быть как глобальной, так и статической переменной. |
13 |
Классы памяти |
|
|
14 |
Стек и куча. Последовательность действий при работе с динамической памятью. |
|
|
15 |
Использование аппаратного стека. Стековый кадр. Указатель на локальную переменную. Переполнение буфера. Массивы на стеке. |
|
|
16 |
Функции с переменным числом параметров |
|
Фактические параметры передаются через стек в порядке, обратном их записи в вызове функции. Это позволяет сравнительно легко передавать переменное число параметров в вызываемую функцию. Функции с переменным числом параметров объявляются так: тип_рез-та имя(<непустой список первых параметров>, …) Для прохождения стека с параметрами используют заголовочный файл <stdarg.h>, в котором объявлены:
|
17 |
Структуры |
|
Структура представляет собой одну или несколько переменных (возможно, разного типа), которые объединены под одним именем, при этом каждая переменных занимает своё место в памяти. Это позволяет связать в единое целое различные по типу и значению данные, связанные между собой. Формат определения: struct [tag] {type1 field1; type2 [field2]; …; typeN fieldN; } [variable] = {value1, value2, …, valueN} Тег структуры имя, позволяющее идентифицировать структуру в самых разных частях программы. Его передают в качестве спецификатора типа (вместе с ключевым словом struct) формального параметра. Тег может быть опущен. |
|
Структура расположена в памяти единым дампом. Поля (перечисленные в структуре переменные) расположены чаще всего подряд, в порядке объявления в структуре. Размер структуры равен сумме размеров её полей. Операции над структурами:
|
||
|
Структуры, как правило, занимают сами по себе большой объём памяти, и при передаче в функцию в качестве параметра непосредственно структуры уходит много времени и ресурсов. Кроме того, в этом случае поля исходной структуры не могут быть изменены. Поэтому чаще всего гораздо экономичнее и проще передавать указатель на структуру (как параметр) и возвращать указатель на структуру (в качестве результата). Поля структуры, являющиеся указателями на объекты другого типа, требуют отдельной обработки при копировании структуры (иначе, например, одноимённые поля различных структур укажут на одну и ту же строку (char*), и редактирование этой строки вызовет фактическую потерю данных и возможные ошибки при высвобождении памяти из-под этой строки). При этом хранить char* гораздо эффективнее, чем char[N], так как длина буфера строки может быть изменена и приведена к наиболее выгодному значению, в отличие от постоянного N у массива. Для удобства программиста и сокращения объёма кода можно словосочетание “struct %tag%” заменить на однословное имя через “typedef struct %tag% new_name“ |
||
18 |
Объединения |
|
Объединение представляет собой одну или несколько переменных (возможно, разного типа), которые объединены под одним именем, при этом каждая переменных занимает одно и то же место в памяти, располагаясь по одному и тому же адресу. Формат определения: union [tag] {type1 field1; type2 field2; …; typeN fieldN; } [var_name]; |
|
Поля определения располагаются по одному и тому же адресу (в начале дампа). Размер объединения равен наибольшему размеру его поля. Операции те же, что и над структурами. |
||
|
Объединения, объявленные в программах, применяются нечасто. Как правило, в них содержат информацию, которую надо обрабатывать и выдавать как полностью, так и по частям. НО: регистры процессора общего назначения, пожалуй, самый яркий пример объединений. К примеру, регистр EAX эквивалентен объединению union pseudo_eax {long eax4; short ax2; struct {char al1; char ah1;}parts; }; |
||
31 |
Стандарты языка Си. Основные концепции языка Си. |
|
К середине 1980-х годов расхождения становятся очень серьёзными, и институт ANSI в 1989 году готовит первый формальный и документированный стандарт для создателей компиляторов и стандартных библиотек. Неформальное название стандарта С89. Небольшие правки в этот стандарт годом позже (в 1990 году) внесла ISO (=>C90). Программистам было крайне неудобно соответствовать существенно различавшимся стандартам С89/С90, с одной стороны, и стандартами для Си-подобных языков, с другой. Для приведения к единообразию ISO и ANSI в 1999-2000 годах разработали и внедрили стандарт С99. Множество небезопасных функций и необходимость расширенной поддержки символов Unicode побудили разработать в 2011 году новый стандарт С11, которому, правда, не соответствует ещё большая часть современных компиляторов.
|
19 |
Битовые операции. Битовые поля |
|
|
|
|
||
|
struct имя_структуры { тип имя1: длина; тип имя2: длина; ... тип имяN: длина; }; Битовые поля должны объявляться как целые, unsigned или signed.
|
20 и 21 |
Препроцессор. Макросы. Особенности макросов с параметрами. |
|
#include включение заголовочного файла #define макроопределение #undef прекращение действия макроопределения условные директивы: #if, #ifndef, #ifdef и т. п.; #elif; #endif. Обозначают условную компиляцию #pragma задаёт модель поведения, зависящую от конкретной реализации компилятора. #line изменяет номер текущей строки и имя компилируемого файла. #error выдача диагностического сообщения Правила, справедливые для всех директив:
|
|
|
||
|
|
||
|
Преимущества макросов перед функциями:
Недостатки макросов:
|
||
|
|
22 |
Динамически расширяемые массивы. |
|
После удаления элемента обычно не сокращают длину массива, понимая, что возможно новое пополнение. Также для добавлений и удалений элементов характерны следующие особенности:
|
|
Добавление элемента: int append(struct dyn_array *d, int item) { if (!d->data) { d->data = malloc(INIT_SIZE * sizeof(int)); if (!d->data) return -1; d->allocated = INIT_SIZE; } else if (d->len >= d->allocated) { int *tmp = realloc(d->data, d->allocated * d->step * sizeof(int)); if (!tmp) return -1; d->data = tmp; d->allocated *= d->step; } d->data[d->len] = item; d->len++; return 0; } Удаление элемента: int delete(struct dyn_array *d, int index) { if (index < 0 || index >= d->len) return -1; memmove(d->data + index, d->data + index + 1, (d->len - index - 1) * sizeof(int)); d->len--; return 0; } Плюсы и минусы динамических массивов:
|
||
23 |
Линейный односвязный список. |
|
По сравнению с массивами, списки:
Односвязные списки имеют широкое применение в вычислительных алгоритмах и архитектурах баз данных. |
|
Элемент списка представляет собой структуру вида struct list_el { поле1; [остальные поля;] list_el* next; } Для последнего элемента списка next должен равняться NULL (иначе список будет кольцевым). В программе обязательно хранить адрес головы. Рассмотрим сложности стандартных алгоритмов работы со списком (напиши их самостоятельно): Операция Стекоподобный список (без хранения указателя на последний элемент списка) -- сложность Очередеподобный список (с хранением указателя на последний элемент списка) -- сложность Создание O(1) O(1) Добавление в начало O(1) O(1) Добавление в конец O(N) O(1) Добавление в середину O(N) O(N) Удаление из начала O(1) O(1) Удаление из любого места O(N) O(N) Очистка списка O(N) O(N) |
||
24 |
Списки в стиле Беркли |
|
struct list_el { поле1; [остальные поля;] list_el* next; list_el* prev; } Для оптимизации работы над списками их делают кольцевыми, то есть head->prev == last && last->next == head. Поскольку двусвязный кольцевой список не имеет настоящих начала и конца, операции создания списка, добавления и удаления элементов имеют сложность О(1), а очистка списка, как обычно, O(N). Правда, для этого удобства требуется гораздо больше места в памяти, чем для линейного односвязного списка, но зато обработка двусвязного списка намного проще и просмотр можно делать в любую сторону и по любой траектории. Кроме того, для универсализации функций работы со спсиками данные кладут в отдельную структуру, а в сегменте данных элемента списка кладут указатель на структуру с данными. В прототипах фукнций фигурирует тип void* и размер структуры данных.
struct berkley_el { поле1; [остальные поля;] struct links_t{berkley_el* next; berkley_el* next;} links; }
|
25 |
Сложные объявления |
|
|
26 |
Преобразование типов. Явное и неявное преобразование. Обычное арифметическое преобразование. |
|
Примеры неявных преобразований типов:
{ int i = 3; double d = 3.6416; i = d; /* i==(int)d == 3.0 */ } { int i = 3; double d = 3.6416; d = i; /* d==(double)i == 3.0 */ }
{int i = 5, j = 2; double r = i/j; /*здесь 2.0 */ r = (double)i/j; /* а здесь 2.5 */}.
{double s = sqrt(2); /* фактически s=sqrt( (double) 2) */ }
(signed+unsigned)=={signed, если значение беззнакового операнда представимо в знаковом типе; unsigned иначе}
Таким образом, целочисленные преобразования таковы: (char, unsigned char, short, unsigned short int unsigned int long long unsigned long long) |
27 |
Библиотеки |
|
Статические библиотеки компонуются в исполняемый файл Динамические библиотеки загружаются из исполняемого файла в процессе работы. Плюсы и минусы типов библиотек: ТИП + - Статические
Динамические
gcc -std=c99 -Wall -Werror -c arr_lib.c
ar rc libarr.a arr_lib.o
ranlib libarr.a Сборка приложения со статической библиотекой gcc -std=c99 -Wall -Werror main.c libarr.a -o test.exe или gcc -std=c99 -Wall -Werror main.c -L. -larr -o test.exe
gcc -std=c99 -Wall -Werror -c arr_lib.c
gcc -shared arr_lib.o -Wl,--subsystem,windows -o arr.dll Сборка приложения с динамической библиотекой (динам. компоновка): gcc -std=c99 -Wall -Werror -c main.c gcc main.o -L. larr -o test.exe Сборка приложения с динамической библиотекой (динам. загрузка): gcc -std=c99 -Wall -Werror main.c o test.exe Windows API для работы с динам. библиотеками содежит следующие функции модуля windows.h:
|
28 |
Неопределённое поведение |
|
Допускать такое поведение считается ошибочным. На некоторых платформах и после компиляции на некоторых компиляторах возможен сбой работы программы. Примеры неопределённого поведения:
{int i=5; i = ++i + ++i; } возможны значения 13 или 14, так как побочные эффекты (инкремент) могут быть применены в любой момент между 2-мя точками следования.
Программисту рекомендуется не допускать случаев неуточняемого поведения, если это важно с точки зрения алгоритма работы программы. Примеры неуточняемого поведения:
|
29 |
Тернарная операция, операция запятая |
|
Если log_op истинно, то r = val1, иначе r = val2.
|
30 |
Типы. Концепция типа данных. Классификация типов. Спецификаторы. Логический тип. |
|
Тип данных определяет множество значений, набор операций, которые можно применять к таким значениям, и, возможно, способ реализации хранения значений и выполнения операций. Любые данные, которыми оперируют программы, относятся к определённым типам.
{unsigned, signed}x{char(1B), short int(2B), [long] int(4B), long long int(8B)}
|
Справочные материалы |
|
Лексемы Операция Класс Приоритет Ассоциативность имена, литералы простые лексемы первичный 16 нет a[k] индексы постфиксный 16 слева направо f(…) вызов функции постфиксный 16 слева направо . прямой выбор постфиксный 16 слева направо -> опосредованный выбор постфиксный 16 слева направо (имя типа) {init} составной литерал (C99) постфиксный 15 справа налево ++ -- положительное и отрицательное приращение постфиксный 15 справа налево sizeof размер унарный 15 справа налево ~ побитовое НЕ унарный 15 справа налево ! логическое НЕ унарный 15 справа налево - + изменение знака, плюс унарный 15 справа налево & получение адреса унарный 15 справа налево * разыменование указателя унарный 15 справа налево (имя типа) приведение типа унарный 15 справа налево * / % мультипликативные операции бинарный 13 слева направо + - аддитивные операции бинарный 12 слева направо << >> сдвиг влево и вправо бинарный 11 слева направо < > <= >= отношения бинарный 10 слева направо == != равенство/ неравенство бинарный 9 слева направо & побитовое И бинарный 8 слева направо ^ побитовое исключающее ИЛИ бинарный 7 слева направо | побитовое ИЛИ бинарный 6 слева направо && логическое И бинарный 5 слева направо || логическое ИЛИ бинарный 4 слева направо ? : условие тернарный 3 справа налево = += -= *= /= %= <<= >>= &= ^= |= присваивание бинарный 2 справа налево , последовательное вычисление бинарный 1 слева направо
Заголовочный файл Функции stdio.h printf и её семейство scanf и её семейство puts, fputs gets, fgets getc getchar fopen rewind fclose feof fseek EOF (макрос) fread fwrite stdlib.h malloc realloc calloc free qsort, bsearch strto*, ato* rand srand stdarg.h va_start va_end va_copy string.h memmove, memset, strcat, strncat strchr, strrchr, strpbrk, strspn, strcspn strcmp, strncmp strstr strlen strdup, strndup assert.h assert math.h abs, fabs, fdim acos, asin, atan, atan2 cos, sin, tan ceil, floor fmod, frexp, ldexp exp, exp2, expm1 log, log10, log1p, logb pow random sqrt, cbrt, hypot acosh, asinh, atanh fmax, fmin lgamma, tgamma |