Как передать одномерный массив в функцию c
Если функция принимает в качестве параметра массив, то фактически в эту функцию передается указатель на первый элемент массива. То есть как и в случае с указателями нам доступен адрес, по которому мы можем менять значения. Поэтому следующие объявления функции будут по сути равноценны:
Передадим в функцию массив:
В данном случае функция print выводит на консоль первый элемент массива.
Теперь определим параметр как указатель:
Здесь также в функцию передается массив, однако параметр представляет указатель на первый элемент массива.
Ограничения
Поскольку параметр, определенный как массив, рассматривается именно как указатель на первый элемент, то мы не сможем корректно получить длину массива, например, следующим образом:
И также мы не сможем использовать цикл for для перебора этого массива:
Передача маркера конца массива
Чтобы должным образом определять конец массив, перебирать элементы массива, обращаться к этим элементам, необходимо использовать специальный маркер, который бы сигнализировал об окончании массива. Для этого могут использоваться разные подходы.
Первый подход заключается в том, чтобы один из элементов массива сам сигнализировал о его окончании. В частности, массив символов может представлять строку — набор символов, который завершается нулевым символом ‘\0’. Фактически нулевой символ служит признком окончания символьного массива:
Однако при таком подходе мы должны быть уверены, что массив содержит такой подобный признак завершения. И если бы в данном случае нулевого байта не оказалось бы в строке, то это привело бы к неприятным последствиям. Поэтому обычно применяется другой подход, который заключается в передаче в функцию размера массива:
Третий подход заключается в передаче указателя на конец массива. Можно вручную вычислять вычислять указатель на конец массива. А можно использовать встроенные библиотечные функции std::begin() и std::end() :
Причем end возвращает указатель не на последний элемент, а адрес за последним элементом в массиве.
Применим данные функции:
Константные массивы
Поскольку при передаче массива передается фактически указатель на первый элемент, то используя этот указатель, мы можем изменить элемены массива. Если нет необходимости в изменении массива, то лучше параметр-массив определять как константный:
В данном случае функция print просто выводит значения из массива, поэтому параметры этой функции помечаются как константные.
Функция twice изменяет элементы массива — увеличивает их в два раза, поэтому в этой функции параметр-массив является неконстантным. Причем поле выполнения функции twice массив numbers будет изменен.
Консольный вывод программы:
Передача массив по ссылке
Еще один сценарий передачи массива в функцию представляет передача массива по ссылке. Прототип функции, которая принимает массив по ссылке, выглядит следующим образом:
Обратите внимание на скобки в записи (&) . Они указывают именно на то, что массив передается по ссылке. Пример использования:
Подобным образом можпо передавать константные ссылки на массивы.
С одной стороны, может показаться, что в передаче массива по ссылке нет большого смысла, поскольку при передачи массива по значению итак просто передается адрес этого массива. Но с другой стороны, передача массива по ссылке имеет некоторые преимущества. Во-первых, не копируется значение — адрес массива, мы напрямую работаем с оригинальным массивом. Во-вторых, передача массива по ссылке позволяет ограничить размер такого массива, соотвественно при компиляции компилятор уже будет знать, сколько элементов будет иметь массив.
Здесь функция print принимает ссылку строго на массив с 5 элементами. И поскольку мы знаем точный размер массива, то нам нет необходимости передавать в функцию дополнительно размер массива.
Если же мы попробуем передать в функцию массив с другим количеством элементов, то на этапе компиляции мы столкнемся с ошибкой, как, например, в следующем случае:
Передача многомерного массива
Многомерный массив также передается как указатель на его первый элемент. В то же время поскольку элементами многомерного массива являются другие массивы, то указатель на первый элемент многомерного массива фактически будет представлять указатель на массив.
Когда определяется параметр как указатель на массив, размер второй размерности (а также всех последующих размерностей) должен быть определен, так как данный размер является частью типа элемента. Пример объявления:
Здесь предполагается, что передаваемый массив будет двухмерным, и все его подмассивы будут иметь по 3 элемента. Стоит обратить внимание на скобки вокруг имени параметра, которые и позволяют определить параметр как указатель на массив. И от этой ситуации стоит отличать следующую:
В данном случае параметр определен как массив указателей, а не как указатель на массив.
Рассмотрим применение указателя на массив в качестве параметра:
В функции main определяется двухмерный массив — он состоит из трех подмассивов. Каждый подмассив имеет по три элемента.
В функцию print вместе с массивом передается и число строк — по сути число подмассивов. В самой функции print получаем количество элементов в каждом подмассиве и с помощью двух циклов перебираем все элементы. С помощью выражения rows[0] можно обратиться к первому подмассиву в двухмерном массиве, а с помощью выражения rows[0][0] — к первому элементу первого подмассива. И таким образом, манипулируя индексами можно перебрать весь двухмерный массив.
В итоге мы получим следующий консольный вывод:
Также мы могли бы использовать нотацию массивов при объявлении и определении функции print, которая может показаться проще, нежели нотация указателей. Но в этом случае опять же надо было бы указать явным образом вторую размерность:
Как передать массив в функцию?
Если размер массива неизвестен, то можно использовать шаблон:
Если то что передается в функцию — это не массив, а указатель (т.е. не T[N] a T* ), то функция должна принимать указатель, а размер надо передавать дополнительным параметром или как-то еще.
Однако это очень ненадежное решение, нет никакой гарантии что будет передан правильный размер массива, или что ptr не равен nullptr .
По этому правильно — это использовать span<T> из C++ Core Guidelines
C++. Функции. Часть 2. Функции и массивы. Передача одномерного и многомерного массива в функцию. Передача структуры и класса в функцию
Функции. Часть 2. Функции и массивы. Передача одномерного и многомерного массива в функцию. Передача структуры и класса в функцию
Содержание
- 1. Пример определения функции, получающей массив целых чисел
- 2. Пример передачи строки символов в функцию
- 3. Как передать массив строк в функцию? Пример
- 4. Пример передачи двумерного массива как параметра функции
- 5. Пример передачи в функцию трехмерного массива чисел
- 6. Как передать структуру в функцию? Пример
- 7. Пример передачи в функцию управляемого указателя на структуру ссылочного типа ( ref )
- 8. Как в качестве параметра функции передать объект класса?
- Связанные темы
Поиск на других ресурсах:
1. Пример определения функции, получающей массив целых чисел
Для передачи массива чисел в функцию, нужно передать указатель на этот массив чисел.
Указателем на массив чисел есть:
- имя массива;
- адреса первого элемента массива.
Пример. Пусть нужно описать функцию SumArrayInts() , которая получает массив из целых чисел и находит сумму элементов этого массива. Функция получает 2 параметра:
- массив целых чисел;
- число элементов в массиве.
Способ 1. Передача массива как int A[] .
Способ 2. Передача массива как int *A .
Вызов функции SumArrayInts() из другого программного кода.
Следует заметить, что при такой передаче массива в функцию, элементы массива можно изменять в теле функции.
2. Пример передачи строки символов в функцию
Строка символов есть массивом элементов типа char . Поэтому, передача строки символов в функцию в качестве параметра выполняется точно так же, как и в случае с числами (п. 1).
Строку символов можно передавать в функцию двумя способами:
- как char* ;
- как char[] .
Пример. Функция, которая возвращает количество символов ‘+‘ (плюс) в строке. Признаком конца строки есть символ ‘\0’ . Поэтому не нужно передавать в функцию длину строки.
Способ 1. Определение функции GetNPlus() . Передача строки как char * .
Заголовок вышеприведенной функции можно было также определить следующим образом:
Способ 2. Определение функции GetNPlus2() . Использование индексов для доступа к символам строки.
Вызов функции GetNPlus2() из другого программного кода.
3. Как передать массив строк в функцию? Пример
Пример. Функция, которая получает массив строк и сортирует его методом вставки. Массив строк передается первым параметром. Вторым параметром передается количество строк.
В вышеприведенной функции использована функция strcmp() . Эта функция сравнивает 2 строки s1 и s2 в лексикографическом порядке:
и возвращает значение
- >0 , если строка s1 следует после строки s2 в лексикографическом порядке;
- =0 , если строки равны между собой;
- <0 , если строка s1 следует перед строкой s2 в лексикографическом порядке.
Вызов функции из другого программного кода:
4. Пример передачи двумерного массива как параметра функции
В данном примере описана функция, которая находит сумму элементов двумерного массива. Функция получает двумерный массив вещественных чисел в качестве параметра.
Вызов функции из программного кода. В функцию передается двумерный массив с именем M размером 2×3.
5. Пример передачи в функцию трехмерного массива чисел
В данном примере описывается функция Sum3() , которая получает входным параметром трехмерный массив целых чисел. Размер массива 2×3×4. Функция возвращает сумму элементов массива.
Вызов функции из другого программного кода
6. Как передать структуру в функцию? Пример
В качестве параметра структуру можно передавать в функцию двумя способами:
- по значению;
- по адресу;
- по ссылке (не используется в среде CLR ).
Более подробно о способах передачи параметров в функцию описывается здесь .
При передаче структуры по значению делается копия в стеке всех полей структурной переменной.
При передаче структуры по адресу передается только адрес структуры в памяти (указатель на структуру). Этот способ есть более эффективным, если для полей структуры нужно выделять много памяти (размер указателя может быть намного меньше размера структурной переменной).
Указатель на структуру, которая передается в функцию может быть двух типов:
- неуправляемый указатель ( * );
- управляемый указатель ( ^ ). В этом случае структура должна объявляться с ключевым словом ref ( см. п. 7 ).
Пример. Передача структурной переменной (объекта) по значению и по адресу (случай неуправляемого указателя * ).
Пусть за пределами класса (или в другом модуле) задана структура, которая описывает точку на координатной плоскости:
Пусть заданы 2 функции, которые определяют, равны ли точки между собой:
- функция Equals() , которая в качестве параметров получает 2 структурные переменные типа MyPoint (передача по значению);
- функция EqualsP() , которая получает 2 указателя на структурные переменные типа MyPoint (передача по адресу).
Тогда вызов функций Equals() и EqualsP() можно осуществить из другого программного кода приблизительно следующим образом:
7. Пример передачи в функцию управляемого указателя на структуру ссылочного типа ( ref )
В данном примере продемонстрирована передача в функцию управляемого ( ^ ) указателя на структуру. Функция EqualsPRef() получает два управляемых ( ^ ) указателя на структуру типа MyPoint . Функция определяет равенство полей структур, на которые указывают указатели.
Структура MyPoint имеет следующее описание:
Определение (реализация) функции EqualsPRef() :
Вызов функции EqualsPRef() из другого программного кода (например, обработчика события клика на кнопке):
8. Как в качестве параметра функции передать объект класса?
Пусть дан класс MyPointClass , описывающий координаты точки на плоскости. Класс определен в двух модулях:
- в модуле MyPointClass.h описывается описание функций и полей класса;
- в модуле MyPointClass.cpp описывается реализация методов и полей класса.
Текст модуля MyPointClass.h :
Текст модуля MyPointClass.cpp :
Пусть в главном модуле программы (например, класс формы) описана функция EqualsClass() , которая сравнивает поля класса MyPointClass . Функция получает два параметра – управляемые указатели на класс ( ^ ). Передать класс как параметр-значения не удастся, поскольку класс принадлежит к ссылочному типу. С классом нужно использовать управляемые указатели ( ^ ).
Более подробно об управляемых и неуправляемых указатели описывается здесь .
Вызов функции EqualsClass() из другого программного кода (например, из обработчика события):
Чтобы использовать методы класса, нужно предварительно подключить модуль MyPointClass.h :
9. Пример передачи структуры в функцию по ссылке (не поддерживается в среде CLR )
Структуру можно передавать в функцию по ссылке. Ниже дается программный код объявления структуры MyPoint , которая передается в функцию EqualsR() по ссылке для приложений типа Win32 . Для приложений, работающих в среде CLR такой способ передачи параметра не поддерживается.
Как стать программистом
Это моя личная ссылка-приглашение на Stepik для вас. Регистрируясь по этой ссылке, записываясь на курсы и решая задачи, Вы помогаете автору данного сайта принять участие в конкурсе платформы Stepik! Подробности конкурса здесь: https://vk.cc/75rKuS
воскресенье, 6 октября 2013 г.
Занятие 18. Передача одномерных массивов в функцию. Возвращение массива из функции.
Добрый вечер друзья. Продолжаем изучать работу с массивами и указателями.
Сегодня научимся передавать массив в функцию и возвращать массив из функции.
Прочитайте улучшенную версию этого урока «Передача аргументов в функцию».
- Ещё более доступное объяснение
- Дополнительные материалы
- 12 задач на программирование с автоматической проверкой решения
Итак, начнем с первого пункта. Пусть нам необходимо передать массив в функцию и там его обработать. Ну допустим вывести его элементы на экран. Тут возможны два варианта.
1. У нас статический массив.
2. У нас динамический массив.
В зависимости от этого и нужно плясать.
Первый случай. Передача в функцию статического массива.
Для определенности будем передавать массив символов. Напишем функцию, которая принимает строку и выводит её на экран.
Давайте внимательно рассмотрим аргументы, которая эта функция принимает. Первый из них как раз и есть массив, который мы хотим передать. Как видите отличие от передачи обычной переменной лишь в том, что мы после имени пишем квадратные скобки. Именно они и указывают на то, что это не просто некая переменная а целый массив переменных данного типа.
В скобках, не нужно указывать размерность массива. С размерностью массива вообще все не так просто. Функции в Си не умеют самостоятельно определять размерность переданного им массива. Поэтому отдельным параметром нам необходимо передавать его размер. В нашей функции мы передаем размер массива с помощью переменной n.
Напишем самую простую программу, которая будет использовать эту функцию.
Обратите внимание, что передача массива в функцию в этом случае, по виду, ничем не отличается от передачи обычной переменной. Мы лишь указываем его имя и все. Это только на первый взгляд так кажется. Но об этом чуть позже.
Второй случай. Передача в функцию динамического массива.
Давайте решим такую задачу. имеется текстовый файл input.txt. Пусть в нем в первой строчке записано натуральное число N не превосходящее 100. А в следующих N строках записаны некоторые вещественные числа. Пусть мы хотим посчитать среднее арифметическое всех этих чисел и вывести.
Удобно для хранения чисел завести динамический массив. Хотя, на самом деле, в этой задаче мы могли бы просто читать числа из файла и сразу вычислять их среднее значение. Но как-то я не могу придумать пока более подходящего примера.
И так напишем требуемую программу.
Обратите внимание на аргументы функции. Как видите, если мы передаем динамический массив, то нам нужно явно указывать на то, что функция принимает указатель на первый элемент массива. В случае одномерного массива это не критично, и вы можете объявить аргументы как и в прошлый раз, т.е.
void sa_arr(float a[], int n)
но так делать не стоит. Приучайтесь сразу передавать динамические массивы таким образом.
Теперь вернемся к нашим отличиям а так же второму вопросу.
Если вы помните, то переменные в языке Си, при передаче их в функцию передаются по значению. То есть мы передаем не сами переменные, а только их значения. И если мы в функции будем их изменять, то настоящих переменных это никак не коснется. В нашей группе в вк, даже было небольшое задание на эту тему. Да и в уроке с указателями мы разбирали, как обойти это ограничение.
Основное отличие передачи массива в функцию в том, что массивы, в отличие от переменных всегда передаются по ссылке. Т.е. в функцию передается не копия массива, а сам массив. И если внутри функции мы будем как-то изменять массив, то эти изменения останутся и после того, как функция закончит свою работу.
Несколько изменим наше предыдущую программу. Изменим один из элементов внутри функции. И посмотрим, что будет с исходным массивом.