Fseek ( in, offset, wherefrom )
Здесь in - указатель файла прямого доступа; offset - выражение типа long, указывающее число байт смещения от точки, определяемой третьим параметром функции; wherefrom указывает точку, от которой следует начинать отсчет смещения, заданного вторым аргументом. Для этого определены следующие константы:
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
Значение 0 - смещение от начала файла.
Значение 1 - смещение от текущей позиции файла.
Значение 2 - смещение от конца файла.
Например, для установки указателя файла на конец файла необходимо воспользоваться таким обращением:
fseek (in, 0L, SEEK_END);
Функция fseek возвращает значение 0, если указатель успешно пере-мещен, и возвращает ненулевое значение при ошибке.
Функция ftell возвращает текущее положение указателя файла. Сме-щение измеряется в байтах, считая от начала файла.
long ftell (FILE *stream);
Функция rewind перемещает указатель файла на начало:
void rewind (FILE *in);
Аналогичное действие может быть выполнено и с помощью вызова
fseek (in, 0L, SEEK_SET);
Для чтения и записи в двоичный файл используются функции fread и fwrite соответственно.
int fread ( void *ptr, int size, int n, FILE *in );
Функция fread читает n элементов, имеющих длину size байт, из входного файла in в блок, указанный в ptr. Общее число прочитанных байтов равно (n*size); ptr является указателем на любой объект; size размер объекта, на который указывает ptr. При успешном окончании функция возвращает число элементов (не байтов), в действительности прочи-танных. Если встретится конец файла или ошибка, то функция fread воз-можно возвращает 0.
int fwrite ( void *ptr, int size, int n, FILE *out);
Функция fwrite добавляет n элементов данных, имеющих длину size байт, к файлу вывода out. Добавляемые данные начинаются с ptr; общее число записанных байтов равно (n * size); ptr является указателем на любой объект; size размер объекта, на который указывает ptr. При успешном окончании функция возвращает число элементов (не байтов), в действительности записанных.
В следующем примере демонстрируется создание двоичного файла пу-тем ввода исходных данных с клавиатуры и сортировка двоичного файла ме-тодом "пузырька".
// Пример pr45
#include <stdio.h>
void main ()
{
FILE *in;
float a, a1; //Буферные пеpеменные для чтения (записи)
int fl; //Флаг для соpтиpовки
long ft; //Количество байтов смещения указателя файла
puts ( "Создать файл? (y/n) " );
if ( getchar () == 'y' )
{
// Создание двоичного файла
in = fopen ( "fileb.dat", "w+b" );
printf ( "\n Введите числo: " );
scanf ( "%f", &a );
while ( !feof ( stdin )) // Пока не конец файла
{ fwrite (&a, sizeof(a), 1, in); // Запись в файл
printf ( "Введите следующее числo: " );
scanf ( "%f", &a ); // Чтение с клавиатуpы
}
}
else
in = fopen ( "fileb.dat", "r+b" );
//Вывод данных из файла на экpан
rewind ( in ); //Установить указатель файла на начало
fread ( &a, sizeof(a), 1, in ); // Чтение из файла
while ( !feof ( in )) //Пока не конец файла
{
printf ( "%f\t", a ); //Вывод на экpан
fread ( &a, sizeof(a), 1, in );
}
printf ( "\n\n" );
//Соpтиpовка двоичного файла методом пузыpька
do
{
fl = 0;
rewind ( in ); //Установить указатель файла на начало
fread ( &a, sizeof(a), 1, in); //Чтение пеpвого числа
while ( !feof ( in ))
{
fread ( &a1, sizeof(a), 1, in);//Чтение след. числа
if (feof(in)) break; //Выйти из цикла, если конец
if(a1<a)
{ //Обмен местами двух компонент файла
ft = ftell (in) - 2*sizeof (a);
fseek ( in, ft, 0l );//Возвpат указателя файла
fwrite ( &a1, sizeof(a), 1, in );
fwrite ( &a, sizeof(a), 1, in );
fl = 1;
}
ft = ftell (in)-sizeof (a);
fseek ( in, ft, 0l );//Возвpат указателя файла на
// одну компоненту назад
fread(&a,sizeof(a),1,in);
}
}
while ( fl == 1 );
//Вывод данных из отсортированного файла
rewind ( in );
fread ( &a, sizeof (a), 1, in );
while ( !feof ( in ))
{
printf ( "%f\t", a );
fread ( &a, sizeof(a), 1, in );
}
fclose ( in );
}
Приведенный пример сортировки является универсальным, так как при изменении структуры данных, хранящихся в файле, изменяется только опи-сание этой структуры, а весь алгоритм сортировки полностью сохраняется.
Первый компонент двоичного файла имеет порядковый номер 0. Еще раз отметим, что двоичные файлы нельзя создать с помощью текстовых редакторов. Они создаются только в процессе работы программы. Очень часто текстовые файлы преобразуют в двоичные, а с ними работать так же просто, как и с массивами.
31.Классы памяти. Область действия имен в языке программирования С++.
В С++ существуют 3 класса памяти.
1) Статическая память - статические данные, размещаемые в сегменте данных;
2) автоматические данные, размещаемые в специальном стеке (сегмент стека) или как частный случай, в регистрах процессора;
3) динамические данные, явно размещаемые в динамической памяти с помощью операций new и delete.
Статические объекты существуют в течение всего времени выполнения программы. К ним относятся глобальные и локальные переменные, объявленные со служебным словом static.
Статические и глобальные переменные, если они не инициализированы явно, инициализируются нулевыми значениями. В любом случае, инициализация статических переменных осуществляется только один раз.
Локальные переменные, не объявленные как static, являются автоматическими. Такие объекты начинают свое существование при объявлении его имени в блоке и заканчивают его при завершении этого блока. Если автоматический объект явно не инициализирован, то его значение до присвоения не определено.
Заметим, что если служебное слово static применено к глобальной переменной или к имени функции, то оно имеет другой смысл. В этом случае и глобальная переменная, и функция становятся видимы только в пределах файла, где они определены и невидимы из других файлов.
С каждой переменной языка С++ связаны два основополагающих свойства – тип и класс переменной . Типы переменных обсуждались в предыдущей части пособия. Класс памяти, если он не задается явно, назначается по умолчанию.
Класс памяти определяет для каждой переменной область ее действия и время ее существования. Областью действия переменной называется та часть программы, где эта переменная известна. Время существования переменной – период в ходе выполнения программы, в течение которого переменная имеет некоторое значение. Области действия переменной и времени ее существования ограничены блоками, функциями и файлами.
В языке С++ различают четыре класса памяти:
· автоматический (auto)
· внешний (extern)
· статический (static)
· регистровый (register)
Таким образом, каждой переменной наряду с типом можно указать и класс памяти. Если класс памяти не указан, то он определяется по умолчанию в зависимости от расположения описания переменной.
Для переменных, описанных внутри функций или блоков (блок ограничивается фигурными скобками), т. е. локальных переменных, по умолчанию назначается класс памяти автоматический (auto). Для автоматической переменной, описанной в начале функции, областью действия будет та функция, где это имя описано. Переменные с этим же именем в других функциях с данной переменной никак не связаны, доступ к таким переменным из внешнего блока не возможен. Это же справедливо и для формальных параметров функции. Память под автоматические переменные отводится при входе в блок, а при выходе из блока – автоматически освобождается. Теперь понятно происхождение термина автоматические переменные.
Для переменных, описанных вне функций, т.е. глобальных переменных, по умолчанию назначается внешний класс памяти (extern). Область действия внешней переменной от точки во входном файле, где она была описана, до конца этого файла. Если внутри блока или функции описана автоматическая переменная, имя которой совпадает с именем глобальной переменной, то внутри блока или функции глобальная переменная маскируется локальной. Это означает, что внутри данного локального блока будет видна именно автоматическая локальная переменная. По умолчанию считается, что все функции внешние.
Для внешних переменных память отводится только один раз и остается занятой до окончания выполнения программы. К внешним переменным возможен доступ из других файлов. Для того чтобы внешнюю переменную использовать в другом файле, для неё следует указать спецификатор памяти extern.
При создании больших программ рекомендуется все внешние описания размещать в отдельном файле с расширением .h и вставлять копию этого файла в каждый файл, где требуется описание внешних переменных.
Статическая переменная может быть внутренней и внешней. Внутренние статические переменные локальны по отношению к отдельной функции, так же как и автоматические, но в отличие от последних они продолжают существовать, а не возникают и уничтожаются при каждой активизации фукции. Это означает, что внутренние статические переменные являются собственной постоянной памятью для функции. Внешние статические переменные известны внутри оставшейся части исходного файла, в котором они описаны, однако в других файлах они не известны. Если необходимо сделать функцию недоступной из других файлов, то ей следует приписать спецификатор static.
Спецификатор register может использоваться только для автоматических переменных [5]. Такой спецификатор говорит о том, что пользователь желает разместить переменные не в оперативной памяти, а в регистрах компьютера. Так как количество регистров ограничено, то в случае избыточности описаний слово register будет игнорировано. Кроме того, нельзя обращаться к адресу таких переменных. Спецификатор register рекомендуется использовать для переменных, к которым происходит интенсивное обращение. Полученный в результате код будет выполняться быстрее и станет более компактным. Область действия и время существования регистровых переменных определяетя так же как у автоматических.
Следует заметить, что при отсутствии явной инициализации переменных внешние и статические переменные будут инициализироваться нулем, а автоматические и регистровые переменные будут иметь неопределенные значения (мусор). Не рекомендуется инициализировать автоматические массивы.
С помощью операции :: расширяется зона видимости имен. Появляется доступ к глобальным переменным, скрытым локальными переменными.
32.Текстовые файлы в языке программирования С++.
Под файлом понимается именованная область внешней памяти или логическое устройство потенциальный источник или приемник информации [10]. Основное отличие внешней памяти ЭВМ от оперативной памяти ? возможность сохранения информации при отключении ЭВМ. Информация сохраняется в виде файлов, доступ к которым поддерживает операционная система ЭВМ. Поддержка операционной системы состоит в том, что в ней имеются средства:
· создания файлов;
· уничтожения файлов;
· поиска файлов на внешнем носителе;
· чтения и записи из файлов и в файлы;
· открытия файлов;
· закрытия файлов;
· позиционирования файлов.
Любой сколько-нибудь развитый язык программирования должен содержать средства для организации хранения информации на внешних запоминающих устройствах и доступа к этой информации. Язык С++ не лишен таких возможностей.
Любой файл в С++ имеет три характерные особенности:
· у файла есть имя, это дает возможность работать с несколькими файлами одновременно;
· содержит компоненты одного типа (типом может быть любой тип, кроме файлового);
· длина вновь создаваемого файла никак не ограничена при объявлении и ограничивается лишь емкостью внешних устройств памяти.
Обращение к файлу производится через указатель на файл, который необходимо описать следующим образом:
FILE *< имя >;
Здесь < имя > - идентификатор указателя на файл; FILE - имя типа, определенного в файле stdio.h, являющегося структурой, описывающей характеристики файла, суть которых в данном пособии не рассматривается.
В зависимости от способа описания можно выделить текстовые файлы и двоичные (типизированные). Вид файла определяет способ хранения информации в файле.
Текстовый файл можно представить как набор строк произвольной длины. Для деления на строки используется управляющий символ \n. Он является файлом последовательного доступа. Логически текстовый файл можно представить как именованную цепочку байтов, имеющую начало и конец. Чтение (или запись) из файла (в файл) ведется байт за байтом от начала к концу. Перед первым обращением к функциям ввода-вывода указатель файла стоит в его начале и указывает на первый компонент. После каждого чтения или записи указатель сдвигается на заданное количество байт. Такой способ доступа называется последовательным. Текстовые файлы оказываются переносимыми с одного типа компьютера на другой, если символы, содержащиеся в файле, принадлежат стандартному набору символов (т. е. не используются дополнительные символы, такие, например, как символы псевдографики фирмы IBM).
Рассмотрим текстовые файлы. Каждой программе доступны два стандартных файла stdin (клавиатура) и stdout (экран). Это - текстовые файлы. Любые другие файлы становятся доступными после выполнения специальных процедур. Рассмотрим основные функции для работы с текстовыми файлами.
Функция открытия файла:
FILE *fopen (char *filename, char *type)
Эта функция возвращает указатель на файл, который открывается. Если файл открыть нельзя, то функция возвращает пустой указатель NULL. char *filename указатель на строку символов, содержащую имя файла и, если необходимо, путь к нему. char *type указатель на строку символов, определяющую тип открываемого файла. Допустимы следующие значения этой переменной :
· r - открыть уже существующий файл на ввод;
· w - cоздать новый файл или очистить уже существующий файл и открыть его на вывод;
· a - cоздать новый файл для вывода или осуществить вывод в конец уже существующего файла;
· r+- открыть уже существующий файл для обновления, которое будет проводиться с начала файла;
· w+- cоздать новый файл или очистить уже существующий файл для обновления его содержимого;
· a+- cоздать новый файл или подстроиться в конец существующего для обновления его содержимого.
Дополнительно к каждой из приведенных строк можно добавить символ b, указывающий на то, что открывается двоичный файл. Если добавлен символ t или символ отсутствует, то открывается текстовый файл.
При заполнении файла после последней записи автоматически помещается невидимый специальный признак "конец файла" (end of file). Существует функция feof(f), тестирующая конец файла. Функция feof(f) возвращает значение истина, если действительно встретился признак "конец файла"; пока это не произойдет, значение feof(f) будет ложь.
fclose(FILE * stream) - функция закрытия файла, на который указывает указатель на файл stream. Функция fclose() выполняется автоматически по отношению ко всем открытым файлам при нормальном за-вершении программы.
Для чтения и записи информации из файла или в файл используется очень много функций. Например, функции fscanf и fprintf, анало-гичные уже знакомым функциям scanf и printf, но в качестве первого параметра в них выступает указатель на файл.
Текстовый файл можно создать, используя любой текстовый редактор, в том числе и встроенный текстовый редактор интегрированной среды Borland C++.
33.Аргументы главной функции в языке программирования С++.
До сих пор функцию main мы рассматривали как функцию без параметров. Эта функция может иметь два параметра argc и argv, которые передаются из внешнего окружения. Соглашение о передаче параметров в большей степени определяется операционной системой, чем самим языком С++. Параметр argc имеет тип int и определяет число передаваемых параметров, которые могут быть приняты за имя и аргументы программы. Параметр argv имеет тип char *[] и указывает на начало массива строк, являющихся передаваемыми параметрами. Каждая строка заканчивается нуль-символом. Система использует пробелы, чтобы сообщить о конце одной и начале другой строки символов.
// Пример pr22
#include <stdio.h>
void main(int argc, char *argv[])
{
for(int c = 0; c < argc; c++)
printf("%s", argv[c]);
printf("\n");
}
argv[0] всегда содержит имя программы, а остальные элементы массива строк будут содержать значения, которые пользователь передает из внешнего окружения, используя опцию меню run argument. Приведенный выше пример представляет программу печати фактических аргументов, передаваемых функции main. Параметры функции main могут использоваться во многих прикладных программах с большой пользой. Например, при вызове программы могут указываться имена входных и выходных файлов или числовые значения, которые внутри программы переводятся в числовой тип.
34.Структурное программирование в языке программирования С++.
При создании средних по размеру приложений (несколько тысяч строк исходного кода) используется структурное программирование, идея которого заключается в том, что структура программы должна отражать структуру решаемой задачи, чтобы алгоритм решения был ясно виден из исходного текста. Для этого надо иметь средства для создания программы не только с помощью трех простых операторов, но и с помощью средств, более точно отражающих конкретную структуру алгоритма. С этой целью в программирование введено понятие подпрограммы – набора операторов, выполняющих нужное действие и не зависящих от других частей исходного кода. Программа разбивается на множество мелких подпрограмм, каждая из которых выполняет одно из действий, предусмотренных исходным заданием. Комбинируя эти подпрограммы, удается формировать итоговый алгоритм уже не из простых операторов, а из законченных блоков кода, имеющих определенную смысловую нагрузку, причем обращаться к таким блокам можно по названиям.
Структурное программирование основано на модульной структуре программного продукта и типовых управляющих структурах алгоритмов обработки данных различных программных модулей.
Типы управляющих структур:
· последовательность;
· альтернатива (условие выбора);
· цикл.
Распространены две методики (стратегии) разработки программ, относящиеся к структурному программированию:
· программирование «сверху вниз»;
· программирование «снизу вверх».
Программирование «сверху вниз», или нисходящее программирование – это методика разработки программ, при которой разработка начинается с определения целей решения проблемы, после чего идет последовательная детализация, заканчивающаяся детальной программой.
Сначала выделяется несколько подпрограмм, решающих самые глобальные задачи (например, инициализация данных, главная часть и завершение), потом каждый из этих модулей детализируется на более низком уровне, разбиваясь в свою очередь на небольшое число других подпрограмм, и так происходит до тех пор, пока вся задача не окажется реализованной.
В данном случае программа конструируется иерархически - сверху вниз: от главной программы к подпрограммам самого нижнего уровня, причем на каждом уровне используются только простые последовательности инструкций, циклы и условные разветвления.
Такой подход удобен тем, что позволяет человеку постоянно мыслить на предметном уровне, не опускаясь до конкретных операторов и переменных. Кроме того, появляется возможность некоторые подпрограммы не реализовывать сразу, а временно откладывать, пока не будут закончены другие части. Например, если имеется необходимость вычисления сложной математической функции, то выделяется отдельная подпрограмма такого вычисления, но реализуется она временно одним оператором, который просто присваивает заранее выбранное значение (например, 5). Когда все приложение будет написано и отлажено, тогда можно приступить к реализации этой функции.
Программирование «снизу вверх», или восходящее программирование – это методика разработки программ, начинающаяся с разработки подпрограмм (процедур, функций), в то время когда проработка общей схемы не закончилась.
Такая методика является менее предпочтительной по сравнению с нисходящим программированием так как часто приводит к нежелательным результатам, переделкам и увеличению времени разработки.
Очень важная характеристика подпрограмм – это возможность их повторного использования. С интегрированными системами программирования поставляются большие библиотеки стандартных подпрограмм, которые позволяют значительно повысить производительность труда за счет использования чужой работы по созданию часто применяемых подпрограмм.
Подпрограммы бывают двух видов – процедуры и функции. Отличаются они тем, что процедура просто выполняет группу операторов, а функция вдобавок вычисляет некоторое значение и передает его обратно в главную программу (возвращает значение). Это значение имеет определенный тип.
Чтобы работа подпрограммы имела смысл, ей надо получить данные из внешней программы, которая эту подпрограмму вызывает. Данные передаются подпрограмме в виде параметров или аргументов, которые обычно описываются в ее заголовке так же, как переменные.
Подпрограммы вызываются, как правило, путем простой записи их названия с нужными параметрами.
Подпрограммы активизируются только в момент их вызова. Операторы. Которые находятся внутри подпрограммы, выполняются, только если эта подпрограмма явно вызвана.
Подпрограммы могут быть вложенными – допускается вызов подпрограммы не только из главной программ, но и из любых других программ.
В некоторых языках программирования допускается вызов подпрограммы из себя самой. Такой прием называется рекурсией и опасен тем, что может привести к зацикливанию – бесконечному самовызову.
Достоинства структурного программирования:
· повышается надежность программ (благодаря хорошему структурированию при проектировании, программа легко поддается тестированию и не создает проблем при отладке);
· повышается эффективность программ (структурирование программы позволяет легко находить и корректировать ошибки, а отдельные подпрограммы можно переделывать (модифицировать) независимо от других);
· уменьшается время и стоимость программной разработки;
· улучшается читабельность программ.
Таким образом, технология структурного программирования при разработке серьезных программных комплексов, основана на следующих принципах:
· программирование должно осуществляться сверху вниз;
· весь проект должен быть разбит на модули (подпрограммы) с одним входом и одним выходом;
· подпрограмма должна допускать только три основные структуры – последовательное выполнение, ветвление (if, case) и повторение (for, while, repeat).
· недопустим оператор передачи управления в любую точку программы (goto);
· документация должна создаваться одновременно с программированием в виде комментариев к программе.
Структурное программирование эффективно используется для решения различных математических задач, имеющих алгоритмический характер.
35.Перегрузка функций в языке программирования С++.
В языке С каждая функция должна иметь свое уникальное имя. В С++ разрешается определять две или несколько функций с одинаковыми именами. Цель перезрузки функций состоит в том, чтобы функции с одинаковыми именами по-разному выполнялись и возвращали различные значения при обращении к ним. К какой функции в данный момент происходит обращение, определяется по контексту, так как каждая фукция имеет оригинальный набор параметров. Функции могут иметь как разные по типу, так и по количеству фактические параметры.
Перегружаемые функции не могут различаться только по типу возвращаемого результата, обязательно отличие по параметрам. В ранних версиях использовался перед именем функции спецификатор overload, теперь он является не только необязательным, но и нежелательным из-за несовместимости с некоторыми версиями языка. Чаще всего перегрузку функций используют, когда возникает необходимость выполнить одни и те же действия над переменными различных типов.
36.Шаблоны функций в языке программирования С++.
В отличие от перегруженных функций шаблоны позволяют не писать один и тот же код программы для переменных различного типа. Шаблоны служат для автоматизации создания функций, которые могут обрабатывать разнотипные данные. Шаблон функций представляет собой обобщенное определение, из которого компилятор может автоматически генерировать код функции. В отличие от механизма перегрузки, когда для каждой сигнатуры определяется своя функция, шаблон семейства функций определяется один раз, но это определение параметризуется. Параметризировать в шаблоне функций можно тип возвращаемого функцией значения и типы любых передаваемых параметров, количество и порядок размещения которых должны быть фиксированы. Для параметризации используется список параметров шаблона.
В определении шаблона семейства функций используется служебное слово template. Для параметризации применяется список формальных параметров шаблона, который заключается в угловые скобки <>. Каждый формальный параметр шаблона обозначается ключевым словом class, за которым следует имя параметра (идентификатор), обозначающего тип.
Шаблон семейства функций состоит из двух частей – заголовка шаблона:
template <class type>
и из обыкновенного определения функции, в котором тип возвращаемого значения и типы любых параметров обозначаются именами параметров шаблона, введенных в его заголовок. Здесь type используется как имя параметра шаблона. Те же имена параметров шаблона могут использоваться и в теле определения функции для обозначения типов локальных объектов.
Шаблон семейства функций служит для автоматического формирования конкретных определений функций по тем вызовам, которые компилятор обнаруживает в тексте программы. Компилятор в соответствии с вызовом сформирует определение функции.
37.Подставляемые функции в языке программирования С++.
Некоторые функции в языке C++ можно определить с использованием специального служебного слова inline. Спецификатор позволяет определить функцию как встраиваемую, то есть подставляемую в текст программы в местах обращения к этой функции. Например, следующая функция определена как подставляемая:
inline float module(float x = 0, float у = 0)
{ return sqrt(x * x + у * у); }
Обрабатывая каждый вызов встраиваемой функции, компилятор "пытается" подставить в текст программы код операторов ее тела. Тем самым при многократных вызовах подставляемой функции размеры программы могут увеличиться, однако исключаются затраты на передачи управления к вызываемой функции и возвраты из нее. Кроме того, подстановка функции позволяет проводить оптимизацию кода. Наиболее эффективно использовать подставляемые функции в тех случаях, когда тело функции состоит всего из нескольких операторов.
Перечислим причины, по которым функция со спецификатором inline будет трактоваться как обычная не подставляемая:
· встраиваемая функция велика;
· встраиваемая функция рекурсивна;
· обращение к встраиваемой функции в программе размещено до ее определения;
· встраиваемая функция используется в выражении более одного раза;
· встраиваемая функция содержит цикл, переключатель или оператор перехода.
Если же для функции со спецификатором inline компилятор не может выполнить подстановку из-за контекста, в который помещено обращение к ней, то функция считается статической (static) и выдается предупреждающее сообщение. Еще одна особенность подставляемых функций - невозможность их изменения без перекомпиляции всех частей программы, в которых эти функции вызываются.
38.Значения параметров функции по умолчанию в языке программирования С++.
В С++ фоpмальным паpаметpам функций могут быть пpисвоены значения по умолчанию. Если параметр имеет значение по умолчанию, то все параметры, стоящие справа от него тоже должны иметь значение по умолчанию. Эти значения передаются функции, когда данный параметр не указан при ее вызове.
Предположим, что вы написали функцию drawcircle, которая рисует на экране окружность, и задали ее прототип:
void drawсircle(int x = 100, int y = 100, int r = 100)
или
void drawсircle(int = 100, int = 100, int = 100) .
Тогда вызовы этой функции будут проинтерпретированы в зависимости от передаваемых параметров:
drawcircle(); // Окружность с центром (100, 100), радиусом 100
drawcircle(200); // Окружность с центром (200, 100), радиусом 100
drawcircle(200, 300); // Окружность с центром (200, 300), радиусом 100
drawcircle(200, 300, 200); // Окружность с центром (200, 300), радиусом 200
drawcircle(, , 50); // Ошибка