Идентификатор или имя функции 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Идентификатор или имя функции



Идентификатор (имя) функции задаётся точно также, как и любой другой идентификатор. В данном примере мы создали функцию с идентификатором simple_function (simple - простой).

 

Список аргументов или параметров

Список аргументов функции записывается в круглых скобках после имени функции. В данном примере список аргументов пуст.

Список аргументов записывается через запятую. Каждый элемент списка состоит из типа и идентификатора. Рассмотрим пример заголовка функции со списком из двух аргументов:

int simple (int a, float b)

 

В скобках мы записали два аргумента: a и b. У аргумента a тип int, а у аргумента b тип float.

Аргументы используются, когда в функцию нужно передать какие-либо данные из вызывающего окружения.

 

Тело функции

Тело функции располагается сразу под заголовком и заключено в фигурные скобки. В теле функции может содержаться сколько угодно операторов. Но обязательно должен присутствовать оператор return. Оператор return возвращает значение:

int simple_function ()

{

return 0;

}

Здесь, simple_function всегда будет возвращать 0. Надо признать, что данная функция бесполезна. Напишем функцию, которая принимает из вызывающего окружения два значения, складывает их и возвращает результат в вызывающее окружение. Назовём эту функцию sum (сумма):

int sum (int a, int b)

{

int c;

c = a + b;

return c;

}

В функцию передаётся два аргумента: a и b типа int. В теле функции они используются как обычные переменные (они и являются обычными переменными). Давайте договоримся: снаружи функции, переменные, которые передаются в неё, мы будем называть аргументами, а эти же переменные в теле функции - параметрами.

В теле функции определяется переменная c. А затем, в эту переменную мы помещаем значение суммы двух параметров.

Последняя строчка возвращает значение переменной c во внешнее окружение.

После ключевого слова return нужно указать значение которое будет возвращено. Можно возвращать как простые значения, так и переменные и даже выражения. Например:

return 32;

return a;

return b;

return a+b;

В последнем случае в вызывающее окружение будет возвращён результат суммы переменных a и b.

Обратите внимание, что оператор return не только возвращает значение, но и служит как бы выходом из функции, после него не будет выполнен ни один оператор:

return a;

c = a+b; // этот оператор не будет выполнен

Благодаря этому, с помощью return удобно создавать условия выхода из функций:

if (a > 0)

{

return 0;

}

else if (a < 0)

{

return 1

}

Здесь, из функции будет возвращено число в зависимости от значения переменной a: если a больше нуля, то будет возвращён 0, в противном случае - 1.

 

Вызов функции

После того как создано определение функции, её можно вызвать.

int sum (int a, int b)

{

int c;

c = a + b;

return c;

}

 

int main()

{

int s;

s = sum(2,2); // вызов функции

cout << s;

return 0;

}

В результате выполнения программы, на экран будет выведено: 4.

Вызов функции состоит из идентификатора функции и списка аргументов в круглых скобках. Вот несколько вызовов функции sum:

int x = 5;

int y = 4;

int z;

 

sum(0,1); // 1

sum(x,2); // 7

sum(x,y); // 9

z = sum(x,y); // z = 9

 

Вызывающее окружение

То место, откуда вызывается функция, называется вызывающим окружением. Вызывающим окружением функции sum является функция main, а вызывающим окружением функции main является отладчик или операционная система.

Функция может обмениваться данными с вызывающим окружением благодаря списку аргументов и возвращаемому значению: вызывающее окружение передаёт данные в функцию с помощью аргументов, а функция передаёт данные в вызывающее окружение с помощью возвращаемого значения.

Тип передаваемого в функцию значения должен совпадать с типом указанным в списке аргументов. Нельзя, например, написать вот так:

int simple (int a)

{

return 1;

}

 

int main ()

{

int b;

b = simple(0.5);

return 0;

}

В списке аргументов мы указали тип int, а в функцию передаётся вещественное значение 0.5. Так делать нельзя.

Рассмотрим более полезный пример: напишем функцию для передвижения персонажа:

int x; // глобальная переменная

 

int move_x (int dx)

{

x = x + dx;

return x;

}

 

int main ()

{

int ch;

char act;

 

while (1)

{

act = _getch();

ch = static_cast(act);

 

if (ch == 75) // была нажата стрелочка влево

move_x(-1);

else if (ch == 77) // была нажата стрелочка вправо

move_x(1);

} // конец while

return 0;

} // конец main

 

Обратите внимание, что для тела if и else if не стоит скобочек. Скобочки ветвлений можно опускать, если в теле ветвления всего один оператор.

Функция move_x двигает персонажа на одну единицу влево или вправо в зависимости от клавиши, которую нажал пользователь.

Создадим ещё одну функцию, а заодно уберём из main часть кода:

int x; // глобальная переменная

 

int move_x (int dx)

{

x = x + dx;

return x;

}

 

void move (int ch)

{

if (ch == 75) // была нажата стрелочка влево

move_x(-1);

else if (ch == 77) // была нажата стрелочка вправо

move_x(1);

}

 

int main ()

