книги / Язык Си
..pdfНаличие круглых скобок в имени указателя на функцию обя зательно.
Перед использованием указателя на функцию необходимо его инициализировать, т.е. присвоить ему адрес первой ячейки облас ти памяти, где расположена функция.
2 |
0.5 |
Пример. Вычислить интегралы
методом прямоугольников.
#include<stdio.h>
#include<conio.h>
#include<math.h>
//Объявление указателя на функцию double (*f)(double);
//Прототип функции интегрирования //методом прямоугольников
double rectangle(double, double, double =0.01);
//Подынтегральная функция первого интеграла double fl(double x)
{
return x/pow(x*x+l,2);
}
//Подынтегральная функция второго интеграла double f2 (double x)
{
return 4*cos(x)*cos(x);
}
//Главная функция main()
{f=fl; //настраиваем указатель на первую функцию
//вычисляем интеграл и печатаем ответ printf("S_fl=%f\п",rectangle(-1,2) );
f=f2; //настраиваем указатель на вторую функцию
//вычисляем интеграл и печатаем ответ printf("S_f2=%f",rectangle(0,0.5));
getch() ; return 0;
}
// Интегрирование методом прямоугольников double rectangle(double a, double b, double h) {double x=a,s=0;
while(x<=b)
{s+=(f(x)+f(x+h))/2*h;
x+=h;
}
return s;
Обращаем ваше внимание на то, что указатель на функцию в данном примере является глобальным, т.е. виден во всех функци ях: main, rectangle и т.д.
Если не использовать указатель на функцию, тогда в функ ции, вычисляющей интеграл (rectangle), нужно было бы ввести еще один параметр (например, пит), по которому можно ориенти роваться, какой интеграл вычислять.
double rectangle(int num, double a, double b, double h)
{double x=a,s=0;
if(num==l)
while(x<=b)
{s+=(fl(x )+f1 (x+h))/2*h;
x+=h;
}
else if(num==2)
while(x<=b)
{s+=(f2 (x)+f2(x+h))/2*h;
x+=h;
}
return s;
}
Таким образом, гораздо удобнее использовать только одно имя - указатель, который предварительно настроен на нужную функцию.
Также из указателей на функции можно формировать масси вы. Объявление массива указателей на функции имеет вид
тип (*имя массива[размер])(список параметров);
Вычислим интегралы из предыдущего примера.
#include<stdio.h>
#include<conio.h>
#includecmath.h>
//глобальный массив указателей на функции double (*f[2])(double);
double rectangle (int,double, double, double=0.01);
double fl(double x) {return x/pow(x*x+l,2) ;
}
double f2(double x) {return 4*cos(x)*cos(x);
}
main()
{//инициализация элементов массива //указателей на функции
f [0]= f 1;
f[l]=f2;
//выполнение интегрирования printf("S_fl=%f\n",rectangle(0,-1,2)); printf("S_f2=% f",rectangle(1,0,0.5));
getch(); return 0;
}
double rectangle(int i, double a, double b, double h)
{double x=a,s=0; while(x<=b)
{s+=(f[i](x)+f[i](x+h))/2*h;
x+=h;
}
return s;
}
В данном случае в функцию rectangle приходится передавать номер элемента /, соответствующего интегрируемой функции, од нако все указатели можно задать сразу.
Указатель на функцию можно использовать в качестве пара метра другой функции.
#include<stdio.h>
#include<conio.h>
#include<math.h>
double rectangle(double (*f)(double), double,double,double=0.01);
double fl(double x) {return x/pow(x*x+l,2);
}
double f2(double x) {return 4*cos(x)*cos(x);
}
main() {printf("S_fl=%f\n",rectangle(fl,-1,2) ); printf("S_f2=%f", rectangle(f2,0,0.5));
getch(); return 0;
}
double rectangle(double (*f) (double x) , double a,double b,double h)
{double x=a,s=0; while(x<=b) {s+=(f(x)+f(x+h))/2*h;
x+=h;
}
return s;
}
Теперь при вызове функции, выполняющей интегрирование, можно указывать и имя подынтегральной функции rectcmgle(f[, -1,2). Очевидно, что из всех рассмотренных вариантов данный способ наиболее удобен.
10.5. Ссылки
Ссылки - это специальный тип указателя, введенный в Си++, который позволяет работать с указателем как с переменной. Объ явление ссылки делается с помощью операции ссылки, обозначае мой амперсандом (&) - тем же символом, который используется для адресации. Если в программе имеется указатель на перемен ную какого-то типа:
float *р;
то можно создать ссылку на переменную оператором:
float &а=*р;
Ссылка является альтернативным именем переменной. При объявлении она должна быть инициализирована, и затем ее значе ние уже нельзя изменить.
Пример. Операции с ссылкой.
#include<stdio.h>
#include<conio.h> main()
{int a=6,b=2;
int &c = а; //с является ссылкой на a
c=b; //приводит к a=b c+=2; //приводит к a+=2
printf(Mc=%d\n",с); //напечатает c=4 printf("a=%d\n",a); //напечатает a=4 getch();
return 0;
}
В данном примере с всегда ссылается на а и все действия вы полненные над с отражаются на а.
10.6. Динамическое выделение памяти
Динамическое распределение памяти широко используется для экономии вычислительных ресурсов. Например, если неизвест но, сколько в массиве будет элементов, то можно заранее с запасом отвести место под множество элементов:
float а [100000];
Однако этот вариант плохой, поскольку связан с излишшщи затратами памяти. Например, при выполнении программы мо^кег понадобиться всего два элемента. Таким образом, в подобных ситуа циях лучше использовать динамическое распределение пам ^и, создавая массив нужного размера по ходу выполнения программы,
Работа с динамической памятью осуществляется посредством библиотечных функций malloc, calloc, realloc, free и операторов new, delete.
10.6.1. Библиотечные функции распределения памяти
Для использования библиотечных функций распределения динамической памяти нужно подключить файл stdlib.h (табл. 10.1).
Т а б л и ц а 10.1
Функции распределения динамической памяти
№ |
Функция |
Прототип функции, назначение |
|
n/n |
|||
|
void *mal!oc(unsigned s) выделяет динамическую |
||
|
|
||
1 |
malloc |
память длиной в s байт. При неудачной попытке |
|
|
|
выделения памяти возвращает NULL |
|
|
|
void ^calloc(unsigned n, unsigned m) выделяет дина |
|
|
calloc |
мическую память под п элементов по т байт каж |
|
2 |
дый, при этом автоматически заполняет нулями |
||
|
|
выделенную память. При неудачной попытке выде |
|
|
|
ления памяти возвращает NULL |
|
|
|
void *realloc(void *р, unsigned т) сжимает или уве |
|
|
|
личивает размер динамической памяти, ранее вы |
|
3 |
realloc |
деленной под переменную р, до т байт. Если ука |
|
|
|
затель */? равен NULL, т.е. память ранее не выделя |
|
|
|
лась, то функция выполняется как malloc |
|
4 |
free |
void free(void *р) освобождает память, ранее вы |
|
деленную под переменнуюр |
|||
|
|
Пример. Выделение памяти под одномерный массив.
#in c lu d e < std io . h >
#in c lu d e < c o n io . h>
#in c lu d e < s t d lib . h >
main ()
{in t i , k , n ;
in t *a;
p u t s ("Введите число элементов"); s c a n t ("%d", &n);
к = s i z e o f ( i n t ) ; |
//операция |
s iz e o f определяет, |
|
|
//ско лько |
байтов |
выделяется |
|
/ /под указанный |
тип данных |
|
//вы деление динамической памяти |
|
||
//п о д одномерный массив |
|
|
|
а = ( i n t * ) m a l l o c (п*к); |
|
|
|
//в в о д элементов |
массива с клавиатуры |
||
f o r ( i= 0 ;i< n ;i+ + ) |
|
|
|
{printf("a[%d]=",i) ; scanf("%d",&a[i]);
//печать массива
for(i=0;i<n;i++)
printf("%3d",a[i]);
/ / освобождение динамической памяти
free(a);
getch();
return 0;
}
Пример. Печать неинициализированного динамического мас
сива.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main()
{int i,k,n,*a;
puts("Введите число элементов"); scanf("%d",&n);
к = sizeof(int);
a = (int*)malloc(n*k) ; for(i=0;i<n;i++) printf ("%3d",a[i] ); printf("\nn); free(a);
puts("Введите число элементов"); scanf("%d",&n);
a = (int*)calloc(n,k); for(i=0;i<n;i++) printf("%3d",a[i]); free(a);
getch(); return 0;
}
Результат на экране:
Введите число элементов
3
-842150451-842150451-842150451
Введите число элементов
3
0 0 0
Первый раз мы выделили память под массив с помощью функции malloc, а затем распечатали массив. Поскольку мы не за полнили массив значениями, там оказались большие случайные числа (в вашем случае они могут быть другими). Второй раз мы выделили память под массив с помощью функции calloc, и она сама заполнила массив нулями.
Пример. Изменение размера массива по ходу выполнения про граммы.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main ()
{int i,k,n,*a;
//выделяем память под массив puts("Введите число элементов"); scant("%d",&n);
к = sizeof(int);
a = (int*)calloc(n,k);
//вводим элементы массива с клавиатуры for(i=0;i<n;i++)
{printf("a[%d]=",i);
scanf("%d",&a[i]);
}
//печатаем массив for(i=0;i<n;i++) printf("%3d",a[i]); print f (1\n" );
//задаем новый размер массива puts("Введите число элементов "); scanf("%d",&n);
а = (int*)realloc(a,n);
//заполняем массив значениями for(i=0;i<n;i++) {printf("a[%d]="/i);
scanf("%d" , &a[i]);
}
//печатаем массив for(i=0;i<n;i++) printf("%3d",a[i] );
free(а); //освобождаем память
getch() ; return 0;
}