Функції. Частина 2. Функції і масиви. Передача одновимірного та багатовимірного масиву в функцію. Передача структури і класу в функцію

Функції. Частина 2. Функції і масиви. Передача одновимірного та багатовимірного масиву в функцію. Передача структури і класу в функцію

Дана тема базується на темі: Функції. Частина 1. Опис функції. Фактичні та формальні параметри. Передача параметрів у функцію за значенням та за адресою.


Зміст



1. Приклад опису функції, що отримує масив цілих чисел

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

Покажчиком на масив чисел є:

  • ім’я масиву;
  • адреса першого елементу масиву.

Приклад. Нехай потрібно описати функцію SumArrayInts(), що отримує масив з цілих чисел і знаходить суму елементів цього масиву. Функція отримує 2 параметри:

  • масив цілих чисел;
  • кількість елементів у масиві.

Спосіб 1. Передача масиву як int A[].

// Функція, що підраховує суму елементів масиву цілих чисел
// Функція отримує 2 параметри:
//    n - кількість елементів масиву,
//    A - масив цілих чисел
int SumArrayInts(int n, int A[])
{
    int i;
    int sum = 0; // сума
    for (i=0; i<n; i++)
        sum = sum + A[i];
    return sum;
}

Спосіб 2. Передача масиву як int *A.

int SumArrayInts(int n, int *A) // масив передаєтсья як *A
{
    int i;
    int sum = 0; // сума
    for (i=0; i<n; i++)
        sum = sum + A[i];
    return sum;
}

Виклик функції SumArrayInts() з іншого програмного коду.

// передача масиву у функцію
int M[5] = { 23, -2, -1, -8, 4 };
int n = 5;
int summa;

summa = SumArrayInts(n, M);     // summa = 16
summa = SumArrayInts(n, &M[0]); // теж добре, summa = 16

Слід зауважити, що при такій передачі масиву у функцію, елементи масиву можна змінювати в тілі функції.

2. Приклад передачі рядка символів у функцію

Рядок символів є масивом елементів типу char. Тому, передача рядка символів у функцію в якості параметру виконується так само як і у випадку з числами (п. 1).

Рядок символів можна передавати у функцію двома способами:

  • як char*;
  • як char[].

Приклад. Функція, що повертає кількість символів ‘+’ (плюс) в рядку. Ознакою кінця рядка є символ ‘\0’. Тому не потрібно передавати у функцію довжину рядка.

Спосіб 1. Визначення функції GetNPlus(). Передача рядка як char *.

// Функція, що повертає кількість символів '+' в рядку
int GetNPlus(char *s)
{
    char *s2;
    int n = 0; // кількість символів - результат
    s2 = s;

    while (*s2!='\0')
    {
        if (*s2=='+') n++;
        s2++;
    }
   return n;
}

Заголовок вищенаведеної функції можна було визначити як

int GetNPlus(char s[])
{
    ...
}

Спосіб 2. Визначення функції GetNPlus2(). Використання індексів для доступу до символів рядка.

// доступ до символів рядка за індексом
int GetNPlus2(char *s)
{
    int i=0;
    int n=0;

    while (s[i]!='\0')
    {
        if (s[i]=='+') n++;
        i++;
    }
    return n;
}

Виклик функції GetNPlus2() з іншого програмного коду.

// передача масиву у функцію
char * str = "+Test + + +++ string .";
int n;
n = GetNPlus2(str); // n = 6

3. Як передати масив рядків у функцію

Приклад. Функція, що отримує масив рядків та сортує його методом вставки. Масив рядків отримується першим параметром. Другим рядком отримується кількість рядків.

// функція, що отримує масив рядків і сортує його методом вставки
void SortStrings(char * s[], int n)
{
    int i, j, k;
    char * ts; // допоміжна змінна

    for (i=0; i<n-1; i++)
        for (j=i; j>=0; j--)
        {
            if (strcmp(s[j],s[j+1])>0)
            {
                // обмін покажчиків на рядки місцями
                ts = s[j];
                s[j] = s[j+1];
                s[j+1] = ts;
            }
       }

    // на виході - посортований масив покажчиків s
    return;
}

У вищенаведеній функції використано функцію strcmp(). Ця функція порівнює 2 рядки s1 та s2 в лексикографічному порядку:

n = strcmp(s1, s2);

і повертає значення

  • >0, якщо рядок s1 слідує після рядка s2 в лексикографічному порядку;
  • =0, якщо рядки рівні;
  • <0, якщо рядок s1 слідує перед рядком s2 в лексикографічному порядку.

Виклик функції з іншого програмного коду:

// передача масиву покажчиків у функцію
char * str[] = { "DEF",
                 "FEC",
                 "CSE",
                 "AFE",
                 "QER" };