{

int ch;

char act;

 

while (1)

{

act = _getch();

ch = static_cast(act);

move(ch); // вызов функции move

} // конец while

return 0;

} // конец main

 

Обратите внимание, что в функции move на месте типа возвращаемого значения стоит void, кроме того, в теле move нет оператора return.

Объявления функций (прототипы)

В последнем примере, определение функции move_x должно располагаться выше определения move (а определения move_x и move должны располагаться до main), так как в функции move происходит вызов move_x.

Обычно определения всех пользовательских функций располагаются после определения main. При этом используются объявления функций (прототипы). Внесём изменения в предыдущую программу:

int x; // глобальная переменная

 

void move(int); // прототип (объявление) функции move

int move_x(int); // прототип функции move_x

 

int main ()

{

int ch;

char act;

while (1)

{

act = _getch();

ch = static_cast(act);

move(ch); // вызов move

}

return 0;

}

 

void move (int ch)

{

if (ch == 75) // была нажата стрелочка влево

move_x(-1);

else if (ch == 77) // была нажата стрелочка вправо

move_x(1);

}

 

int move_x (int dx)

{

x = x + dx;

return x;

}

Прототип функций совпадает с заголовком определения, но в прототипе можно опустить имена переменных в списке аргументов. Следующие объявления равносильны:

int move_x(int dx);

int move_x(int);

Объявления функций расположены в начале файла. Прототип функции говорит компилятору, что данную функцию можно вызывать, а её определение будет позже (или находится в другом файле).

Объявление функции может находиться в любом месте программы (за пределами определений функций программы или в любом определении), главное, чтобы оно появилось до первого вызова функции. Если вы не используете объявления, то до первого вызова функции должно стоять определение, которое также может располагаться в любом месте программы.

Возврат void

На месте возвращаемого типа, в определении (и в объявлении) функции move стоит ключевое слово void (void - пусто, пустой). Это значит, что функция не возвращает никакого значения. Следовательно не требуется и оператор return, так как функции нечего вернуть в вызывающее окружение.

Указатели в Си.  Использование указателей при обработке одномерных и двумерных массивов.

Си тіліндегі көрсеткіштер. Бірөлшемді және екіөлшемді массивтерді өңдеу барысында көрсеткіштерді қолдану.

Указатели и массивы

Для работы с адресами памяти используются указатели.

int *a; // указатель на переменную целого типа
float *addr_f; // указатель на переменную вещественного типа

 

Размер памяти для переменной-указателя зависит от конфигурации машины. Конкретный адрес является указателем и получается с помощью операции &(адресации). Адресация не может применяться к переменным класса памяти register и к битовым полям структур. Разадресация * применяется для получения значения величины, указатель которой известен. Если значение указателя нулевое, то результат разадресации непредсказуем.

int *рa, x; int a[20]; double d;
рa= &a[5]; // это адрес 6-го элемента массива а
х = *рa; // x присваивается значение 6-го элемента массива а
if (x==*&x) cout<<"true\n"; d=*(double *)(&x);
// адрес х преобразуется к указателю на double и d=x.


       Указатель - это переменная, содержащая адрес другой переменной. Указатели очень широко используются в языке Cи. Это происходит отчасти потому, что иногда они дают единственную возможность выразить нужное действие, отчасти потому, что они обычно ведут к более компактным и эффективным программам, чем те, которые могут быть получены другими способами. Так как указатель содержит адрес объекта, это дает возможность "косвенного" доступа к этому объекту через указатель. Предположим, что X - переменная, например, типа int, а РX - указатель, созданный неким еще не указанным способом. Унарная операция & выдает адрес объекта, так что оператор РX = &X; присваивает адрес X переменной РX; говорят, что РX"указывает" на X. Операция & применима только к переменным и элементам массива, конструкции вида &(X-1) и &3 являются незаконными. Нельзя также получить адрес регистровой переменной.

Унарная операция * рассматривает свой операнд как адрес конечной цели и обращается по этому адресу, чтобы извлечь содержимое. Следовательно, если Y тоже имеет тип int, то Y = *РX; присваивает Y содержимое того, на что указывает РX. Последовательность РX = &X; Y = *РX; присваивает Y то же самое значение, что и оператор Y = X; Переменные, участвующие во всем этом, необходимо описать: int X, Y; int *РX; Описание указателя int *РX; должно рассматриваться как мнемоническое; оно говорит, что комбинация *РX имеет тип int. Это означает, что если РX появляется в контексте *РX, то это эквивалентно переменной тип int. Фактически синтаксис описания переменной имитирует синтаксис выражений, в которых эта переменная может появляться. Это замечание полезно во всех случаях, связанных со сложными описаниями. Например, double atof(), *DР; говорит, что atof() и *DР имеют в выражениях значения типа double.


       Указатели могут входить в выражения. Например, если РX указывает на целое X, то*РX может появляться в любом контексте, где может встретиться X. Оператор Y = *РX + 1; присваивает Y значение, на 1 большее значения X; printf("%d\n", *РX) печатает текущее значение X; D = sqrt((double) *РX) получает в D квадратный корень из X, причем до передачи функции sqrt значение X преобразуется к типу double. В выражениях вида Y = *РX + 1 унарные операции * и & связны со своим операндом более крепко, чем арифметические операции, так что такое выражение берет то значение, на которое указывает РX, прибавляет 1 и присваивает результат переменной Y.


       Ссылки на указатели могут появляться и в левой части присваивания. Если РXуказывает на X, то *РX = 0 полагает X равным нулю, *РX += 1 увеличивает его на единицу, как и выражение (*РX)++. Круглые скобки в последнем примере необходимы; если их опустить, то это выражение увеличит РX, а не ту переменную, на которую он указывает. Если РY - другой указатель на переменную типа int, то РY = РX копирует содержимое РX в РY, в результате чего РY указывает на то же, что и РX.

       Массив рассматривается как набор элементов одного типа. Чтобы объявить массив, необходимо в описании поcле имени массива в квадратных скобках указать его размерность.

