Ответ 1
Функции не могут возвращать массивы в C.
Однако они могут возвращать структуры. А структуры могут содержать массивы...
Я попытался вернуть имя массива, как показано ниже. В основном я пытаюсь вернуть функцию test массиву, который можно использовать в основном. Не могли бы вы посоветовать мне, что мне нужно прочитать, чтобы узнать, как выполнить такую функцию?
#include <stdio.h>
int test(int size, int x){
int factorFunction[size];
factorFunction[0] = 5 + x;
factorFunction[1] = 7 + x;
factorFunction[2] = 9 + x;
return factorFunction;
}
int main(void){
int factors[2];
factors = test(2, 3);
printf("%d", factors[1]);
return 0;
}
Я получаю ошибки компилятора:
smallestMultiple.c:8: warning: return makes integer from pointer without a cast
smallestMultiple.c:8: warning: function returns address of local variable
smallestMultiple.c: In function ‘main’:
smallestMultiple.c:13: error: incompatible types in assignment
Функции не могут возвращать массивы в C.
Однако они могут возвращать структуры. А структуры могут содержать массивы...
Вы можете вернуть массив, вернув указатель (массивы распадутся на указатели). Тем не менее, это было бы плохо в вашем случае, так как тогда вы возвращали бы указатель на локальную переменную и приводили к поведению undefined. Это связано с тем, что память, на которую указывает возвращенный указатель, больше не действует после возвращения функции, поскольку пространство стека теперь снова используется другими функциями.
Что вы должны сделать, так это передать массив и его размер как аргументы функции.
У вас также есть другая проблема в вашем коде, и вы используете массив размером два, но пишите в третий элемент.
Вам нужно будет выделить память в куче и вернуть указатель. C не может возвращать массивы из функций.
int* test(int size, int x)
{
int* factorFunction = malloc(sizeof(int) * size);
factorFunction[0] = 5 + x;
factorFunction[1] = 7 + x;
factorFunction[2] = 9 + x;
return factorFunction;
}
Первая строка сообщений об ошибках означает именно то, что она говорит: вы объявили функцию как возвращающую int
, но вы пытаетесь вернуть указатель.
Большая проблема (как говорит вторая строка сообщений об ошибках) заключается в том, что массив, к которому вы пытаетесь вернуть указатель, является локальным массивом и, следовательно, выходит из области действия, когда функции возвращаются и перестают быть действительными.
То, что вам нужно сделать, - это динамически выделить массив (т.е. кусок непрерывной памяти) с помощью malloc
или new
и вернуть указатель на него. И, конечно же, убедитесь, что вы освобождаете память, когда закончите с ней.
К сожалению, C не поддерживает возврат произвольных массивов или анонимных структур из функций, но есть два обходных пути.
Первым решением является создание структуры, содержащей в ней массив. Он будет иметь тот же размер, что и массив, который будет выделен в стеке, обеспечивая пространственную локальность.
например.
typedef struct {
int arr[5];
} my_array1;
typedef struct {
int values[3];
} factorFunctionReturnType_t;
Вторым обходным решением является создание пула статической памяти (например, массив с настраиваемым malloc/free для этого массива), и это позволит вам динамически распределять память из этого пула, снова эффективно возвращая указатель на непрерывный стек пространство, которое по определению является массивом.
например.
#include <stdint.h>
static uint8_t static_pool[2048];
Затем реализуем my_alloc, my_free, которые управляют этим конкретным пулом памяти, снова гарантируя, что созданная память находится в стеке, а память уже принадлежит вашему приложению apriori (тогда как malloc может выделять память, ранее недоступную приложению или сбой, если недостаточно памяти и не проверял возврат отказа).
Третьим решением является функция, возвращающая локальную переменную в функцию обратного вызова; это гарантирует, что после завершения функции вы можете использовать результат без искажения стека, потому что функция, использующая память, будет сидеть над областью, содержащей стек.
#include <stdint.h>
#include <stdio.h>
void returnsAnArray(void (*accept)(void *)) {
char result[] = "Hello, World!";
accept(result);
}
void on_accept(void *result) {
puts((char *)result);
}
int main(int argc, char **argv)
{
returnsAnArray(on_accept);
return 0;
}
Это более эффективно, чем пул памяти, не содержащий стека, который должен принимать решения во избежание фрагментации, более эффективный, чем пул в виде стека, который просто помещает результат поверх стека, потому что ему не нужно копировать строку, и более потокобезопасными, потому что возвращаемое значение функции не может быть перезаписано другим потоком (если не используется блокировка).
Самое смешное, что все "парадигмы функционального программирования" в конечном итоге подчеркивают, что вы можете писать программы на C без какого-либо malloc путем цепочки функций обратного вызова, эффективно выделяя в стеке.
У этого есть интересный побочный эффект создания связанных списков, которые больше не кэшируют враждебные (поскольку связанные с обратным вызовом списки, выделенные в стеке, все будут находиться рядом друг с другом в стеке, что позволяет делать такие вещи, как манипуляции с runtime string без каких-либо mallocs, и позволяет вам создавать неизвестные пользовательские входы без каких-либо mallocs.
C не рекомендует возвращать адрес локальной переменной вне функции, поэтому вам нужно будет определить локальную переменную как статическую.
#include <stdio.h>
/* function to generate and return random numbers */
int * getRandom( ) {
static int r[10];
int i;
/* set the seed */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i) {
r[i] = rand();
printf( "r[%d] = %d\n", i, r[i]);
}
return r;
}
/* main function to call above defined function */
int main () {
/* a pointer to an int */
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ ) {
printf( "*(p + %d) : %d\n", i, *(p + i));
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int* test(int size, int x){
int *factorFunction = (int *) malloc(sizeof(int) * size);
if( factorFunction != NULL ) //makes sure malloc was successful
{
factorFunction[0] = 5 + x;
factorFunction[1] = 7 + x;
factorFunction[2] = 9 + x; //this line won't work because your array is only 2 ints long
}
return factorFunction;
}
int main(void){
int *factors;
factors = test(2, 3);
printf("%d", factors[1]);
//just remember to free the variable back to the heap when you're done
free(factors);
return 0;
}
вы также можете захотеть убедиться, что индексы, которые вы устанавливаете, действительно существуют в вашем массиве, как я отметил выше
Во-первых, если у вас нет C99, у которого VLA s, размер массива должен быть постоянным на C. Вы не можете использовать инструкцию ниже
int factorFunction[size];
Во-вторых, вы пытаетесь вернуть массив, созданный в функции, которая будет удалена из области.
Чтобы этого избежать, вы можете взять массив как параметр в тестовой функции или динамически создать массив с помощью функции malloc
. Btw ваша функция test
может возвращать указатель на обновленный массив.
Мое предложение состояло в том, чтобы передать массив, чтобы заполнить:
void test(int size, int factors[], int x){
factorFunction[0] = 5 + x;
factorFunction[1] = 7 + x;
factorFunction[2] = 9 + x;
}
int main(void){
int factors[3];
test(3, factors, 3);
printf("%d", factors[1]);
return 0;
}
С помощью этого метода вам не нужно беспокоиться о распределении, и вам не нужно будет освобождать массив позже.
Я также исправил размер массива, поэтому вы не пишете его за третьим элементом. Помните, что массивы C объявляются "сколько хотите", а затем индексируются из 0 ... (how_many-1)
, поэтому [2]
в массиве, объявленном с помощью [2]
, выходит за пределы массива.
Вот еще один способ передать массив:
int test(){
static int factorFunction[3];
factorFunction[0] = 5 + x;
factorFunction[1] = 7 + x;
factorFunction[2] = 9 + x;
return factorFunction;
}
Статичность указывает, что переменная будет распределена таким образом, чтобы она оставалась в памяти. Поэтому, если у вас есть фиксированный размер для значения и вы хотите, чтобы он оставался в памяти между вызовами функций, это один из способов сделать это.
Во-первых, вы не можете вернуть массив из функции в C напрямую. Что вы можете сделать, так это то, что вы можете вернуть адрес массива в эту функцию. В этом случае функция будет выглядеть примерно так:
int* test(int size, int x){
/* function body */
return factorFunction;
}
А для получения массива вам понадобится указатель - не массив.
Итак, вместо int factors[2];
вы должны использовать int *factors;
в своей функции main
.
Во-вторых, даже если вы вернете адрес массива, этот код не будет работать; потому что вы пытаетесь вернуть адрес локального массива; который не будет существовать после выполнения функции. Один простой способ решить эту проблему - объявить локальный массив (factorFunction
в этом случае) static.
Учитывая эти два вопроса, функция test
будет выглядеть так:
int* test(int size, int x){
static int factorFunction[size];
/* function body */
return factorFunction;
}
Очень простое объяснение кода о том, как вернуть массив обратно из пользовательской функции в основную функцию, надеюсь, это поможет. Ниже я написал полный код, чтобы сделать. простите за язык c++, однако, пожалуйста, не стесняйтесь комментировать, если вам нужна именно программа c
#include<iostream>
using namespace std;
int * function_Random()// function with returning pointer type of integer
{
static int arr[100];
cout<<"We are Inside FunctionRandom"<<endl;
for(int i=0;i<100;i++)//loop to add elements in array
{
arr[i]=rand();//rand() function to put random numbers generated by system
cout<<"\t"<<arr[i]; //to show how our array will look
}
cout<<endl<<endl;//endl for end line to look well formatted
return arr;
}
int main()
{
int *arrptr; //pointer to get back base address of array
arrptr=function_Random();//function that returns base address
cout<<"We are Inside Main"<<endl;
for(int j=0;j<100;j++)
{
cout<<"\t"<<arrptr[j];//returned base address has complete link of array that why it is able to print the array:contiguous memory locations.
}
return 0;//nothing to return that why 0
}