Опубликован: 14.12.2010 | Доступ: платный | Студентов: 48 / 8 | Оценка: 4.53 / 4.12 | Длительность: 26:28:00
Лекция 12:

Указатели и функции в языке программирования С

< Лекция 11 || Лекция 12: 1234 || Лекция 13 >
Аннотация: В лекции изучаются вопросы программирования функций, аргументами которых могут быть указатели, а также функции, возвращающие значения через указатели. В практической части рассматриваются примеры с их полной программной реализацией.

Теоретическая часть

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

Ранее было отмечено, что в языке С аргументы передаются в функции по значению и не существует прямого способа изменить переменную вызывающей функции, действуя внутри вызываемой функции. Благодаря аргументам-указателям функция может обращаться к объектам в вызвавшей ее функции, в том числе модифицировать их [11.1]. В качестве примера рассмотрим функцию swap(), в задачу которой входит обмен элементов местами. Для решения такой задачи необходимо передать из вызывающей программы (например, из главной функции main() ) в функцию указатели на переменные, которые нужно изменить. Программный код решения примера:

#include <stdio.h>
#include <conio.h>

// Прототип функции
void swap(int*, int*);

int main (void) {
	int a = 10,
		b = -20;
	
    // Вывод на консоль исходных значений переменных
    printf("\n Initial values:\n a = %d, b = %d\n", a, b);
    
    // Вызов функции swap() с фактическими параметрами
     swap(&a, &b);
    
    // Результат после обращения функции swap()
     printf("\n New values:\n a = %d, b = %d\n", a, b);

	printf("\n ... Press any key: ");
	_getch();
	return 0;
}

// Определение функции
void swap(int *pa, int *pb)
{
int temp;
temp = *pa;
*pa = *pb;
*pb = temp;
}

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

Результат выполнения программы показан нa рис. 11.1.

Результат обмена данными, выполненного функцией swap()

Рис. 11.1. Результат обмена данными, выполненного функцией swap()

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

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

Общая форма определения функции, которая возвращает указатель, следующая:

тип  *имя_функции ( аргументы функции ) 
{
// тело функции

тип *имя_указателя;
?

return  имя_указателя;
}

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

Программный код решения примера:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int *out2(int A[], int B[], int);

int main (void) {
	int i, n;
	int A[] = {1,2,3,4,5};
	int B[] = {2,2,2,2,2};
	int *ptrAB = NULL;

	n = (sizeof(A)/sizeof(A[0]));

	puts("\n The initial arrays: ");
	for (i = 0; i < n; i++)
		printf(" %d", A[i]);
	
     puts("");
	for (i = 0; i < n; i++)
		printf(" %d", B[i]);

	ptrAB = out2(A, B, n);
	puts("\n\n Result from function: ");
	for (i = 0; i < n; i++)
		printf(" %d", ptrAB[i]);

	puts("\n\n Control of the arrays: ");
	for (i = 0; i < n; i++)
		printf(" %d", A[i]);
	
     puts("");
	for (i = 0; i < n; i++)
		printf(" %d", B[i]);

     free(ptrAB); // освобождение выделенной памяти

	printf("\n\n ... Press any key: ");
	_getch();
	return 0;
}

int *out2(int A[], int B[], int n)
{
     int i;
int *ptr = (int *)calloc(n, sizeof(int)); //выделение памяти

     for (i = 0; i < n; i++)
     ptr[i] = A[i] + B[i];

     return ptr;
}

Программа не требует особых пояснений.

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

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

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

Указатель на функцию – это переменная, содержащая адрес в памяти, по которому расположена функция [11.2]. Имя функции – это адрес начала программного кода функции. Указатели на функции могут быть переданы функциям в качестве аргументов, могут возвращаться функциями, сохраняться в массивах и присваиваться другим указателям на функции [11.2].

Типичное определение указателя на функцию следующее:

тип_возвращаемый_функцией(*имя_указателя_на_функцию)(аргументы);

В приведенном объявлении используются круглые скобки, в которых собственно и определяется указатель на функцию, которая возвращает тот или иной тип – тип_возвращаемый_функцией. Хотя знак * обозначает префиксную операцию, он имеет более низкий приоритет, чем функциональные круглые функции, поэтому для правильного комбинирования частей объявления необходимы еще и дополнительные скобки [11.1]. При этом аргументы – это аргументы той или иной функции с заданным типом возвращаемого значения, и на которую ссылается указатель *имя_указателя_на_функцию. Очевидно, что возможны сложные объявлений функций.

Указатели на функции часто используются в системах, управляемых меню [11.2]. Пользователь выбирает команду меню (одну из нескольких). Каждая команда обслуживается своей функцией. Указатели на каждую функцию находятся в массиве указателей. Выбор пользователя служит индексом, по которому из массива выбирается указатель на нужную функцию.

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

< Лекция 11 || Лекция 12: 1234 || Лекция 13 >
Мухаммадюсуф Курбонов
Мухаммадюсуф Курбонов