Передача массивов в качестве параметров

ВВЕДЕНИЕ

С увеличением объема программы становится все более сложным удерживать в памяти все детали. Естественным способом борьбы со сложностью любой задачи является ее разбиение на части. В С+ + задача может быть разделена на более простые подзадачи с помощью функций, после чего программу можно рассматривать на уровне взаимодействия функций.

Использование функций является первым шагом к повышению степени абстракции программы и ведет к упрощению структуры.

Следующим шагом в повышении уровня абстракции программы является группировка функций и связанных с ними данных в отдельные файлы (модули), компилируемые раздельно. Получившиеся в результате компиляции объектные модули объединяются в исполняемую программу с помощью компоновщика.

Функции

Объявление и определение функций

Функция − это именованная последовательность описаний и операторов, выполняющая какое-либо законченное действие. Функция может принимать параметры и возвращать значение. Любая программа на С++ состоит из функций, одна из которых должна иметь имя main − с нее начинается выполнение программы. Функция начинает выполняться в момент вызова. Любая функция должна быть объявлена и определена. Объявление функциизадает ее имя, тип возвращаемого результата и список передаваемых параметров. Определение функции содержит кроме объявления тело функции, представляющее собой последовательность операторов и описаний в фигурных скобках:

[класс ] тип имя_функции ([список параметров ])

[throw (исключения)]

{тело функции}

С помощью необязательного модификатора класс можно явно задать область видимости функции, используя ключевые слова extern и static:

- extern − глобальная видимость во всех модулях программы (по умолчанию);

- static − видимость только в пределах модуля, в котором определена функция.

Тип возвращаемого функцией значения может быть любым, кроме массива и функции, но может быть указателем на массив или функцию. Если функция не должна возвращать значение, указывается тип void.

Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра, передаваемого в функцию, указывается его тип и имя (в объявлении имена параметров можно опускать).

Для вызова функции в простейшем случае нужно указать ее имя, за которым в круглых скобках через запятую перечисляются имена передаваемых аргументов. Если тип возвращаемого функцией значения не void, она может входить в состав выражений или, в частном случае, располагаться в правой части оператора присваивания.

Пример. Функция, возвращающая сумму двух целых величин:

# include <iostream.h>

int sum (int a, int b); // объявление функции

int main ( ) {

int a = 2, b = 3, c,d;

c = sum(a, b); // вызов функции

cin >> d;

cout << sum(c,d);

return 0;

}

int sum (int a, int b) { // определение функции

return a+b;

}

Все величины, описанные внутри функции, а также ее параметры являются локальными. Областью их действия является функция. Для того чтобы сохранить значение локальной переменной между вызовами функции, такую переменную нужно объявить с помощью модификатора static.

!!! При совместной работе функции должны обмениваться информацией. Это можно осуществить с помощью глобальных переменных, через параметры и возвращаемое функцией значение.

Глобальные переменные

Глобальные переменные видны во всех функциях, где не описаны локальные переменные с теми же именами, поэтому использовать их для передачи данных между функциями легко. Однако делать это не рекомендуется. поскольку затрудняет отладку программы и препятствует помещению функций в библиотеки общего пользования.

Возвращаемое значение

Механизм возврата из функции в вызывающую ее функцию реализуется оператором

return [выражение];

Функция может содержать несколько операторов return. Если функция описана как void, выражение не указывается. Оператор return можно опускать для функции типа void, если возврат из нее происходит перед закрывающей скобкой, и для функции main.

Примеры

int f1 ( ) {return 1;} // Правильно

void f2 ( ) {return 1;} // Неправильно

Параметры функции

Механизм параметров является основным способом обмена информацией между функциями. Параметры, перечисленные в заголовке описания функции, называются формальными, а записанные в операторе вызова функции − фактическими.

Существует два способа передачи параметров в функцию − по значению и по адресу.

При передаче по значению операторы функции работают с копиями значений фактических параметров. Доступа к исходным значениям параметров у функции нет, а следовательно, нет возможности их изменить.

При передаче по адресу функция осуществляет доступ к ячейкам памяти по соответствующим адресам и может изменить исходные значения параметров.

