Как сделать чтобы функция возвращала массив c

Обновлено: 08.07.2024

Массивы, также как остальные переменные, можно передавать в функции в качестве аргументов. Рассмотрим такую программу:

В теле функции main() объявляется массив, состоящий из 10 элементов. Далее вызывается функция arr_make() , которой передаются в качестве аргументов имя массива и два целых числа.

Если посмотреть на функцию arr_make() , то можно заметить, что ее первый параметр выглядит немного странно. Функция принимает массив неизвестно какого размера. Если предположить, что массивы передаются по значению, т.е. передаются их копии, то как при компиляции будет вычислен необходимый объем памяти для функции arr_make() , если неизвестно какого размера будет один из ее параметров?

На прошлом уроке мы выяснили, что имя массива — это константный указатель на первый элемент массива; т.е. имя массива содержит адрес. Выходит, что мы передаем в функцию копию адреса, а не копию значения. Как мы уже знаем, передача адреса приводит к возможности изменения локальных переменных в вызывающей функции из вызываемой. Ведь на одну и ту же ячейку памяти могут ссылаться множество переменных, и изменение значения в этой ячейке с помощью одной переменной неминуемо отражается на значениях других переменных.

Описание вида arr[] в параметрах функций говорит о том, что в качестве значения мы получаем указатель на массив, а не обычную (скалярную) переменную типа int, char, float и т.п.

Продолжим рассуждения. Если в функцию передается только адрес массива, то в теле функции никакого массива не существует, и когда там выполняется выражение типа arr[i] , то на самом деле arr — это не имя массива, а переменная-указатель, к которой прибавляется смещение. Поэтому цикл в функции arr_make() можно переписать на такой:

В теле цикла результат выражения справа от знака присваивания записывается по адресу, на который указывает arr. За это отвечает выражение *arr . Затем указатель arr начинает указывать на следующую ячейку памяти, т.к. к нему прибавляется единица ( arr++ ). Еще раз: сначала выполняется выражение записи значения по адресу, который содержится в arr; после чего изменяется адрес, содержащийся в указателе (сдвигается на одну ячейку памяти определенного размера).

Поскольку мы можем изменять arr, это доказывает, что arr — обычный указатель, а не имя массива. Тогда зачем в заголовке функции такой гламур, как arr[] ? Действительно, чаще используют просто переменную-указатель:

Хотя в таком случае становится не очевидно, что принимает функция - указатель на обычную переменную или все-таки на массив. В любом случае она будет работать.

Часто при передаче в функцию массивов туда же передают и количество его элементов в виде отдельного параметра. В примере выше N является глобальной константой, поэтому ее значение доступно как из функции main() , так и arr_make() . Иначе, более грамотно было бы написать функцию arr_make() так:

В данном случае параметр n — это количество обрабатываемых элементов массива.

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

Но если вы хотите написать более надежную программу, в которой большинство функций не должны менять значения элементов массивов, то лучше в заголовках этих функций объявлять параметр-указатель как константу, например:

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

Усовершенствуем программу, которая была приведена в начале этого урока:

Теперь у пользователя запрашивается минимум и максимум, затем создается массив из элементов, значения которых лежат в указанном диапазоне. Массив выводится на экран с помощью функции arr_print() . Далее у пользователя запрашивается знак + или -. Вызывается функция arr_inc_dec() , которая в зависимости от введенного знака увеличивает или уменьшает на единицу значения элементов массива.

В функциях arr_make() и arr_print() используется нотация указателей. Причем в теле функций значения указателей меняются: они указывают сначала на первый элемент массива, затем на второй и т.д. В функции arr_inc_dec() используется вид обращения к элементам массива. При этом значение указателя не меняется: к arr прибавляется смещение, которое увеличивается на каждой итерации цикла. Ведь на самом деле запись arr[i] означает *(arr+i) .

При использовании нотации обращения к элементам массива программы получаются более ясные, а при использовании записи с помощью указателей они компилируются чуть быстрее. Это связано с тем, что когда компилятор встречает выражение типа arr[i] , то он тратит время на преобразование его к виду *(arr+i) . Однако лучше потратить лишнюю секунду при компиляции, но получить более читаемый код.