int n = 5;
int i;

// виклик функції
SortStrings(str, n);

4. Приклад передачі двовимірного масиву як параметру функції

У даному прикладі описана функція, що знаходить суму елементів двовимірного масиву. Функція, яка отримує двовимірний масив дійсних чисел в якості параметру.

// функція обчислення суми двовимірного масиву
double Sum2(double A[][3])
{
    double s = 0;
    int i,j;
    for (i=0; i<2; i++)
        for (j=0; j<3; j++)
            s = s + A[i][j];
    return s;
}

Виклик функції з програмного коду. У функцію передається двовимірний масив з іменем M розміром 2*3.

// Передача двовимірного масиву як параметру функції
// двовимірний масив чисел
double M[][3] = { { 2.78, -3.18, 9.4 },
                  { -3.4,   8.8, 0.5 } };

double summa;
summa = Sum2(M);

5. Приклад передачі у функцію тривимірного масиву чисел

У даному прикладі описується функція Sum3(), яка отримує вхідним параметром тривимірний масив цілих чисел. Розмір масиву 2*3*4. Функція повертає суму елементів масиву.

// передача тривимірного масиву D як параметру функції
// функція обчислює суму елементів тривимірного масиву
int Sum3(int D[][3][4])
{
    int summa = 0; // змінна - результат
    int i, j, k;

    // обчислення суми
    for (i=0; i<2; i++)
        for (j=0; j<3; j++)
            for (k=0; k<4; k++)
                summa = summa + D[i][j][k];

    return summa;
}

Виклик функції з іншого програмного коду

// тривимірний масив чисел
int A[2][3][4];
int i, j, k;
int sum;

// заповнення масиву A довільними значеннями
for (i=0; i<2; i++)
    for (j=0; j<3; j++)
        for (k=0; k<4; k++)
            A[i][j][k] = i+j+k;

// виклик функції, що знаходить суму елементів масиву
sum = Sum3(A);

6. Як передати структуру у функцію? Приклад

В якості параметру структуру можна передавати у функцію трьома способами:

  • за значенням;
  • за адресою;
  • за посиланням (не підходить для середовища CLR).

Більш детально про способи передавання параметрів у функцію описується тут.

При передаванні структури за значенням робиться копія в стеку усіх полів структурної змінної.

При передаванні структури за адресою передається тільки адреса структури в пам’яті (покажчик на структуру). Цей посіб є більш ефективним коли для полів структури потрібно виділяти багато пам’яті (розмір покажчика може бути набагато менше розміру структурної змінної).

Покажчик на структуру, який передається у функцію може бути двох типів:

  • некерований покажчик (*);
  • керований покажчик (^). У цьому випадку структура повинна оголошуватись з ключовим словом ref (див. п. 7).

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

Нехай за межами класу (або в іншому модулі) задано структуру, що описує точку на координатній площині:

...

// структура типу struct MyPoint
struct MyPoint
{
    int x;
    int y;
};

...

Нехай задано 2 функції, які визначають чи точки є рівні між собою:

  • функція Equals(), яка в якості параметрів отримує 2 структурні змінні типу MyPoint (передавання за значенням);
  • функція EqualsP(), яка отримує 2 покажчики на структурні змінні типу MyPoint (передавання за адресою).
// функція, що визначає чи точки є рівні між собою
// передавання структурних змінних здійснюється за значенням
bool Equals(MyPoint mp1, MyPoint mp2)
{
    bool f = false;
    if ((mp1.x==mp2.x) && (mp1.y==mp2.y))
        f = true;
    return f;
}

// функція, аналогічна функції Equals, тільки
// передавання структурних змінних виконується за адресою
bool EqualsP(MyPoint *mp1, MyPoint *mp2)
{
    bool f = false;
    if ((mp1->x == mp2->x) && (mp1->y = mp2->y))
        f = true;
    return f;
}

Тоді виклик функцій Equals() та EqualsP() можна здійснити з іншого програмного коду приблизно таким чином:

...

// передавання структури у функцію
MyPoint p1, p2; // структурні змінні
bool res;

// заповнення значення змінної p1
p1.x = 28;
p1.y = -33;

// заповнення значення змінної p2
p2.x = 28;
p2.y = -33;

// передавання структури у функцію Equals за значенням
res = this->Equals(p1, p2); // res = true
res = Equals(p1, p2); // res = true - також добре

// передавання адреси структурної змінної
res = EqualsP(&p1, &p2); // res = true

...

7. Приклад передачі в функцію керованого покажчика на структуру посилального типу (ref)

У даному прикладі продемонстровано передачу у функцію керованого (^) покажчика на структуру. Функція EqualsPRef() отримує два керовані (^) покажчики на структуру типу MyPoint. Функція визначає рівність полів структур, на які вказують покажчики.

