Любая программная единица на языках C, C++ оформляется как функция, причем в отличие от языка Pascal функции не могут быть вложены друг в друга. Поэтому функция представляется как некий кирпичик, который может быть размещен в любом месте программы. А вся программа состоит из последовательности таких кирпичиков, среди которых обязательно присутствует главный – функция с именем main.
Описание любой функции начинается с ее заголовка, имеющего вид:
trv namef(type1 par1,type2 par2,...)
Здесь
trv – тип возвращаемого значения;namef – имя функции;par1 – имя первого аргумента функции, имеющего тип type1 ;par2 – имя второго аргумента функции, имеющего тип type2 ;Функция может не возвращать значение и тогда на месте trv указывается служебное слово void. Функция может не иметь аргументов, но тогда после ее имени указываются либо пустые скобки, либо скобки, содержащие служебное слово void.
Если аргументы (параметры) функции являются скалярными (т.е. одиночными) величинами, то различают три способа передачи параметров:
Пример 1. Функции передаются два значения, по которым она находит и возвращает среднее арифметическое.
double mid(double x,double y)
{ return (x+y)/2.0; }
Пример 2. Функции передаются два параметра по указателю. Функция меняет местами значения переданных ей переменных.
void swap(int *x,int *y)
{ int tmp;
tmp=*x; *x=*y; *y=tmp;
}
Пример 3. Функции передаются два параметра по ссылке. Функция меняет местами значения переданных ей переменных.
void swap(float x,float y)
{ float tmp;
tmp=x; x=y; y=tmp;
}
По сути дела, два последние способа передачи параметров одинаковы – и в том, и в другом случае функции сообщают адрес расположения параметра в оперативной памяти. По этому адресу функция может извлечь текущее значение параметра или записать на его место новое значение. Разница только в форме обращения по полученному адресу. Ссылки делают это обращение более простым, к имени параметра не надо ничего добавлять. При работе с указателями выборка и запись по указанному адресу сопровождается дополнительным символом *.
Так как функция может находиться в любом месте программы (по отношению к точкам программы, из которых производится вызов функции), то компилятор должен удостовериться в правильности обращения к функции. То-есть, он должен знать количество параметров, их последовательность и тип каждого параметра. Для этой цели заголовки всех используемых функций дублируют в начале программы, завершая каждый из них точкой с запятой. Такие строки принято называть прототипами функций.
Пример 4. Заголовки функций вынесены в список прототипов.
double mid(double x, double y);
void swap1(double *x,double *y);
void swap2(double x,double y);
void main()
{ double a=1.5, b=-2.5,c;
c=mid(a,b);
swap1(a,b);
swap2(b,c);
.............
}
double mid(double x, double y)
{ return (x+y)/2.0; }
void swap1(double *x,double *y)
{ double tmp;
tmp=*x; *x=*y; *y=tmp;
}
void swap2(double x,double y)
{ double tmp;
tmp=x; x=y; y=tmp;
}
Вообще говоря, имена формальных параметров в заголовке функции и в ее прототипе могут не совпадать. Более того, некоторые программисты предпочитают указывать в прототипе только типы формальных параметров, опуская их имена. Например:
double mid(double, double);
Для нужд компилятора, который проверяет в вызовах функций только
количество параметров и их тип, этого достаточно. И синтаксис языков
C, C++ разрешает так делать. Но, на наш взгляд, выбор запоминающихся
мнемонических имен формальных параметров и сохранение их в прототипах
могут уменьшить вероятность появления ошибок, связанных с
перестановкой данных. Например, как догадаться о смысле параметров по
следующему
int intersect(double,double,double,double,double,double);
В каком из параметров, – в первой паре или в последней, – надо указывать ссылки на координаты точки пересечения. Очевидно, что более информативным был бы прототип следующего вида:
int intersect(double x1, double y1, double x2, double y2,
double x, double y);
Данные (переменные и константы), используемые в каждой функции, могут быть объявлены как в теле функции, так и за пределами всех функций. В первом случае они являются индивидуальной собственностью той функции, где они объявлены. Говорят, что они локализованы в этой функции, и с ними связывают термин локальные данные. Другие функции об этих данных ничего не знают, и пользоваться ими не могут. В отличие от этого описания некоторых данных могут быть вынесены за пределы всех функций – обычно их выносят в заголовочные файлы или размещают в начале программы. Такими данными может воспользоваться любая функция из этого же программного файла, и применительно к ним говорят о глобальных данных.
Если в какой-то функции объявлена локальная переменная, и ее имя совпадает с именем глобальной переменной, то это не считается ошибкой. Просто данная функция отказывается иметь дело с глобальной переменной и предпочитает у себя использовать только свою локальную переменную. В некоторых функциях, возможно, хочется использовать обе переменные. Тогда перед именем глобальной переменной размещают двойное двоеточие, чтобы отличать ее значение от значения локальной переменной с тем же именем.
#include <iostream.h>
#include <conio.h>
int x=20; //глобальная переменная
void main()
{ int x=40; //локальная переменная
cout << "Local x=" << x << endl;
cout << "Global x=" << ::x << endl;
getch();
}
Глобальным переменным место в памяти выделяется до начала
исполнения программы, и это место сохраняется за ними до завершения
работы программы. В отличие от этого место для хранения локальных
переменных выделяется только в момент вызова функции, а при выходе из
функции выделенные ресурсы возвращаются системе. Поэтому значения
локальных переменных пропадают, их бывшее место в оперативной памяти
будет перераспределено под нужды других функций. Однако существует
специальная группа локальных переменных, которая описывается внутри
функции со спецификатором static. Ячейки памяти, выделенные для их
хранения, фиксируются до окончания работы всей программы. При
повторном обращении к функции значения ее статических переменных
сохранены, и функция вновь может ими воспользоваться. Однако для
других функций внутренние
Объявление переменных в общем случае выглядит следующим образом:
[static] tv namev [=value]
Здесь
tv – тип переменной;namev – имя переменной;value – начальное значение переменной.Если переменная объявляется как глобальная и ее начальное значение не указано, то системы BC 3.1 и BCB выделяют ей соответствующий участок памяти и заносят нули в выделенные байты. Однако из соображений переносимости программы не стоит рассчитывать на такую чистку памяти. Лучше принудительно задавать те или иные значения (в том числе и нулевые) – этот способ никогда не подведет.
Если переменная объявляется как локальная и ее начальное значение задано, то оно заносится в такую переменную при каждом вызове функции (при условии, что эта переменная не объявлена статической).
Объявление глобальной переменной тоже может сопровождаться
спецификатором static. Это имеет смысл, когда полный текст программы
разбросан по нескольким файлам. В этом случае статические глобальные
переменные доступны только тем функциям, которые включены в тот же
файл. Из других файлов эти переменные не доступны. Для ссылок на
глобальные переменные, описанные в другом файле, обычно используют
спецификатор extern (от англ. external – внешний):
double qq(int n,double r)
{ extern float eps;
...................
Глобальные переменные, объявленные в этом же файле, в таком дополнительном пояснении не нуждаются.
Для объявления
const [tc] namec=value;
Здесь
tc – необязательный тип константы (по умолчанию tc=int );namec – имя константы;value – значение константы.Например:
const Nmax=100; const double eps=1e-6;
Иногда для задания таких же констант прибегают к механизму простейшей макроподстановки:
#define Nmax 100 #define eps 1e-6
Это означает, что перед трансляцией программы компилятор (точнее,
прекомпилятор) просмотрит ее текст и всюду, где будет встречено
сочетание символов Nmax, его заменят на число 100, а сочетание символов eps на число 1e-6. Результат будет тем же самым, но работа по
макроподстановке связана с более заметными затратами времени.
Оператор присваивания является наиболее распространенным средством, позволяющим изменить значение переменной во время работы программы.
В простейшем случае он имеет следующий формат:
namev = expression;
Здесь
namev – имя переменной:expression – выражение, значение которого будет присвоено переменной namev.Если переменная namev относится к категории числовых данных, то
результат вычисления выражения тоже должен быть числовым. Типы
переменной namev и значения выражения expression при этом могут не
совпадать. О соответствующем преобразовании машинных форматов система
позаботится сама. Но не забывайте, что при преобразовании
вещественного значения в целочисленное дробная часть выражения (какой
бы она ни была) будет отброшена. Таким образом, об округлении вы
должны позаботиться сами. В тех случаях, когда тип выражения допускает
более широкий диапазон представления данных, возможна namev. В
таких случаях компилятор выдает сообщение о возможных последствиях, и
на такие сообщения программист обязан обратить внимание.
Если нескольким переменным необходимо присвоить значение одного и того же выражения, то оператор присваивания допускает расширенный формат:
v1=v2=v3=exp;
Используя такую форму множественного присвоения, не пытайтесь писать операторы, результат выполнения которых может по разному толковаться разными пользователями. Например:
i=5; i=a[i]=4; j=6; a[j]=j=2;
Результат таких действий зависит от алгоритма просмотра строки программы и последовательности выполнения присваиваний – слева направо или справа налево. Старайтесь избегать подобных ситуаций, т.к. в случае переноса программы в другую систему программирования можно получить неожиданный результат.
В программах на C, C++ очень часто встречаются специфические форматы записи операторов присваивания. В тех случаях, когда значение переменной должно быть увеличено или уменьшено на 1, используются следующие синтаксические конструкции:
x++; // вместо x=x+1; ++x; // вместо x=x+1; x--; // вместо x=x-1; --x; // вместо x=x-1;
В приведенных примерах размещение двойного знака сложения или вычитания роли не играет. Однако такая конструкция может входить в качестве операнда в арифметическое выражение (что встречается не очень часто) или выступать в роли индекса у элементов массива. Например:
y=a[i++]; z=b[++j];
В первом случае переменной y будет присвоено значение a[i] со
старым индексом, после чего индекс i будет увеличен на 1. Во втором
случае сначала индекс j будет увеличен на 1, а потом значение b[j] с
новым индексом будет участвовать в операции присвоения.
Еще одна форма оператора присваивания ведет свое происхождение от
условного арифметического выражения, впервые появившегося в языке
v = (a > b)? e1 : e2;
Выполняется такой оператор следующим образом. Проверяется условие,
записанное в круглых скобках и, если оно удовлетворяется, то
переменной v присваивается значение выражения e1. В противном случае в
переменную v засылается значение выражения e2.
Следующая группа операторов присваивания обязана своим происхождением формату машинных команд в двухадресных машинах:
COD A1,A2
Здесь
COD – код машинной операции;A1,A2 – адреса ячеек оперативной памяти и/или арифметических регистров.Результат выполнения такой операции над содержимым A1 и A2
записывается по адресу A1 ( $$A1=A1\otimes A2$$ ). По аналогии с такой записью в
языках C, C++ появилась следующая синтаксическая конструкция:
Здесь символ $$\otimes$$ обозначает один из следующих знаков двухместных операций:
+,-,*,/,%,<<,>>,,|,^
Например:
x += 2; //вместо x=x+2; z /= 1.5; //вместо z=z/1.5;
Довольно экзотически выглядит оператор присваивания, в правой части которого через запятую задана последовательность некоторых действий. Например:
x=(y=sin(a+b),z=cos(a-b),max(y,z));
Действия в скобках выполняются слева направо, т.е. сначала будет
вычислено значение sin(a+b), которое занесут в переменную y, затем
будет вычислено значение переменной z. Окончательным результатом
скобки, которое будет присвоено переменной x, станет вычисление
значения функции max(y,z).
С помощью условного оператора в программе можно создать две альтернативные цепочки операторов, выполнение каждой из которых происходит в зависимости от истинности или ложности заданного условия:
if(условие) {S1; S2;...} [else {Q1;Q2;...}]
Если условие, указанное в круглых скобках истинно, то выполняется
цепочка операторов S1, S2, .... В противном случае выполняется цепочка
операторов Q1,Q2,.... Альтернативная ветвь вместе со служебным словом
else может отсутствовать. И тогда речь идет о выполнении или обходе
цепочки операторов S1,S2,....
Простейшие условия задаются в виде проверки соотношения двух однотипных выражений:
if(a>b) cout<<a; else cout<<b; if(x>=0) y=sqrt(x);
Напомним, что
== |
равно | != |
не равно | > |
больше |
>= |
больше или равно | < |
меньше | <= |
меньше или равно |
Более сложные условия могут составляться из элементарных
соотношений с помощью логических операций "ИЛИ" ( || ), "И" ( ), "НЕ"
( !). Например, проверка принадлежности x диапазону [ a,b ] выглядит
следующим образом:
if(a<=x x<=b) ...
В качестве логического условия иногда можно встретить в круглых скобках обычное арифметическое выражение:
if(a)...
В языке C
if(a != 0)...
Перед любым исполняемым оператором программы может находиться символьная метка, отделяемая от оператора двоеточием:
m5: printf("\nx=%f",x);
На помеченный таким образом оператор может быть передано управление
с помощью оператора goto m5. Но такие переходы допустимы только внутри
goto
недопустим.
В ряде книг можно встретить утверждение, что пользоваться этим
оператором ни в коем случае нельзя. Однако это не так. Оператором goto
пользоваться можно, а вот злоупотреблять им действительно не
рекомендуется. Бездумное и неумеренное использование операторов goto
приводит к появлению программ трудных для понимания, обладающих
запутанной логикой, мало пригодных к внесению изменений.
Рассмотрим две реализации программы, которая вводит три
целочисленных значения и выводит максимальное из них. В первой из них
(программа-спагетти) на 10 исполняемых строк приходится 5 операторов goto. Во второй реализации потребовалось всего 5 исполняемых строк и
ни одного оператора goto.
Пример 5.1. Программа-спагетти.
#include <stdio.h>
#include <conio.h>
void main()
{ int a,b,c;
scanf("%d %d %d",a,b,c);
if(a>b) goto m1;
if(b>c) goto m2;
m3: printf("max=%d",c);
goto m5;
m1: if(c>a) goto m3;
m4: printf("max=%d",a);
goto m5;
m2: printf("max=%d",b);
m5: getch();
}
Пример 5.2. Пример прозрачной логики
#include <stdio.h>
#include <conio.h>
void main()
{ int a,b,c;
scanf("%d %d %d",a,b,c);
if(b>a) a=b;
if(c>a) a=c;
printf("max=%d",a);
getch();
}
Одним из случаев, когда применение
int i,j;
for(i=0; i<n; i++) {...
for(j=0; j<20; j++) {...
if(условие_выхода) goto mm;
}
}
mm:
Конечно, можно придумать более запутанную схему, не используя goto:
int i,j,k=1;
for(i=0; i<n k; i++) {...
for(j=0; j<20 k; j++) {...
if(условие_выхода) {k=0; break;}
}
}
Применяя оператор goto, стоит следовать следующим
рекомендациям:
Операторы цикла позволяют организовать повторное выполнение
фрагмента программы до тех пор, пока не выполнится некоторое условие.
Конечно, аналогичные действия могут быть оформлены с использованием
условных операторов ( if...) и безусловных переходов ( goto ) в начало
повторяющегося фрагмента. Однако использование операторов цикла
позволяет сделать логику работы программы более прозрачной и немного
более эффективной за счет применения специальных машинных команд,
которые вставляет компилятор.
Наиболее часто применяемая конструкция цикла использует оператор for:
for(S1; C; S2) { Q1; Q2;...}
Здесь
S1 – действие, которое выполняется перед повторением группы операторов Q1, Q2, ..., образующих тело цикла;C – условие, при выполнении которого тело цикла повторяется. Если условие C не выполнено, то тело цикла обходится и цикл завершается;S2 – действие, которое выполняется вслед за последним оператором тела цикла. После этого управление передается на проверку условия завершения цикла.Одна из форм оператора for позволяет организовать повторение тела
цикла заданное число раз, изменяя при каждом повторении значение
некоторой управляющей переменной (иногда такую переменную называют
счетчиком цикла или индексом цикла):
s=0;
for(j=0; j<10; j++)
s=s+a[j];
В приведенном примере тело цикла состоит из единственного
оператора, который можно не заключать в фигурные скобки. Перед началом
цикла в переменную j заносится 0 и поскольку это значение меньше 10,
то к содержимому переменной s прибавляется значение первого элемента
массива a[0]. После первого завершения тела цикла к счетчику j
добавляется 1 и тело цикла повторяется. Так продолжается до тех пор,
пока значение счетчика не увеличится до 10, при котором условие
повторения цикла уже не выполняется.
Если счетчик цикла используется только в теле цикла и значение этой
переменной за пределами цикла сохранять не нужно, то стандарт C++
позволяет определить такую суперлокальную переменную непосредственно в
операторе for:
for(int j=0; j<10; j++)
Значение счетчика (индекса) может не только увеличиваться при каждом повторении цикла, но и уменьшаться:
s=0;
for(j=9; j>=0; j--)
s=s+a[j];
В этом примере массив a суммируется, начиная с последнего
элемента.
Иногда цикл по счетчику в обратном порядке организуют следующим образом:
count=20;
for(s=0; count; count--)
s += a[count];
В этом примере условием повторения цикла является положительное
значение счетчика count, которое воспринимается как
"истина". Как только содержимое счетчика станет равным нулю
(т.е. "лжи"), цикл завершит свою работу.
В отличие от языка Паскаль, где оператор for допускает только
увеличение или уменьшение счетчика цикла только на 1, оператор for в
языках C, C++ позволяет изменять значение управляющей переменной
произвольным образом. Эта переменная может быть вещественного типа, и
ее значение может меняться не только по закону арифметической
прогрессии, но и любым сколь угодно сложным способом. Например, можно
просуммировать только элементы массива с четными индексами:
s=0;
for(j=0; j<10; j+=2)
s=s+a[j];
Действие S1, выполняемое при входе в цикл, может состоят не только
из единственного оператора, засылающего в счетчик цикла начальное
значение. Если нужно выполнить несколько операторов, то их разделяют
запятыми (список действий, аналогичный экзотической форме оператора
присваивания). В приведенных выше примерах очистку переменной s тоже
можно было внести в оператор заголовка цикла:
for(s=0,j=0; j<10; ++j)
s=s+a[j];
Аналогичный список из нескольких операторов можно использовать и в
качестве действия S2, выполняемого вслед за последним оператором тела
цикла. В приведенном ниже примере оператор цикла вычисляет n-й член
последовательности чисел Фибоначчи:
for(x=1,y=1,i=2; i<n; z=x+y, x=y, y=z, i++);
Иногда в программах можно встретить на первый взгляд бессмысленный
оператор for:
for(;;){Q1;Q2;...;}
Судя по описанию оператора for, тело такого цикла должно
выполняться бесконечное число раз. Однако такие циклы могут оказаться
полезными в DOS-приложениях для организации ожидания какого-либо
события, появление которого проверяется в теле цикла. Если событие
произошло (например, ввод информации со стороны пользователя
состоялся, или по каналу связи поступило долгожданное сообщение), то
из тела цикла можно выйти с помощью оператора break или goto. В среде
Windows существуют и более эффективные (с точки зрения загрузки
процессора) средства, контролирующие появление того или иного
события.
Вторая конструкция оператора цикла начинается со служебного слова while (от англ. – пока):
while(условие) {Q1; Q2;...}
Вход в такой цикл начинается с проверки условия, заданного в
круглых скобках. Если это условие истинно, то тело цикла (операторы Q1, Q2,...) выполняется. В случае невыполнения условия тело цикла
обходится. С помощью оператора while тоже можно организовать
суммирование элементов массива:
s=0; i=0;
while(i<10)
{ s=s+a[i]; i++; }
Согласитесь, что этот вариант выглядит менее изящно, чем его аналог
с оператором for, хотя здесь присутствуют те же элементы, которые
раньше фигурировали в заголовке цикла for. Однако в других
итерационных процессах использование цикла while может оказаться более
уместным. Например, итерационная схема вычисления корня квадратного из x (аналогичные схемы можно написать и для корней других степеней)
имеет следующий вид:
yn+1=0.5*(yn +x/yn)
Для ее реализации можно воспользоваться следующим циклом:
y=x; //начальное приближение
while(fabs(x-y*y)>1e-6)
y=0.5*(y+x/y);
Третья конструкция цикла начинается с оператора do (от англ. –
выполнить) и завершается проверкой while:
y=x; //начальное приближение
do
y=0.5*(y+x/y);
while(fabs(x-y*y)>1e-6)
Отличие конструкции do – while от двух предыдущих операторов цикла
заключается в том, что здесь тело цикла выполняется, по крайней мере,
один раз. Этот цикл иногда сопровождают термином с постусловием – т.е.
проверка
Все конструкции операторов цикла допускают вложение других циклов в свои тела. Например, для умножения квадратных матриц можно воспользоваться следующим фрагментом программы:
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{for(d=0,k=0; k<n; k++)
d += a[i][k]*b[k][j];
c[i][j]=d;
}
К числу дополнительных средств управления циклами относятся
операторы break (от англ. – прервать) и continue (от англ. –
продолжить).
С помощью оператора break организуется досрочное окончание цикла с
передачей управления оператору, следующему непосредственно за концом
цикла. Пусть, например, нам предстоит суммирование элементов массива a
до тех пор, пока не встретится первое отрицательное значение:
for(s=0,j=0; j<n; j++)
{ if(a[j]<0) break;
s += a[j];
}
Однако если оператор break употреблен во внутреннем цикле, то с его
помощью нельзя выйти за пределы внешнего даже в том случае, когда
кажется, что тело внешнего цикла кончается там же, где и тело
внутреннего. На самом деле, в конце каждого цикла незримо присутствуют
системные вставки, обеспечивающие нормальный выход из цикла. В
частности, такие вставки возвращают память, выделенную под переменные,
объявленные в заголовке цикла. Кроме того, здесь же находятся команды,
возвращающие управление в начало цикла при необходимости повторения
итераций.
Оператор continue позволяет не выполнять расположенную ниже часть
тела цикла, но продолжить итерационный процесс. Пусть, например, нам
потребовалось найти среднее арифметическое среди положительных
элементов массив а:
for(s=0.0,j=0,k=0; j<n; j++)
{ if(a[j]<=0) continue;
s += a[j];
k++; //счетчик количества положительных слагаемых
}
if(k>0) s=s/k;
if, с
помощью которого можно было организовать разветвление по двум
направлениям: одно в случае истинности проверяемого условия, другое –
в случае ложности. Несколько операторов if позволяют сделать большее
количество разветвлений. Например, простейший калькулятор можно было
бы смоделировать следующим образом:
cin >>x>>y; //ввод операндов
cin >> ch; //ввод символа операции
if(ch=='+') {z=x+y; goto m;}
if(ch=='-') {z=x-y; goto m;}
if(ch=='*') {z=x*y; goto m;}
if(ch=='/' y!=0) {z=x/y; goto m;}
cout << "Эта операция не определена"<<endl;
z=0;
m:
cout << "Result="<<z<< endl;
Примерно такую же функциональность обеспечивает фрагмент программы
с переключателем switch:
cin >>x>>y; //ввод операндов
cin >> ch; //ввод символа операции
switch(ch)
{
case '+': z=x+y; break;
case '-': z=x-y; break;
case '*': z=x*y; break;
case '/': if(y!=0) {z=x/y; break;}
default : cout << "Эта операция не определена"<<endl; z=0;
}
cout << "Result="<<z<< endl;
После служебного слова switch (от англ. – переключатель) в круглых
скобках записывается переключающее выражение, которое может быть
целочисленным или символьным. Тело переключателя всегда является
case (от англ. – случай) записывается константа, с
которой сравнивается значение переключающего выражения. Если
совпадение обнаружено, то управление передается оператору, отделенному
от константы двоеточием. На его месте может оказаться либо один
оператор, либо цепочка операторов. И в том, и в другом случае эти
действия должны завершаться оператором break, передающим управление
оператору, расположенному вслед за переключателем.
Если значение переключающего выражения не совпадает с указанной
константой, то из тела переключателя выбирается следующая строка,
начинающаяся со служебного слова case, и проверки продолжаются. Самой
последней строкой переключателя может быть строка, начинающаяся со
служебного слова default. На нее
управление попадает только в том случае, когда значение переключающего
выражения не совпадает ни с одной из предусмотренных констант. В этом
случае выполняются операторы, отделенные от слова default двоеточием.
В переключателе может и не быть строки с непредусмотренной ситуацией,
тогда в случае несовпадения значения переключающего выражения ни с
одной из заданных констант переключатель ничего не делает, т.е.
срабатывает как пустой оператор.
Отсутствие оператора break в качестве завершающего
действия какой-либо группы приведет к тому, что начнут выполняться
операторы, принадлежащие следующей группе (в этом случае никакой
проверки на совпадение со следующей константой уже не происходит –
часть следующей строки "case c:" просто игнорируется).
Обращение к функциям, не возвращающим значение, выглядит следующим образом:
namef(a1,a2,...);
Здесь
namef – имя вызываемой функции;a1, a2, ... – список фактических параметровЕсли формальный параметр в заголовке функции объявлен как значение,
то соответствующим ему фактическим параметром может быть выражение
такого же типа. Если формальный параметр объявлен как указатель, то на
месте соответствующего ему фактического параметра может находиться
только адрес данного такого же void *,
им могут соответствовать . Для массивов адресом считается имя
массива. Например:
char str[80];
int x;
........
scanf("%d %s",x,str);
Однако если нам предстоит ввод в определенный элемент массива, то
нужно указывать его адрес. Например, str[5] или str+5:
scanf("%c",str[5]);
scanf("%c",str+5);
Если формальный параметр в описании функции объявлен как ссылка, то на месте соответствующего фактического параметра задается имя переменной. Например:
void swap(int a,int b)
{ int tmp=a;
a=b; b=tmp;
}
..........
swap(x,y);
Для функций, возвращающих значение, возможны два варианта вызова. Основной вариант предусматривает использование вызываемой функции в качестве операнда соответствующего выражения:
y=a*fin1(x,-2)+b;
В этом случае сначала будет вычислено значение операнда fin1(x,-2),
которое затем будет использовано при подсчете значения выражения.
Второй вариант заключается в игнорировании возвращаемого значения.
Пример подобного рода – использование функции scanf. Вообще говоря,
кроме своей основной миссии (ввод данных, поступающих с терминала),
она возвращает количество полей ввода, обработанных без ошибок. Для
организации тщательного контроля за вводимыми данными это значение
может оказаться полезным. Однако в большинстве практических программ
на языке C вы вряд ли обнаружите обращение следующего вида:
k=scanf("%d %s",x,str);
Комментарии – обязательная принадлежность каждой программы. В комментарий, расположенный вслед за заголовком функции, обычно выносится информация о назначении функции и смысле ее параметров. Описание нетривиального алгоритма, как правило, снабжается пояснениями, которые помогут разобраться в тексте программы персоналу сопровождения программных продуктов. Наконец, отключение части программы путем перевода ее в разряд комментариев – наиболее употребительный прием отладки программ.
В языках C, C++ предусматривается две разновидности комментариев – многострочные и однострочные.
Многострочные комментарии начинаются с пары символов " /* " и
заканчиваются такой же парой, записанной в обратном порядке – " */ ".
Комментарий подобного рода вовсе не обязан содержать несколько строк.
Он, в частности, может находиться в любом месте программной строки,
например, для исключения из рассмотрения компилятора фрагмента
формулы:
y=sin(/*x+*/0.25)*q;
Довольно часто в многострочный комментарий заключают фрагмент программы, который не должен компилироваться в текущем сеансе.
Однострочный комментарий начинается вслед за парой символов " // " и
продолжается до конца программной строки. Обычно с его помощью
записывается комментарий к текущей строке или исключается фрагмент
текущей строки из области обслуживания компилятором.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.