Пример

# include <iostream.h>

void f (int i, int *j, int & k);

int main ( ) {

int i = 1, j = 2, k= 3;

cout << "i j k \n";

cout << i << ' '<< j << ' ' << k << '\n';

f(i, &j, k);

cout << i << ' '<< j << ' ' << k << '\n';

return 0;

}

void f(int i, int *j, int &k) {

i ++; (*j)++; k++;

}

На экране будет напечатано:

i j k

1 2 3

1 3 4

Первый параметр функции f (i) передается по значению. Его изменение в функции не влияет на исходное значение. Второй параметр (j) передается по адресу с помощью указателя. Третий параметр (k) передается по адресу с помощью ссылки.

Если требуется запретить изменение параметра внутри функции, используется модификатор const:

int f(const char *a);

Передача массивов в качестве параметров

При использовании в качестве параметра массива в функцию передается указатель на его первый элемент, иначе говоря, массив всегда передается по адресу. При этом информация о количестве элементов теряется, и следует передавать его размерность через отдельный параметр (в случае массива символов, т.е. строки, ее фактическую длину можно определить по положению нуль-символа).

Пример

# include <iostream.h>

int sum (const int *mas, const int n);

int const n = 10;

int main ( ) {

int marks [n] = {3,4,5,4,4};

cout << "Сумма элементов массива" << sum (marks,n);

return 0;

}

int sum (const int *mas, const int n);

// Варианты заголовка: int sum (int mas [ ], int n);

// или int sum (int mas[n], int n);

int s = 0;

for (int i = 0; i<n; i + +;) s +=mas[ i ];

return s;

}

При передаче двумерных массивов все размерности, если они не известны на этапе компиляции, должны передаваться в качестве параметров. В приведенном ниже примере с помощью функции подсчитывается сумма элементов двумерных массивов. Размерность массива b известна на этапе компиляции, под массив с именем a память выделяется динамически.

Пример

include <stdio.h>

include <stdlib.h>

int sum (const int *a, const int nstr, const int nstb);

int main ( ) {

int b[2] [2] = {{2,2},{4,3}};

printf ("Сумма элементов b: %d \ n",sum (&b[0][0],2,2));

int i, j, nstr, nstb, *a;

printf( "Введите количество строк и столбцов а: \n");

scanf("%d%d", &nstr, &nstb);

a=(int *) malloc(nstr*nstb*sizeof(int));

for (i = 0; i<nstr; i++)

for (j = 0; j<nstb; j++) scanf ("%d", &a[i * nstb + j]);

printf("Сумма элементов a: %d \n", sum(a, nstr, nstb));

return 0;

}

int sum (const int *a, const int nstr, const int nstb) {

int i, j, s =0;

for (i = 0; i < nstr; i++)

for (j = 0; j<nstb; j++) s +=a[i*nstb+j];

return s;

}

!!! Двумерный массив внутри функции интерпретируется как одномерный, а его индекс пересчитывается в программе, поэтому возможно такое обращение к элементу с номерами i и j: a[i*nstb + j].

Альтернативный способ работы с двумерным массивом − использование операций new и delete.

Пример

# include <iostream.h>

int sum (int **a, const int nstr, const int nstb);

int main( ) {

int nstr, nstb;

cin >> nstr >> nstb;

int **a, i, j;

a = new int* [nstr];

for (i =0; i<nstr; i++) a[ i ]=new int [nstb];

for (i =0; i<nstr; i++)

for (j =0; j<nstb; j++) cin >> a[ i ][ j ];

cout << sum (a, nstr,nstb);

return 0;

}

int sum (int **a, const int nstr, const int nstb) {

int i, j, s =0;

for (i =0; i<nstr; i++);

for (j =0; j<nstb; j++) s += a[ i ][ j ];

return s;

}

Задания

1. Разработать функцию, возвращающую минимальный элемент одномерного числового массива, и написать с ней программу обработки массива.

2. Разработать функцию, вычисляющую количество неотрицательных элементов в двумерном числовом массиве. Размерность массива не известна на этапе компиляции.

Наши рекомендации