Вы можете заказать у нас

VPS (Virtual Private Server, виртуальный выделенный сервер, другое название VDS — Virtual Dedicated Server) — стартовая площадка для крупных проектов, позволяющая более рационально использовать представляемые ресурсы в рамках выбранного тарифа OpenVZ-сервера. OpenVZ — технология виртуализации c общим ядром основной операционной системы без эмуляции отдельного физического сервера. Предлагает меньшую стоимость за счёт низких накладных расходов на виртуализацию. KVM — аппаратная виртуализация, при которой полностью эмулируется физический сервер, что позволяет устанавливать любые операционные системы (Linux, Windows, FreeBSD и другие) и дает гарантированные ресурсы физического сервера. Для всех серверов предоставляется надежная DDOS-защита.

Функция возврата массива Си — это процедура, которая выполняет возврат указателя массива.

Введение

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

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 1. Код. Автор24 — интернет-биржа студенческих работ

Передачу массива возможно осуществить следующим образом:

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 2. Код. Автор24 — интернет-биржа студенческих работ

В качестве аргумента функции возможно использование массива. В функцию необходимо передать наименование массива, а фактически его указатель. Приведём пример:

void fun(double array )

Образец функции, именуемый fun, снабжён указателем того, что аргументом массива является массив вида double (без идентификатора массива). Функция вызывается так:

В теле функции не копируется массив, все операции выполняются с имеющимися компонентами и по окончании работы функции, величины компонентов массива поменяются (естественно, в случае, если это заложено в функциональный алгоритм). Отсылать в функцию объём массива нет необходимости. Следует заметить, что в языке С++ понятия массива и указателя являются практически синонимами. Но так как переадресация массива по значению означает формирование копии целого массива, что считается достаточно сложной процедурой (массив может быть очень большим), то по этой причине передаётся только указатель на первый элемент массива, а не сам массив. Из этого следует, что два вида задания функции:

Готовые работы на аналогичную тему

void f(int A) и void f(int * A)

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

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

Возврат массива из функции

Приведём пример функции, которая может изменять величины передаваемых ей переменных:

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 3. Код. Автор24 — интернет-биржа студенческих работ

Когда вызывается функция swap, формируются новые аргументы, а и b, они получают веса три и пять. Данные переменные не имеют ни каких связей с переменными р и q, и перемена их числовых значений не влияет на величины р и q. Данный метод передачи параметрических данных определяется как передача параметров по значению. Для обеспечения возможности изменения функцией величин переменных, которые были объявлены в других функциях, следует сделать указание, что параметр, который передаётся, есть не постоянная величина, а переменная. Значения таких параметров следует передавать по ссылке. Чтобы это условие работало, функция swap должна быть задана так:

void swap(int & a, int & b)

Знаки перед именами переменных (амперсанды) обозначают, данные переменные не локальные, а являются ссылками на переменные, которые были указаны как параметры при задании функции. Значит, когда вызывается swap(p,q), то переменные а и b считаются синонимами р и q, и если меняются их величины, то изменятся и р и q. Но вызвать функцию в форме swap(3,5) уже не будет возможности, так как три и пять это постоянные числа, которые не могут быть синонимами переменных. Следует также заметить, что в языке С (не С++) не существовало таких понятий, как передать параметры по ссылке. Для реализации функции, подобной swap в примере выше, нужно было сообщать адреса переменных р и q, а собственно функцию следовало объявить следующим образом:

void swap(int a, int b)

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

Возврат массива в Си

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 4. Код. Автор24 — интернет-биржа студенческих работ

Далее рассмотрим возврат двумерного массива вида dоublе из функции согласно этому способу GetDoubleArray().

Имеем в качестве исходных параметров объём массива m*n. Данный метод выполняет возврат массива.

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 5. Код. Автор24 — интернет-биржа студенческих работ

