Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Возврат Значения (оператор return)




Из функции, которая не описана как void, можно (и должно) возвращать значение. Возвращаемое значение задается оператором return.

Например:

int fac(int n) {return (n>1)? n*fac(n-1): 1; }

В функции может быть больше одного оператора return:

int fac(int n)

{

if (n > 1)

return n*fac(n-1);

else

return 1;

}

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

Например:

double f()

{

//...

return 1; // неявно преобразуется к double(1)

}

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

int* f() {

int local = 1;

//...

return &local; // так не делайте

}

Эта ошибка менее обычна, чем эквивалентная ошибка при использовании ссылок:

int& f() {

int local = 1;

//...

return local; // так не делайте

}

К счастью, о таких возвращаемых значениях предупреждает компилятор.

Вот другой пример:

int& f() { return 1;} // так не делайте

Активизация функции

С функцией можно делать только две вещи: вызывать ее и брать ее адрес. Указатель, полученный взятием адреса функции, можно затем использовать для вызова этой функции.

Например:

void error(char* p) { /*... */ }

void (*efct)(char*); // указатель на функцию

void f()

{

efct = &error; // efct указывает на error

(*efct)("error"); // вызов error через efct

}

Чтобы вызвать функцию через указатель, например, efct, надо сначала этот указатель разыменовать, *efct. Поскольку операция вызова функции () имеет более высокий приоритет, чем операция разыменования *, то нельзя писать просто *efct("error"). Это означает *efct("error"), а это ошибка в типе. То же относится и к синтаксису описаний.

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

Например:

void (*pf)(char*); // указатель на void(char*)

void f1(char*); // void(char*)

int f2(char*); // int(char*)

void f3(int*); // void(int*)

void f()

{

pf = &f1; // ok

pf = &f2; // ошибка: не подходит возвращаемый тип

pf = &f3; // ошибка: не подходит тип параметра

(*pf)("asdf"); // ok

(*pf)(1); // ошибка: не подходит тип параметра

int i = (*pf)("qwer"); // ошибка: void присваивается int"у

}

Правила передачи параметров для непосредственных вызовов функции и для вызовов функции через указатель одни и те же.

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

Например:

typedef int (*SIG_TYP)(); // из

typedef void (*SIG_ARG_TYP);

SIG_TYP signal(int,SIG_ARG_TYP);

Бывает часто полезен вектор указателей на функцию. Например, система меню для моего редактора с мышью*4 реализована с помощью векторов указателей на функции для представления действий. Подробно эту систему здесь описать не получится, но вот общая идея:

typedef void (*PF)();

PF edit_ops[] = { // операции редактирования

cut, paste, snarf, search

};

PF file_ops[] = { // управление файлом

open, reshape, close, write

};

Затем определяем и инициализируем указатели, определяющие действия, выбранные в меню, которое связано с кнопками (button) мыши:

PF* button2 = edit_ops;

PF* button3 = file_ops;

В полной реализации для определения каждого пункта меню требуется больше информации. Например, где-то должна храниться строка, задающая текст, который высвечивается. При использовании системы значение кнопок мыши часто меняется в зависимости от ситуации. Эти изменения осуществляются (частично) посредством смены значений указателей кнопок. Когда пользователь выбирает пункт меню, например пункт 3 для кнопки 2, выполняется связанное с ним действие:

(button2[3])();

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

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

typedef int (*CFT)(char*,char*);

int sort(char* base, unsigned n, int sz, CFT cmp)

{

for (int i=0; iname, Puser(q)->name);

}

int cmp2(char*p, char* q) // Сравнивает числа dept

{

return Puser(p)->dept-Puser(q)->dept;

}

Эта программа сортирует и печатает:

main ()

{

sort((char*)heads,6,sizeof(user),cmp1);

print_id(heads,6); // в алфавитном порядке

cout << "n";

sort((char*)heads,6,sizeof(user),cmp2);

print_id(heads,6); // по порядку подразделений

}

Можно взять адрес inline-функции, как, впрочем, и адрес перегруженной функции.


ПРАКТИЧЕСКАЯ ЧАСТЬ

Задание: Элемент матрицы называется локальным минимумом, если он строго меньше всех имеющихся у него соседей. Подсчитать количество локальных минимумов заданной матрицы размером 10х10.

Решение: Тут все проще, чем кажется. Для начала нужно задать массив, нужного размера, потом в цикле сравниваем каждый элемент массива с соседними элементами.

 
 


-
+
-
-
+
+
Элемент меньше всех соседних элементов
Инкрементируем счетчик
Задаем массив

Текст программы:

#include <vcl.h>

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#pragma hdrstop

#include <iostream>

#include <iomanip>

using namespace std;

 

#pragma argsused

 

int main(int argc, char* argv[])

{int A[10][10],i,k,z=0,n=1; //описываем переменные

 

srand(time(NULL));

for(i=0;i<10;i++) //цикл для создания массива

{ cout<<endl;

for(k=0;k<10;k++)

{A[i][k]=(50-(rand()%70));

cout<<setw(4)<<A[i][k];

}}

cout<<endl<<endl;

for(i=0;i<10;i++) // цикл для сравнения элементов массива

{

for(k=0;k<10;k++)

{ if ((A[i][k]<A[i-1][k-1])&&(A[i][k]<A[i-1][k])&&(A[i][k]<A[i-1][k+1])&&(A[i][k]<A[i][k+1])&&(A[i][k]<A[i+1][k+1])&&(A[i][k]<A[i+1][k])&&(A[i][k]<A[i+1][k-1])&&(A[i][k]<A[i][k-1])) // сравнение элементов

{z=z++;

cout<<"Lokalniy minimum #"<<n<<": "; //вывод значений на экран

n=n++;

cout<<A[i][k]<<endl;}}}

cout<<endl<<"Kol-vo lokalnih minimumov: "<<z<<endl;

system ("pause");

return 0;

}

Рисунок 1 – Окно программы.

Заключение

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

В процессе выполнения практического задания я освоил приемы работы с числовыми матрицами. Созданная прикладная программа работает правильно, в соответствии с поставленной задачей.


Список литературы

1. Язык программирования С++. Вводный курс. Четвёртое издание. [Вильямс, 2007] (Стенли Липпман, Жози Лажойе)

2. Прототипы функций в С++[http://cppstudio.com/uchebniki/yazyk-programmirovaniya-s/prototipy-funkcij-v-s/]

3. Функции в C++[http://code-live.ru/post/cpp-functions/]

 





Поделиться с друзьями:


Дата добавления: 2017-02-11; Мы поможем в написании ваших работ!; просмотров: 443 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Велико ли, мало ли дело, его надо делать. © Неизвестно
==> читать все изречения...

2460 - | 2139 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.012 с.