Индивидуальное задание к лабораторной работе №15 взять из работы №3.
Контрольные вопросы для подготовки и самостоятельной работы
1 Можно ли использовать указатели в качестве данных-членов структур?
2 Можно ли использовать массивы и структуры в качестве данных-членов структур (вложенные объявления)?
3 Можно ли использовать в качестве вложенных структуры объявляемого (своего) типа, а также указатели на структуры своего типа?
4 Как объявить указатель на структуру, массив указателей на структуры? Существуют ли различные варианты объявления?
5 Можно ли использовать typedef для объявления типа структуры?
6 Как получить доступ к элементу структуры с помощью указателя?
7 Как осуществляется доступ к данным-членам структуры при использовании массива указателей на структуры?
8 Можно ли использовать различные классы памяти применительно к переменным структурного типа?
9 Обязательно ли указывать ключевое слово struct при объявлении структурного типа, переменных структурного типа?
10 Можно ли хранить адрес структуры в самой структуре?
Лабораторная работа № 16
Использование указателей для работы с функциями
(2 часа)
Цель работы: выработать практические навыки в написании программ с функциями и в использование указателей для работы с функциями.
Теоретические сведения
С позволяет использовать указатели на базовые типы, на массивы и структуры как параметры передаваемые в функцию и возвращаемые из функции, а также указатели на функции. Общий синтаксис для объявления указателя на структуру как параметры функции:
[const ]<тип>*<имя указателя>
При объявлении функции имя указателя как формального параметра может не указываться аналогично другим видам формальных параметров.
Ключевое слово const предохраняет данные от изменения данных в структуре функции, тогда как отсутствие ключевого слова const позволяет функции изменять значения данных, т.к. при использовании указателей в теле функции известны физические адреса переменных.
Пример использования указателей на различные типы данных как параметры функции.
int funct (float*, int*); // передача указателей на тип float и на тип int
Struct Мyst
{
//члены;
};
void loadMy(Myst*pmy); // передача указателя рmу натип структур типа Муst.
В примере объявлена структура типа Myst и объявлена функция loadMy(). Функция имеет формальный параметр-указатель pmy на тип Мyst.
Вызов функции funct() и fn():
Float*pf; int*pl;
Int a = funct(pf, pl); fn(pf);
Объявление указателя на функцию аналогично объявлению функций, с которыми он будет использоваться. Например
void (* pfunc) (int, int);
Объявлен указатель pfunc на функцию, которая требует два параметра типа int и не возвращает значения (void). Типы и количество параметров, а также тип возвращаемого значения должны создать. Для использования указателя объявим функцию
void f1 (int, int);
Присвоим указателю адрес функции
pfunc= f1;
и осуществим её вызов
(*pfunc)(2,4);
Указатели как параметры функции
Указатели широко используются при передаче аргументов в функцию и из функции, создавая двухсторонний поток данных между вызываемой и вызывающей функциями.
Для передачи аргументов в функцию используют:
1 Указатели на простые типы данных, как параметры функции.
2 Указатели на массивы (передавать по значению нельзя).
3 Указатели на перечислимые типы как параметры функции.
4 Указатели на структуры и объединения как параметры функции.
5 Указатели на функции (передавать по значению нельзя).
С позволяет объявлять и использовать указатели на функции. В таком указателе хранится адрес функции, т.е. адрес первого выполнимого оператора. Указатель на функцию можно использовать для её вызова. Общий синтаксис для объявления указателя на функцию:
<тип_возвращаемого_значения> (*<имя_указателя_на_функцию>) (<объявления_типов_параметров>);
При инициализации указателя на функцию нужно использовать имя функции, у которой тип возвращаемого значения и список типов параметров соответствуют объявлению указателя. Имя функции имеет тип указателя на функцию с заданными для неё в объявлении типами параметров и возвращаемого значения.
Инициализация указателя на функцию:
<имя_указателя> = <имя_функции>;
Общий синтаксис для вызова функции с использованием указателя:
(*<имя_указателя>)(<список_фактических_параметров>);
Пример
int linescarch (int)*pstring //объявление функции linesearch (int*)
Voild main()
{int a; * pstr = “Hello World!”; // объявление переменной и указателя pstr на тип int
int (*search)(int*); // объявление указателя на функцию
search= linesearch; //присваиваем адрес функции linesearch() указателю search
//другие операторы
a = (* search)(pstr); // вызов функции linesearch () с помощью указателя.
}
Пример
/* ЗАНЯТИЕ N 16
Разработал Петров Ю.В.
Объявить заданные функции и указатель на функцию этого типа,
выполнить определение функций. Объявить массивы и указатели
на них, выполнить инициализацию в соответствии с заданными
зависимостями и использованием указателей. Для одного из
массивов выделить память в куче. Вывести значения элементов
массивов на экран. Осуществить вызов функций с применением
указателя. Вывести результаты работы функций на экран. */
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include <iostream.h>
const int kx = 6, ky = 6, kw = 8, a1 = 3, a2 = 9,
b1 = 6, b2 = 5, c1 = 6, c2 = 10;
//Вычисляет сумму отрицательных элементов массива
float summa (int, float*);
//Вычисляет произведение положительных элементов массива
float prois (int, float*);
float (*ps)(int, float*); //Объявление указателя на функцию
void main ()
{
int i;
float y[ky+2]; //+2 элемента массива для хранения
// результатов работы функций
float *px=new float [kx+2];//Выделение памяти для массива в "куче"
float *xptr;
clrscr();
printf("Массив x[]\n");
for (i=0; i<kx; i++)
{ *px = a1*i*i - a2*(5-i); //Инициализация динамического массива
printf("x[%d] = %6.2f %p \n",i, *px, px);
px++;
}
xptr = y;
gotoxy(25,1); printf("Массив y[]\n");
for (i=0; i<ky; i++)
{ *xptr = b1*sin(2*i) + b2*exp(i-5); //Инициализация массива y[]
gotoxy(30,i+2);
printf("y[%d] = %6.2f\n",i,*xptr);
xptr++;
}
px-=kx; //Установка указателя на нулевой элемент массива
printf("Указатель на дин. массив содержит адрес рx = %p\n ", px);
ps=summa; //Связывание указателя с функцией summa()
printf("Указатель на функцию содержит адрес рs = %p\n ", ps);
printf("Сумма: x[%d] = %6.2f ", kx, (*ps)(kx, px));
printf("Сумма: y[%d] = %6.2f\n ", ky, (*ps)(ky, y));
ps=prois; //Связывание указателя с функцией prois()
printf("Указатель на функцию содержит адрес рs = %p\n ", ps);
printf("Произведение: x[%d] = %8.2f ", kx+1, (*ps)(kx, px));
printf("Произведение: y[%d] = %8.2f\n ", ky+1, (*ps)(ky, y));
delete [] px; //Освобождение памяти, выделенной в "куче"для массива
getch();
}
float summa (int kol, float* Arr) //Определение функции
{ float s=0;
for (int i=0; i<kol; i++) if (Arr[i]<0) s+=Arr[i];
return s;
}
float prois (int kol, float* Arr) //Определение функции
{ float s=1;
for (int i=0; i<kol; i++) if (Arr[i]>0) s*=Arr[i];
return s;
}
/*
Массив x[] Массив y[]
x[0] = -45.00 0AD0 y[0] = 0.03
x[1] = -33.00 0AD4 y[1] = 5.55
x[2] = -15.00 0AD8 y[2] = -4.29
x[3] = 9.00 0ADC y[3] = -1.00
x[4] = 39.00 0AE0 y[4] = 7.78
x[5] = 75.00 0AE4 y[5] = 1.74
Указатель на дин. массив содержит адрес рx = 0AD0
Указатель на функцию содержит адрес рs = 049C
Сумма: x[6] = -93.00 Сумма: y[6] = -5.29
Указатель на функцию содержит адрес рs = 04F3
Произведение: x[7] = 26325.00 Произведение: y[7] = 2.52 */
Ход работы
1 Изучить теоретические сведения.
2 В соответствии с индивидуальным заданием по лабораторной работе №7. разработать алгоритм.
3 Объявить указатели на функции. Использовать указатели для вызова соответствующих функций. Использовать оператор switch для выбора варианта функций.
4 Разработать и набрать программу на компьютере, устранить ошибки.
5 Получить результат.
6 Оформить отчет.
7 Подготовиться к защите лабораторной работы, изучив контрольные вопросы.
Индивидуальное задание к лабораторной работе №16
Составить программу использующую вызовы функций с помощью указателей. Индивидуальные задания приведены в таблице 16.1.
Таблица 16.1 - индивидуальные задания
Вариант | первая функция | вторая функция | третья функция | четвертая функция |
int (*func1) (int *) | int (*func2) (int *,float *) | int (*func3) (void *) | char *func4 (char *,…) | |
float (*func1) (int *, float *, double *) | float (*func2) (void *,…) | float (*func3) (int, …) | double (*func4 (double, double))[3] | |
void (*func1) (void *, int *) | void (*func2) (int, int *) | void (*func3) (void) | int (*func4 (void))(int) | |
double (*func1) (float *, int) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | int (*func4(int)) (int)[3][5] | |
long double (*func1) (int *, float *) | long double (*func2) (void *, …) | long double (*func3) (int, …) | char * (*func4 (int *, …))(void *) | |
char (*func1) (unsigned int *) | char (*func2) (int *, float *, double *) | char (*func3) (void *,…) | int *func4(char *, int *,…) | |
long int (*func1) (int, int *) | long int (*func2)(double, long int) | long int (*func3)(void) | float (*func4 (double)(void)) [10] | |
unsigned int (*func1) (int *) | unsigned int (*func2) (int, …) | unsigned int (*func3) (int *,float *) | long int (*func4(int)) (void) | |
float (*func1) (int *, float *, double *) | float (*func2) (unsigned int *) | float (*func3) (void) | void *func4 (int *, int, …) | |
unsigned long int (*func1) (int, …) | unsigned long int (*func2) (int *) | unsigned long int (*func3) (double, long int) | float (*func4(long int, int))[5] | |
signed int (*func1) (int *, float *, double *) | signed int (*func2) (int) | signed int (*func3) (void *, …) | double (*func4 (char)(int *))[4] | |
double (*func1) (float *, int) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | double (*func4 (double, double))[3] | |
long double (*func1) (int *, float *) | long double (*func2) (void *, …) | long double (*func3) (int, …) | int (*func4 (void))(int) | |
char (*func1) (unsigned int *) | char (*func2) (int *, float *, double *) | char (*func3) (void *,…) | int (*func4(int)) (int)[3][5] | |
long int (*func1) (int, int *) | long int (*func2)(double, long int) | long int (*func3)(void) | char * (*func4 (int *, …))(void *) | |
unsigned int (*func1) (int *) | unsigned int (*func2) (int, …) | unsigned int (*func3) (int *,float *) | int *func4(char *, int *,…) | |
int (*func1) (int *) | int (*func2) (int *,float *) | int (*func3) (void *) | float (*func4 (double)(void)) [10] | |
float (*func1) (int *, float *, double *) | float (*func2) (void *,…) | float (*func3) (int, …) | long int (*func4(int)) (void) | |
void (*func1) (void *, int *) | void (*func2) (int, int *) | void (*func3) (void) | int *func4(char *, int *,…) | |
double (*func1) (float *, int) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | float (*func4 (double)(void)) [10] | |
long double (*func1) (int *, float *) | long double (*func2) (void *, …) | long double (*func3) (int, …) | long int (*func4(int)) (void) | |
char (*func1) (unsigned int *) | char (*func2) (int *, float *, double *) | char (*func3) (void *,…) | void *func4 (int *, int, …) | |
unsigned long int (*func1) (int, …) | unsigned long int (*func2) (int *) | unsigned long int (*func3) (double, long int) | float (*func4(long int, int))[5] | |
signed int (*func1) (int *, float *, double *) | signed int (*func2) (int) | signed int (*func3) (void *, …) | double (*func4 (char)(int *))[4] | |
double (*func1) (float *, int) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | char *func4 (char *,…) | |
long double (*func1) (int *, float *) | long double (*func2) (void *, …) | long double (*func3) (int, …) | double (*func4 (double, double))[3] | |
char (*func1) (unsigned int *) | char (*func2) (int *, float *, double *) | char (*func3) (void *,…) | int (*func4 (void))(int) | |
double (*func1) (int *, float *, double *) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | int (*func4(int)) (int)[3][5] | |
void (*func1) (void *, int *) | void (*func2) (int, int *) | void (*func3) (void) | char * (*func4 (int *, …))(void *) | |
double (*func1) (float *, int) | double (*func2) (double, long int) | double (*func3) (unsigned int *) | int *func4(char *, int *,…) |