Пример выполнения методики GetArrayChar(), генерирующей, то есть выполняющей возврат двумерного массива объектов типа Char.

Код. Автор24 — интернет-биржа студенческих работ

Рисунок 6. Код. Автор24 — интернет-биржа студенческих работ

Образец применения функции вызова GetArrayChar() из другого программного кода.

Я относительно новичок в C, и мне нужна помощь с методами работы с массивами. Исходя из Java-программирования, я привык говорить int [] method() , чтобы возвращать массив. Тем не менее, я обнаружил, что с C вы должны использовать указатели для массивов, когда вы возвращаете их. Будучи новым программистом, я действительно не понимаю этого вообще, даже с многочисленными форумами, которые я просматривал.

По сути, я пытаюсь написать метод, который возвращает массив символов в C. Я предоставлю метод (давайте назовем его returnArray) с массивом. Он создаст новый массив из предыдущего массива и вернет на него указатель. Мне просто нужна помощь о том, как начать и как прочитать указатель, как только он будет отправлен из массива. Любая помощь, объясняющая это, приветствуется.

Предлагаемый формат кода для функции возврата массива

Абонент функции

Я еще не проверял это, так как мой компилятор C в данный момент не работает, но я хотел бы выяснить это

Является ли возвращаемый массив известным размером, указанным в примере кода? Единственное другое замечание, которое я вижу, кроме проблем со стеком, упомянутых в ответах, состоит в том, что если ваш возвращаемый массив имеет неопределенный размер, учитывая то, как работают указатели / массивы в C, вы не будете знать, насколько он велик.

Вы не можете вернуть массивы из функций в C. Вы также не можете (не должны) делать это:

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

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

Опция 1:

динамически распределять память внутри функции (вызывающая сторона отвечает за освобождение ret )

Назовите это так:

Вариант 2:

заполнить предварительно выделенный буфер, предоставленный вызывающей стороной (вызывающая сторона выделяет buf и передает функции)

И назовите это так:

@moooeeeep: Да, я специально это упустил, чтобы все было просто, но да, вы можете вернуть указатель на статические данные, объявленные внутри функции.

@ user1506919: На самом деле я бы предпочел вариант 2, так как ясно, кто выделяет и освобождает память, но я добавлю для вас пример.

Среди прочего, это означает, что вы не можете передать выражение массива функции и получить его как тип массива ; функция фактически получает тип указателя:

При вызове foo выражение str преобразуется из типа char [6] в char * , поэтому вместо параметра foo объявляется первый параметр . Так как выражение массива является операндом оператора, оно не преобразуется в тип указателя, поэтому вы получаете количество байтов в массиве (6). char *a char a[6] sizeof str sizeof

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

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

Другой метод заключается в том, что функция динамически выделяет массив и возвращает указатель и размер:

В этом случае вызывающая сторона отвечает за освобождение массива с помощью free функции библиотеки.

Обратите внимание, что dst в приведенном выше коде это простой указатель на char , а не указатель на массив char . Указатель C и семантика массива таковы, что вы можете применить оператор индекса [] к выражению типа массива или типа указателя; оба src[i] и dst[i] получат доступ к i '-ому элементу массива (даже если src имеет только тип массива).

Вы можете объявить указатель на массив из N элементов T и сделать нечто подобное:

Несколько недостатков с вышесказанным. Прежде всего, более старые версии C ожидают SOME_SIZE быть константой времени компиляции, то есть функция будет работать только с одним размером массива. Во-вторых, вы должны разыменовать указатель перед применением индекса, который загромождает код. Указатели на массивы работают лучше, когда вы имеете дело с многомерными массивами.

Я относительно знал C, я привык программировать на Java, поэтому я нахожу C немного сложнее в том, что касается массивов. Я все еще сливаюсь с этими делами:

В java я бы сделал что-то вроде этого, чтобы вернуть массив в функцию:

EDITED: У меня есть эта функция:

И я делаю следующее:

И выход только 1 элемент.

