Масиви і функції як параметри

Покажчики на функції

double sin (double x); double cos (double x); double tan (double x);

Можна описати і покажчик на функцію. Наприклад, для функції з аргументом типу double, що повертає значення типу double, опис такого покажчика буде виглядати наступним чином:

double (* fn) (double x);

Тут, як і в разі покажчика на масив, круглі дужки збільшують пріоритет операції *. Якби вони були відсутні, то була б описаний не покажчик на функцію, а функція, що повертає значення покажчика на double.

Після того, як описаний покажчик на функцію, стають можливими такі операції:

fn = sin; / * Налаштування покажчика на функцію sin * / a = fn (x); / * Виклик функції sin через покажчик * / fn = cos; / * Налаштування покажчика на функцію cos * / b = fn (x); / * Виклик функції cos через покажчик * /

Можна описати масив покажчиків на функцію і проинициализировать

Тепер стає можливим наступний цикл:

printf ( "F (x) =% lf \ n", fnArray [i] (x));

Можна описати функцію повертає значення покажчика на функцію:

double (* fnFunc (int i)) (double x)

case 0. return sin; case 1. return cos; case 2. return tan;

Описана функція має параметр типу int і повертає значення покажчика на функцію з аргументом типу double, що повертає значення типу double.

Після опису функції fnFunc стає можливим наступний цикл:

printf ( "F (x) =% lf \ n", fnFunc (i) (x));

Масиви та вказівники

і здійснено присвоювання:

pa [0] або * pa буде позначати a [0]; pa [1] або * (pa + 1) буде позначати a [1];

pa [2] або * (pa + 2) буде позначати a [2] і т. д. І взагалі позначення виду * (pa + n) і pa [n] є повністю еквівалентними. Точно також еквівалентні вирази * (a + i) і a [i].

На перший погляд, здається, що масив і покажчик повністю еквівалентні. Однак є дві істотні відмінності масиву від покажчика:

int A [20], * pA = A; double B [20], * pB = B;

Для покажчиків визначені операції збільшення та зменшення на целочисленную величину, як альтернативна форма запису виразів

pA = pA + i; еквівалентно pA + = i; pA = pA - i; еквівалентно pA - = i;

pA = pA + 1; еквівалентно pA ++; або ++ pA;

pA = pA - 1; еквівалентно pA--; або --pA; При цьому, робота префіксних і Постфіксний операцій ++ і - збігається з їх роботою для арифметичних даних.

Покажчики допускається використовувати в операціях порівняння. При цьому завжди можливо порівняння покажчика з нулем і порівняння двох однотипних покажчиків. Однак правильність результату останнього порівняння для 16-ти розрядного режиму роботи IBM PC гарантується тільки в тому випадку, якщо

порівнювані покажчики є покажчиками на елементи одного і того ж масиву даних або якщо вони попередньо піддаються нормалізації (див. нижче).

У наступному фрагменті програми ілюструється використання вищеописаних операцій

double A [100], * pA, * pA100; int i;

/ * Заповнюємо масив A. Працюємо з масивом * / for (i = 0; i<100; i++) A[i]=0;

/ * Заповнюємо масив A. Працюємо з покажчиками * / for (pA = A, pA100 = pA + 100; pA

Останній варіант заповнення масиву може виявитися більш ефективним.

Покажчики і двовимірні масиви

Нехай є такі визначення масивів і покажчиків:

int * p, (* pA) [4] [2], (* pAstr) [2];

Тут A являє собою двовимірний масив з чотирьох рядків і двох стовпців, B - одновимірний масив з двох елементів. Для кожного з цих масивів буде виділено відповідну кількість пам'яті, достатню для зберігання всіх їх елементів.

елементів даних з опису масивів буде використано лише для коректного зміни значення покажчика при виконанні над ним допустимих арифметичних операцій.

Сенс трактування цих покажчиків визначається напрямом слеванаправо для поспіль наступних операцій [], а також зміною пріоритету операції * за допомогою круглих дужок. Якщо не поставити круглих дужок, то таке визначення

розглядається як визначення двовимірного масиву з покажчиків на тип int.

Для вищеописаних покажчиків припустимі наступні операції привласнення, оскільки зліва і праворуч від операції присвоювання знаходяться покажчики на один і той же тип даних:

p = A [0] [0]; p = A [2];

є невірним, так як зліва від операції присвоювання знаходиться покажчик на тип int, а праворуч - покажчик на перший елемент масиву A, який (елемент) являє собою масив з двох елементів типу int. У таких випадках компілятори видають попередження про підозрілий перетворенні покажчика.

Якщо програміст впевнений в своїх дії, то він може використовувати операцію явного приведення типу для усунення цього повідомлення, але при цьому компілятор знімає з себе будь-яку відповідальність за коректність використання такого покажчика. Так, після присвоювання

елементи, на які посилається покажчик, і елементи масиву A знаходяться в наступному відповідно:

p [0] еквівалентно A [0] [0] p [1] еквівалентно A [0] [1]

p [2] еквівалентно A [1] [0] p [3] еквівалентно A [1] [1] p [4] еквівалентно A [2] [0] p [5] еквівалентно A [2] [1] p [ 6] еквівалентно A [3] [0] p [7] еквівалентно A [3] [1]

Абсолютно коректними є такі присвоювання

після якого використання масиву A і покажчика pAstr абсолютно еквівалентні:

pAstr [i] [j] еквівалентно A [i] [j]

встановлює наступне відповідність між елементами, на які посилається покажчик pAstr і елементами масиву A:

pAstr [0] [0] еквівалентно A [2] [0] pAstr [0] [1] еквівалентно A [2] [1] pAstr [1] [0] еквівалентно A [3] [0] pAstr [1] [ 1] еквівалентно A [3] [1]

Наступні присвоювання коректні

pA = A; / * Покажчик на двовимірний масив * / pAstr = B; / * Покажчик на одновимірний масив * /

і встановлюють наступне відповідність елементів:

(* PA) [i] [j] еквівалентно A [i] [j] (* pAstr) [i] еквівалентно B [i]

Масиви покажчиків зручні для зберігання символьних рядків:

Схожі статті