int а[5]; // массив, состоящий из 5 целых переменных
char sym[20]; // массив из 20 символьных переменных
double c[10]; // массив из 10 вещественных величин.

       Индексы элементов изменяются от 0 до N-1, где N- размерность массива. Переменная типа массив является указателем на элементы массива.
Многомерный массив определяется путем задания нескольких константных выражений в квадратных скобках:

float d_l[3][5], c_dim[5][3][3];

       Элементы массива запоминаются в последовательных возрастающих адресах памяти. Хранятся элементы массива построчно. Для обращения к элементу массива вычисляется индексное выражение. Для a[i] индексное выражение равно *(а+ i), где а - указатель, например, имя массива; i - целая величина, преобразованная к адресному типу; * - операция разадресации. Для двумерного массива b[i][j] индексное выражение:*(b+i+j).

 

Рассмотрим пример ввода/вывода значений элементов массива с помощью функций scanf и рrintf:

#include <stdio.h> // подключается файл с прототипами функций scanf и рrintf
void main(void) { int a[3]; int i; float b[4]; double c[2];
for (i=0; i<3; i++) { scanf("%d ", &a[i]); рrintf("%d", a[i]); }
i=0; while (i < 4)
{scanf ("%f",b[i]); рrintf("%g",b[i]); i++;}
i=0; do
{ scanf("%lf ", &c[i]); рrintf("%g", c[i]); i++;}
while(i< 2); } }

Динамически выделять память под массивы и другие объекты можно с помощью функций calloc, malloc:

int *dim_i, n_dim_i;
n_dim_i =10;
dim_i =(int *)calloc(n_dim_i*sizeof(int));...

Тогда освобождать память необходимо функцией free:

free(dim_i);

При использовании функицй calloc, malloc, free в текст программы требуется включить файл описаний этих функций alloc.h:


#include <alloc.h>

В Си++ динамическое распределение памяти проводится оператором new, а освобождение - оператором delete. Выделенная по new область памяти занята до соответствующего delete или до конца программы.

int *i_рtr; i_рtr=new int; // резервируется память под величину int
d_рtr = new double(3.1415); // то же, что и *i_рtr=3.1415
c_рtr = new char[str_len]; // область памяти для str_len символов

Реальный размер выделяемой памяти кратен опеределенному числу байт. Поэтому невыгодно выделять память по new для небольших объектов. Если new не может выделить блок памяти, то она возвращает значение NULL.
Примеры освобождения памяти оператором delete:

delete i_рtr; delete d_рtr; delete [str_len] c_рtr;

Результат delete непредсказуемый, если переменная, записанная после него, не содержит адрес блока памяти или равна NULL.

Символьные строки и функции над строками. Функции операции над строками.

Символдық жолдар және жолдарға қолданылатын функциялар. Жолдарға қолданылатын опреациялардың функциялары.

Сөз тіркестерін өңдейтін басқа функциялар.

Сөз тіркестерін енгізу-шығару функциялары

 

Символдар тіркесін пернелерден енгізу үшін екі стандартты функция – scanf() немесе gets() қолданылады, ал олардың прототиптері stdio.h тақырыптық файлында болады.

 

Scanf () функциясы тіркестік айнымалылар мәнін %s форматымен енгізеді, бірақ ол тіркесті тек бірінші босорын таңбасына дейін ғана енгізе алады.  

 

Ал gets() функциясы арасында босорыны бар тіркестерді енгізеді, енгізу ENTER пернесімен аяқ-талады. Екі функция да тіркес соңына нөлдік байт қо-сып жазады. Оның үстіне тіркес – символдық жиым, ал жиым аты – оның компьютер жадындағы алғашқы адресіне сілтеме болғандықтан, тіркестік айнымалы атының алдына «&» символы жазылмайды.

 

Бір мысал келтірейік.

 

/*сөз тіркесін шығару*/

#include <conio.h>

#include <stdio.h>

Void mai n()

{

 char b[]=” Сезам, ашыл! ”;

 clrscr();

 printf("%s",b);

 getch();

 }

 

Мұндағы b жиымының ұзындығы 13 символ, яғни сөздер ұзындығынан 1-ге артық.

Сөз тіркестерін шығару функциялары:



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 27; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.218.218.230 (0.055 с.)