EDIT: Чтобы прямо ответить на ваш обновленный вопрос: вы должны передать размер массива. C не имеет механизма для хранения размера массивов, таких как Java. Если компилятор знает о размере массива, потому что массив является глобальной или локальной переменной, а не динамически распределен, то вы можете использовать оператор sizeof(). В противном случае вы должны знать размер отдельно или использовать значения дозорности в вашем массиве (например, 0.0 в конце или NULL).

Что касается массивов, указателей и аргументов в целом, см. Ниже:

Вы будете возвращать указатель на массив, который обозначается синтаксисом '*':

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

Скобки идут после имени переменной, в отличие от Java, где они являются частью типа. Несмотря на то, что синтаксис Java более согласован, он не имеет особого смысла в C, где вы часто указываете размер массива в скобках в объявлении переменной:

Невозможно указать, что функция возвращает массив, а не простой указатель. В C ссылки на массивы распадаются на указатели (хотя указатели и массивы НЕ являются тем же, что и обычно). Это означает, что всякий раз, когда вы передаете массив вокруг, C предоставляет только средство для передачи указателя на массив. Весь массив на самом деле не копируется. Как это бывает, имя массива также является указателем на первый элемент массива.

Также обратите внимание на то, что пользователь268396 говорит в своем ответе. Если вы планируете создавать новый массив и возвращать его, вам нужно либо распределить массив динамически, либо передать указатель на уже выделенный массив (что похоже на то, что вы вроде как все равно),

Надеюсь это поможет

С точки зрения Java, указатели просто напоминают (не точно) ссылки на объекты.

Подобно Object Reference O указывает на некоторый фактический объект типа SomeClassName, так и указатели в C:

Переменная b просто указывает на расположение адреса на a. Глубокое погружение в концепции массива:

Здесь мы просто говорим, что г-н * b указывает на первое местоположение группы a, т.е. a [0].

Теперь указатель мощности в C - это то, что теперь, после:

Это означает, что вы меняете * (b + 4), вы меняете [4].

Вы не можете. Когда функция вернет фрейм стека, будет стерта (как правило), и ваш сгенерированный массив будет скроен этим. Однако вы можете отредактировать прототип функции, чтобы принять указатель на изменяемый массив. Такой аргумент функции известен как "выходной параметр". Пример:

Это напечатает "Результат: foo [0] = 1, foo [1] = 2".

Нужно упомянуть, когда вы используете массив в списке параметров функции, он будет преобразован в указатель. Поэтому в основной (. ) декларации char *argv[] и char **argv на самом деле такие же. В этом случае int a[] и int* a являются одинаковыми. Но массив и указатель - это не одно и то же.

В качестве примера возьмем следующий код:

p является указателем, когда мы обращаемся к p [i], обратите внимание, что адрес p не является адресом a, а содержимое p является адресом a. Тогда код будет:

получить доступ к памяти, чтобы получить содержимое p, то есть адрес a. вычислить смещение на основе я и типа указателя (int). получить доступ к памяти, чтобы получить результат.

a - массив int, если мы обращаемся к [i], адрес a - это просто адрес [0], код будет:

Вычислить смещение на основе я и типа int. Получите доступ к памяти.

Указатель и массив - разные типы. Поэтому, если вы объявляете int * p в одном файле и используете его в этом файле, но определяете p как массив в другом файле, что вызовет проблему.

Вы можете также задаться вопросом о int * p = a, в ANSI, если вы используете массив (его имя) в качестве выражения, компилятор преобразует его в указатель, указывая на самый первый элемент массива.

Обновление, основанное на комментариях Джима Бальтера:

Если вы используете массив (его имя) в качестве выражения, компилятор не всегда будет преобразовывать его в указатель, указывая на самый первый элемент массива. Например, в sizeof (p-> q-> a), p-> q-> a является выражением, но если a является массивом, он не преобразуется в указатель.

"За исключением случаев, когда он является операндом оператора sizeof или унарного оператора или является строковым литералом, используемым для инициализации массива, выражение, которое имеет тип type '' type, преобразуется в выражение с типом '' указателем на тип который указывает на начальный элемент объекта массива.

Читайте также: