Функции. Часть 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


Связанные темы