Структура MyPoint має наступний опис:

ref struct MyPoint
{
    int x;
    int y;
};

Визначення (реалізація) функції EqualsPRef():

// Функція, що отримує на вході два керовані покажчики (^)
// на структури посилального типу.
// Функція визначає рівність структур, на які вказують покажчики
bool EqualsPRef(MyPoint ^p1, MyPoint ^p2)
{
    bool f = false;
    if ((p1->x == p2->x) && (p1->y == p2->y))
        f = true;
    return f;
}

Виклик функції EqualsPRef() з іншого програмного коду (наприклад, обробника події кліку на кнопці):

// якщо структура оголошена як посилальний тип
// з ключовим словом ref
MyPoint ^mp1; // керований покажчик на структуру
MyPoint ^mp2;

// виділення пам'яті під структурні змінні
mp1 = gcnew MyPoint;
mp2 = gcnew MyPoint;

// заповнення полів структури 1
mp1->x = 30;
mp1->y = -30;

// заповнення полів структури 2
mp2->x = 28;
mp2->y = -30;

// визначення результату, виклик функції
bool res;
res = EqualsPRef(mp1, mp2); // res = false

8. Як в якості параметру функції передати об’єкт класу?

Нехай дано клас MyPointClass, що описує координати точки на площині. Клас описаний у двох модулях:

  • в модулі MyPointClass.h описується опис функцій та полів класу;
  • в модулі MyPointClass.cpp описується реалізація методів та полів класу.

Текст модуля MyPointClass.h:

#pragma once

// клас оголошено як "managed" - керований
ref class MyPointClass
{
    int x;
    int y;

    public:
    MyPointClass(void);
    int GetX(void);
    int GetY(void);
    void SetXY(int nx, int ny);
};

Текст модуля MyPointClass.cpp:

#include "StdAfx.h"
#include "MyPointClass.h"

MyPointClass::MyPointClass(void)
{
    x = 0;
    y = 0;
}

int MyPointClass::GetX(void)
{
    return x;
}

int MyPointClass::GetY(void)
{
    return y;
}

// встановити нове значення x та y
void MyPointClass::SetXY(int nx, int ny)
{
    x = nx;
    y = ny;
}

Нехай в головному модулі програми (наприклад, клас форми) описана функція EqualsClass(), що порівнює поля класу MyPointClass. Функція отримує два параметри – керовані покажчики на клас. Передати клас як параметр-значення не вдасться, оскільки клас належить до посилального типу. З класом потрібно використовувати керовані покажчики (^).

Більш детально про керовані та некеровані покажчики описується тут.

// функція, що отримує змінну-покажчик на клас як параметр
// функція порівнює на рівність поля класу
bool EqualsClass(MyPointClass ^p1, MyPointClass ^p2)
{
    int x1, y1, x2, y2;
    bool res = false;

    x1 = p1->GetX();
    y1 = p1->GetY();

    x2 = p2->GetX();
    y2 = p2->GetY();

    if ((x1==x2) && (y1==y2))
        res = true;
    return res;
}

Виклик функції EqualsClass() з іншого програмного коду (наприклад, з обробника події):

// передача класу у функцію
MyPointClass pc1; // об'єкт змінна типу клас, у функцію як параметр передавати неможна
MyPointClass ^pc2 = gcnew MyPointClass(); // керований покажчик на клас - можна передавати у функцію
MyPointClass ^pc3 = gcnew MyPointClass(); // керований покажчик на клас
bool f;

// встановлення значень змінних
pc1.SetXY(4, 2);    
pc2->SetXY(5, 2);
pc3->SetXY(5, 2);

f = EqualsClass(pc2, pc3); // f = true, працює

Щоб використати методи класу, потрібно попередньо підключити модуль MyPointClass.h:

#include "MyPointClass.h"

9. Приклад передачі структури у функцію за посиланням (не підтримується у середовищі CLR)

Структуру можна передавати у функцію за посиланням. Нижче наведено програмний код оголошення структури MyPoint, що передається у функцію EqualsR() за посиланням для додатку типу Win32. Для додатків, що працюють у середовищі CLR такий спосіб передачі параметру не підтримується.

struct MyPoint
{
    int x;
    int y;
};

// передача за посиланням
bool EqualsR(MyPoint& mp1, MyPoint& mp2)
{
    bool res = false;
    if ((mp1.x == mp2.x) && (mp1.y == mp2.y))
    res = true;
    return res;
};

Використання функції EqualsR() в іншому програмному коді:

bool res;
MyPoint p1, p2;
p1.x = 23; p1.y = 23;
p2.x = 26; p2.y = 23;
res = EqualsR(p1, p2);  // res = false


Зв’язані теми