Hablando estrictamente en este contexto, no necesita devolver la matriz, ya que la matriz se pasa por referencia, por lo que cualquier cambio en los elementos dentro de 'arr' se verá fuera de la función.
BuggerMe
12
devolver la matriz es conveniente para encadenar funciones.
Seand
55
Siempre y cuando no esté cometiendo el error de crear una matriz en la pila y devolverle un puntero.
detly
2
@ismail: no puede devolver una nueva matriz, a menos que esa matriz se haya asignado dinámicamente. Y si ese es el caso, úsalo std::vector.
GManNickG
44
@BuggerMe: Las matrices no se pasan por referencia (a menos que lo solicite con una sintaxis mucho más divertida), en el código, la matriz se desintegra en un puntero al primer elemento y eso se pasa a la función. El 5compilador descarta la firma en la función.
David Rodríguez - dribeas
Respuestas:
204
En este caso, su variable de matriz arrtambién puede tratarse como un puntero al comienzo del bloque de su matriz en la memoria, mediante una conversión implícita. Esta sintaxis que estás usando:
int fillarr(int arr[])
Es una especie de azúcar sintáctica. Realmente podría reemplazarlo con esto y aún funcionaría:
int fillarr(int* arr)
Entonces, en el mismo sentido, lo que desea devolver de su función es en realidad un puntero al primer elemento de la matriz:
int* fillarr(int arr[])
Y aún podrá usarlo como lo haría con una matriz normal:
int main(){int y[10];int*a = fillarr(y);
cout << a[0]<< endl;}
Para aclarar, esa "declaración clásica de C ++" es falsa; Las matrices no son punteros.
GManNickG
25
recuerde la regla a [i] == * (a + i)
2010
8
@Brent Nash, no. Una matriz es una matriz. Un puntero al inicio de la matriz es un puntero. Simplemente sucede que el compilador tiene algo de azúcar sintáctico que hace la traducción por usted en algunas situaciones. arrayy &arrayson intercambiables en muchos casos.
Carl Norum
20
@Brent: No. Una matriz es de su propio tipo, no es un tipo especial de puntero. El tipo de aen int a[10]es int[10]. Lo que puede decir es que las matrices "decaen" en punteros a su primer elemento. (Esta es una conversión implícita de matriz a puntero). Entonces su respuesta iría en la misma línea que la mía. Si edita su respuesta para diferenciar entre matrices, conversión de matriz a puntero y punteros, eliminaré mi respuesta ya que tendrían la misma información central y usted fue el primero.
GManNickG
8
@seand recuerda la regla a [i] == * (a + sizeof (a) * i)
Amir
114
Las funciones de C ++ no pueden devolver matrices de estilo C por valor. Lo más cercano es devolver un puntero. Además, un tipo de matriz en la lista de argumentos simplemente se convierte en un puntero.
int*fillarr(int arr[]){// arr "decays" to type int *return arr;}
Puede mejorarlo utilizando una matriz de referencias para el argumento y el retorno, lo que evita la descomposición:
int(&fillarr(int(&arr)[5]))[5]{// no decay; argument must be size 5return arr;}
Con Boost o C ++ 11, la referencia de paso solo es opcional y la sintaxis es menos alucinante:
array<int,5>&fillarr(array<int,5>&arr ){return arr;// "array" being boost::array or std::array}
La arrayplantilla simplemente genera una structmatriz que contiene un estilo C, por lo que puede aplicar una semántica orientada a objetos y conservar la simplicidad original de la matriz.
+1 para dar un ejemplo de cómo se puede pasar una matriz por referencia. Pero está equivocado porque no puede devolver una matriz por referencia. La sintaxis más sencilla de lograrlo es mediante el uso de un typedef: typedef int array[5]; array& foo();Pero usted ni siquiera necesita el typedef si es que quiere escribir esto: int (&foo())[5] { static int a[5] = {}; return a; }, el ejemplo de la pregunta sería: int (&foo( int (&a)[5] ))[5] { return a; }. Simple, ¿no es así?
David Rodríguez - dribeas
@David: gracias, recibí la impresión errónea del mensaje de Comeau error: function returning array is not allowedque ocurre si se omiten los parentes externos en la sintaxis no typedef. Afortunadamente, hoy revisé la regla derecha-izquierda para otra pregunta y logré construir lo correcto ... después de ver que dijiste que es posible ... antes de ver que le diste el código: vP.
Potatoswatter
1
La respuesta de chubsdad tiene la cita correcta del estándar: no puede devolver una matriz, pero puede devolver una referencia o puntero a una matriz. Las matrices no se pueden copiar (como tipo) y, como tales, no se pueden devolver, lo que implicaría una copia, y cuando esa sintaxis está presente, el compilador convertirá el argumento en un puntero.
David Rodríguez - dribeas
3
@David: Así es. Esta página se está volviendo extrañamente larga. Nunca tantas personas han escrito voluntariamente tantas funciones triviales que devuelven una matriz en un solo lugar.
Potatoswatter
@Potatoswatter Soy nuevo en cpp, ¿Puedes explicar el segundo fragmento de código en detalle? No puedo dividirlo en partes en aras de la comprensión.
Citando OP:(...) you can consider the array returned arr2, totally another array (...)
cubuspl42
22
$ 8.3.5 / 8 estados-
"Las funciones no tendrán un tipo de retorno de tipo de matriz o función, aunque pueden tener un tipo de retorno de puntero de tipo o referencia a tales cosas. No habrá matrices de funciones, aunque puede haber matrices de punteros a funciones".
int(&fn1(int(&arr)[5]))[5]{// declare fn1 as returning refernce to arrayreturn arr;}int*fn2(int arr[]){// declare fn2 as returning pointer to arrayreturn arr;}int main(){int buf[5];
fn1(buf);
fn2(buf);}
Su segunda función devuelve un puntero a un int, no a una matriz.
GManNickG
de nuevo, ¿por qué devolver el tipo cuando la matriz real se actualiza dentro de la función? ¿Es una cuestión de mejores prácticas?
Dan
14
la respuesta puede depender un poco de cómo planea usar esa función. Para la respuesta más simple, decidamos que en lugar de una matriz, lo que realmente quiere es un vector. Los vectores son agradables porque el aspecto de todo el mundo es aburrido, los valores ordinarios que puede almacenar en punteros regulares. Veremos otras opciones y por qué las quiere después:
std::vector<int> fillarr( std::vector<int> arr ){// do somethingreturn arr;}
Esto hará exactamente lo que espera que haga. Lo bueno es questd::vector se asegura de que todo se maneje de manera limpia. La desventaja es que esto copia una gran cantidad de datos, si su matriz es grande. De hecho, copia cada elemento de la matriz dos veces. primero copia el vector para que la función pueda usarlo como parámetro. luego lo copia nuevamente para devolverlo a la persona que llama. Si puede manejar la administración del vector usted mismo, puede hacer las cosas con bastante más facilidad. (puede copiarlo por tercera vez si la persona que llama necesita almacenarlo en una variable de algún tipo para hacer más cálculos)
Parece que lo que realmente estás tratando de hacer es llenar una colección. Si no tiene un motivo específico para devolver una nueva instancia de una colección, no lo haga. podemos hacerlo así
De esta forma, obtiene una referencia a la matriz que se pasa a la función, no una copia privada de la misma. la persona que llama puede ver cualquier cambio que realice en el parámetro. Podría devolverle una referencia si lo desea, pero esa no es una gran idea, ya que implica que está obteniendo algo diferente de lo que aprobó.
Si realmente necesita una nueva instancia de la colección, pero desea evitar tenerla en la pila (y todas las copias que conlleva), debe crear algún tipo de contrato sobre cómo se maneja esa instancia. la forma más fácil de hacerlo es usar un puntero inteligente, que mantiene la instancia referenciada mientras alguien la esté sosteniendo. Se va limpiamente si se sale del alcance. Eso se vería así.
std::auto_ptr<std::vector<int>> fillarr(const std::vector<int>& arr){
std::auto_ptr<std::vector<int>> myArr(new std::vector<int>);// do stuff with arr and *myArrreturn myArr;}
En su mayor parte, el uso *myArrfunciona de manera idéntica al uso de un vector simple de vainilla. Este ejemplo también modifica la lista de parámetros al agregar la constpalabra clave. Ahora obtiene una referencia sin copiarla, pero no puede modificarla, por lo que la persona que llama sabe que será la misma que antes de que la función llegara a ella.
Todo esto es genial, pero la idiomática c ++ rara vez funciona con colecciones en su conjunto. Más normalmente, usará iteradores sobre esas colecciones. eso se vería más como esto
La sintaxis es incorrecta, el &símbolo debe aparecer después del tipo:void fillarr(std::vector<int> & arr)
David Rodríguez - dribeas
9
Esta:
int fillarr(int arr[])
en realidad se trata igual que:
int fillarr(int*arr)
Ahora, si realmente desea devolver una matriz, puede cambiar esa línea a
int* fillarr(int arr[]){// do something to arrreturn arr;}
Realmente no está devolviendo una matriz. está devolviendo un puntero al inicio de la dirección de la matriz.
Pero recuerde que cuando pasa en la matriz, solo pasa un puntero. Entonces, cuando modifica los datos de la matriz, en realidad está modificando los datos a los que apunta el puntero. Por lo tanto, antes de pasar la matriz, debe darse cuenta de que ya tiene en el exterior el resultado modificado.
Sugiero que desee considerar poner una longitud en su función fillarr como esta.
int* fillarr(int arr[],int length)
De esa manera, puede usar la longitud para llenar la matriz a su longitud sin importar cuál sea.
Para usarlo realmente correctamente. Haz algo como esto:
int* fillarr(int arr[],int length){for(int i =0; i < length;++i){// arr[i] = ? // do what you want to do here}return arr;}// then where you want to use it.int arr[5];int*arr2;
arr2 = fillarr(arr,5);// at this point, arr & arr2 are basically the same, just slightly// different types. You can cast arr to a (char*) and it'll be the same.
Si todo lo que desea hacer es establecer la matriz en algunos valores predeterminados, considere usar la función integrada de memset.
También podemos devolver la matriz. Para devolver la matriz, el tipo de retorno de la función debe ser de tipo estructura, es decir, marcas. Esto se debe a que en realidad estamos pasando la estructura que contiene la matriz. Entonces el código final puede verse así.
Esta es una pregunta bastante antigua, pero voy a poner mis 2 centavos, ya que hay muchas respuestas, pero ninguna muestra todos los métodos posibles de una manera clara y concisa (no estoy seguro acerca del bit conciso, ya que esto obtuvo un poco fuera de control TL; DR 😉).
Supongo que el OP quería devolver la matriz que se pasó sin copiar, ya que algunos medios de pasar esto directamente al llamador para que se pase a otra función para que el código se vea más bonito.
Sin embargo, usar una matriz como esta es dejar que se descomponga en un puntero y que el compilador la trate como una matriz. Esto puede provocar errores sutiles si pasa en una matriz como, con la función esperando que tenga 5 elementos, pero su llamador realmente pasa algún otro número.
Hay algunas maneras en que puede manejar esto mejor. Pase en unstd::vector o std::array(no estoy seguro si std::arrayexistía en 2010 cuando se hizo la pregunta). Luego puede pasar el objeto como referencia sin copiar ni mover el objeto.
std::array<int,5>& fillarr(std::array<int,5>& arr){// (before c++11)for(auto it = arr.begin(); it != arr.end();++it){/* do stuff */}// Note the following are for c++11 and higher. They will work for all// the other examples below except for the stuff after the Edit.// (c++11 and up)for(auto it = std::begin(arr); it != std::end(arr);++it){/* do stuff */}// range for loop (c++11 and up)for(auto& element : arr){/* do stuff */}return arr;}
std::vector<int>& fillarr(std::vector<int>& arr){for(auto it = arr.begin(); it != arr.end();++it){/* do stuff */}return arr;}
Sin embargo, si insiste en jugar con matrices C, utilice una plantilla que mantenga la información de cuántos elementos hay en la matriz.
template<size_t N>int(&fillarr(int(&arr)[N]))[N]{// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])for(int* it = arr; it != arr + N;++it){/* do stuff */}return arr;}
Excepto que parece feo y súper difícil de leer. Ahora uso algo para ayudar con lo que no existía en 2010, que también uso para los punteros de función:
template<typename T>usingtype_t= T;template<size_t N>type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr){// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])for(int* it = arr; it != arr + N;++it){/* do stuff */}return arr;}
Esto mueve el tipo donde uno esperaría que fuera, haciendo que esto sea mucho más legible. Por supuesto, usar una plantilla es superfluo si no va a usar nada más que 5 elementos, por lo que puede, por supuesto, codificarlo:
type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr){// Prefer using the compiler to figure out how many elements there are// as it reduces the number of locations where you have to change if needed.for(int* it = arr; it != arr +sizeof(arr)/sizeof(arr[0]);++it){/* do stuff */}return arr;}
Como dije, mi type_t<>truco no hubiera funcionado cuando se hizo esta pregunta. Lo mejor que podría haber esperado en ese entonces era usar un tipo en una estructura:
template<typename T>struct type
{typedef T type;};typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr){// Prefer using the compiler to figure out how many elements there are// as it reduces the number of locations where you have to change if needed.for(int* it = arr; it != arr +sizeof(arr)/sizeof(arr[0]);++it){/* do stuff */}return arr;}
Lo que comienza a verse bastante feo nuevamente, pero al menos es aún más legible, aunque typenamepuede haber sido opcional en ese momento dependiendo del compilador, lo que resulta en:
type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr){// Prefer using the compiler to figure out how many elements there are// as it reduces the number of locations where you have to change if needed.for(int* it = arr; it != arr +sizeof(arr)/sizeof(arr[0]);++it){/* do stuff */}return arr;}
Y luego, por supuesto, podría haber especificado un tipo específico, en lugar de usar mi ayudante.
typedefint(&array5)[5];
array5 fillarr(array5 arr){// Prefer using the compiler to figure out how many elements there are// as it reduces the number of locations where you have to change if needed.for(int* it = arr; it != arr +sizeof(arr)/sizeof(arr[0]);++it){/* do stuff */}return arr;}
En aquel entonces, las funciones gratuitas std::begin()ystd::end() no existían, aunque podrían haberse implementado fácilmente. Esto habría permitido iterar sobre la matriz de una manera más segura ya que tienen sentido en una matriz C, pero no en un puntero.
En cuanto al acceso a la matriz, puede pasarla a otra función que tome el mismo tipo de parámetro o crear un alias (lo que no tendría mucho sentido ya que ya tiene el original en ese ámbito). Acceder a una referencia de matriz es como acceder a la matriz original.
void other_function(type_t<int(&)[5]> x){/* do something else */}void fn(){intarray[5];
other_function(fillarr(array));}
o
void fn(){intarray[5];auto& array2 = fillarr(array);// alias. But why bother.int forth_entry =array[4];int forth_entry2 = array2[4];// same value as forth_entry}
Para resumir, es mejor no permitir que una matriz decaiga en un puntero si tiene la intención de iterar sobre ella. Es una mala idea, ya que evita que el compilador lo proteja de dispararse en el pie y hace que su código sea más difícil de leer. Siempre intente ayudar al compilador a ayudarlo manteniendo los tipos el mayor tiempo posible a menos que tenga una muy buena razón para no hacerlo.
Editar
Ah, y para completar, puede permitir que se degrade en un puntero, pero esto desacopla la matriz de la cantidad de elementos que contiene. Esto se hace mucho en C / C ++ y generalmente se mitiga al pasar el número de elementos en la matriz. Sin embargo, el compilador no puede ayudarlo si comete un error y pasa el valor incorrecto a la cantidad de elementos.
// separate size valueint* fillarr(int* arr,size_t size){for(int* it = arr; it != arr + size;++it){/* do stuff */}return arr;}
En lugar de pasar el tamaño, puede pasar el puntero final, que apuntará a uno más allá del final de su matriz. Esto es útil ya que crea algo que está más cerca de los algoritmos estándar, que toman un puntero de inicio y fin, pero lo que devuelve ahora es solo algo que debe recordar.
// separate end pointerint* fillarr(int* arr,int* end){for(int* it = arr; it != end;++it){/* do stuff */}return arr;}
Alternativamente, puede documentar que esta función solo tomará 5 elementos y esperar que el usuario de su función no haga nada estúpido.
// I document that this function will ONLY take 5 elements and // return the same array of 5 elements. If you pass in anything// else, may nazal demons exit thine nose!int* fillarr(int* arr){for(int* it = arr; it != arr +5;++it){/* do stuff */}return arr;}
Tenga en cuenta que el valor de retorno ha perdido su tipo original y se degrada a un puntero. Debido a esto, ahora está solo para asegurarse de que no va a sobrepasar la matriz.
Podrías pasar un std::pair<int*, int*>, que puedes usar para comenzar y terminar y pasarlo, pero luego deja de parecer una matriz.
std::pair<int*,int*> fillarr(std::pair<int*,int*> arr){for(int* it = arr.first; it != arr.second;++it){/* do stuff */}return arr;// if you change arr, then return the original arr value.}void fn(){intarray[5];auto array2 = fillarr(std::make_pair(&array[0],&array[5]));// Can be done, but you have the original array in scope, so why bother.int fourth_element = array2.first[4];}
o
void other_function(std::pair<int*,int*>array){// Can be done, but you have the original array in scope, so why bother.int fourth_element = array2.first[4];}void fn(){intarray[5];
other_function(fillarr(std::make_pair(&array[0],&array[5])));}
Curiosamente, esto es muy similar a cómo std::initializer_listfunciona (c ++ 11), pero no funcionan en este contexto.
No creo que el 'int [] fillarr ...' sea legal. El 'int * fillarr' es lo que usaría debido a la equivalencia de puntero de matriz.
Seand
1
Como se mencionó anteriormente, las rutas son correctas. Pero creo que si solo devolvemos una variable de matriz local de una función, a veces devuelve valores basura como sus elementos.
para evitar tener que crear la matriz dinámicamente y continuar. Que es algo como esto.
C ++ no permite devolver una matriz completa como argumento para una función. Sin embargo, puede devolver un puntero a una matriz especificando el nombre de la matriz sin un índice.
Si desea devolver una matriz de dimensión única de una función, deberá declarar una función que devuelva un puntero como en el siguiente ejemplo:
int* myFunction(){...}
C ++ no recomienda devolver la dirección de una variable local al exterior de la función, por lo que tendría que definir la variable local como variable estática.
Aplicando estas reglas a la pregunta actual, podemos escribir el programa de la siguiente manera:
# include <iostream>usingnamespace std;int* fillarr();int main (){int*p;
p = fillarr();for(int i =0; i <5; i++)
cout <<"p["<< i <<"] : "<<*(p + i)<< endl;return0;}int* fillarr(){staticint arr[5];for(int i =0; i <5;++i)
arr[i]= i;return arr;}
En realidad, cuando pasa una matriz dentro de una función, el puntero a la matriz original se pasa en el parámetro de la función y, por lo tanto, los cambios realizados en la matriz dentro de esa función se realizan realmente en la matriz original.
Utilice una redacción adecuada en inglés (en lugar de usted) y omita frases vacías como "amigo".
hola
Además: "entonces en realidad se pasa como referencia" está mal. La variable en ysí se pasa como una copia de sí misma, pero debido a que es un puntero, operará directamente en la matriz. Por favor edite su respuesta.
std::vector
.5
compilador descarta la firma en la función.Respuestas:
En este caso, su variable de matriz
arr
también puede tratarse como un puntero al comienzo del bloque de su matriz en la memoria, mediante una conversión implícita. Esta sintaxis que estás usando:Es una especie de azúcar sintáctica. Realmente podría reemplazarlo con esto y aún funcionaría:
Entonces, en el mismo sentido, lo que desea devolver de su función es en realidad un puntero al primer elemento de la matriz:
Y aún podrá usarlo como lo haría con una matriz normal:
fuente
array
y&array
son intercambiables en muchos casos.a
enint a[10]
esint[10]
. Lo que puede decir es que las matrices "decaen" en punteros a su primer elemento. (Esta es una conversión implícita de matriz a puntero). Entonces su respuesta iría en la misma línea que la mía. Si edita su respuesta para diferenciar entre matrices, conversión de matriz a puntero y punteros, eliminaré mi respuesta ya que tendrían la misma información central y usted fue el primero.Las funciones de C ++ no pueden devolver matrices de estilo C por valor. Lo más cercano es devolver un puntero. Además, un tipo de matriz en la lista de argumentos simplemente se convierte en un puntero.
Puede mejorarlo utilizando una matriz de referencias para el argumento y el retorno, lo que evita la descomposición:
Con Boost o C ++ 11, la referencia de paso solo es opcional y la sintaxis es menos alucinante:
La
array
plantilla simplemente genera unastruct
matriz que contiene un estilo C, por lo que puede aplicar una semántica orientada a objetos y conservar la simplicidad original de la matriz.fuente
typedef int array[5]; array& foo();
Pero usted ni siquiera necesita el typedef si es que quiere escribir esto:int (&foo())[5] { static int a[5] = {}; return a; }
, el ejemplo de la pregunta sería:int (&foo( int (&a)[5] ))[5] { return a; }
. Simple, ¿no es así?error: function returning array is not allowed
que ocurre si se omiten los parentes externos en la sintaxis no typedef. Afortunadamente, hoy revisé la regla derecha-izquierda para otra pregunta y logré construir lo correcto ... después de ver que dijiste que es posible ... antes de ver que le diste el código: vP.En C ++ 11, puede regresar
std::array
.fuente
(...) you can consider the array returned arr2, totally another array (...)
$ 8.3.5 / 8 estados-
"Las funciones no tendrán un tipo de retorno de tipo de matriz o función, aunque pueden tener un tipo de retorno de puntero de tipo o referencia a tales cosas. No habrá matrices de funciones, aunque puede haber matrices de punteros a funciones".
fuente
int
, no a una matriz.la respuesta puede depender un poco de cómo planea usar esa función. Para la respuesta más simple, decidamos que en lugar de una matriz, lo que realmente quiere es un vector. Los vectores son agradables porque el aspecto de todo el mundo es aburrido, los valores ordinarios que puede almacenar en punteros regulares. Veremos otras opciones y por qué las quiere después:
Esto hará exactamente lo que espera que haga. Lo bueno es que
std::vector
se asegura de que todo se maneje de manera limpia. La desventaja es que esto copia una gran cantidad de datos, si su matriz es grande. De hecho, copia cada elemento de la matriz dos veces. primero copia el vector para que la función pueda usarlo como parámetro. luego lo copia nuevamente para devolverlo a la persona que llama. Si puede manejar la administración del vector usted mismo, puede hacer las cosas con bastante más facilidad. (puede copiarlo por tercera vez si la persona que llama necesita almacenarlo en una variable de algún tipo para hacer más cálculos)Parece que lo que realmente estás tratando de hacer es llenar una colección. Si no tiene un motivo específico para devolver una nueva instancia de una colección, no lo haga. podemos hacerlo así
De esta forma, obtiene una referencia a la matriz que se pasa a la función, no una copia privada de la misma. la persona que llama puede ver cualquier cambio que realice en el parámetro. Podría devolverle una referencia si lo desea, pero esa no es una gran idea, ya que implica que está obteniendo algo diferente de lo que aprobó.
Si realmente necesita una nueva instancia de la colección, pero desea evitar tenerla en la pila (y todas las copias que conlleva), debe crear algún tipo de contrato sobre cómo se maneja esa instancia. la forma más fácil de hacerlo es usar un puntero inteligente, que mantiene la instancia referenciada mientras alguien la esté sosteniendo. Se va limpiamente si se sale del alcance. Eso se vería así.
En su mayor parte, el uso
*myArr
funciona de manera idéntica al uso de un vector simple de vainilla. Este ejemplo también modifica la lista de parámetros al agregar laconst
palabra clave. Ahora obtiene una referencia sin copiarla, pero no puede modificarla, por lo que la persona que llama sabe que será la misma que antes de que la función llegara a ella.Todo esto es genial, pero la idiomática c ++ rara vez funciona con colecciones en su conjunto. Más normalmente, usará iteradores sobre esas colecciones. eso se vería más como esto
Usarlo parece un poco extraño si no estás acostumbrado a ver este estilo.
foo ahora 'señala' el comienzo de la modificación
arr
.Lo que es realmente bueno de esto es que funciona igual de bien en vectores que en matrices C simples y muchos otros tipos de colección, por ejemplo
Que ahora se parece muchísimo a los ejemplos de punteros simples dados en otra parte de esta pregunta.
fuente
&
símbolo debe aparecer después del tipo:void fillarr(std::vector<int> & arr)
Esta:
en realidad se trata igual que:
Ahora, si realmente desea devolver una matriz, puede cambiar esa línea a
Realmente no está devolviendo una matriz. está devolviendo un puntero al inicio de la dirección de la matriz.
Pero recuerde que cuando pasa en la matriz, solo pasa un puntero. Entonces, cuando modifica los datos de la matriz, en realidad está modificando los datos a los que apunta el puntero. Por lo tanto, antes de pasar la matriz, debe darse cuenta de que ya tiene en el exterior el resultado modificado.
p.ej
Sugiero que desee considerar poner una longitud en su función fillarr como esta.
De esa manera, puede usar la longitud para llenar la matriz a su longitud sin importar cuál sea.
Para usarlo realmente correctamente. Haz algo como esto:
Si todo lo que desea hacer es establecer la matriz en algunos valores predeterminados, considere usar la función integrada de memset.
algo como: memset ((int *) & arr, 5, sizeof (int));
Aunque estoy en el tema sin embargo. Dices que estás usando C ++. Echa un vistazo al uso de vectores stl. Es probable que su código sea más robusto.
Hay muchos tutoriales. Aquí hay uno que le da una idea de cómo usarlos. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
fuente
std::copy
másmemset
, es más seguro y más fácil. (E igual de rápido si no más rápido)para devolver una matriz de una función, definamos esa matriz en una estructura; Entonces se ve algo como esto
Ahora creemos variables de la estructura de tipo.
Podemos pasar la matriz a una función de la siguiente manera y asignarle un valor:
También podemos devolver la matriz. Para devolver la matriz, el tipo de retorno de la función debe ser de tipo estructura, es decir, marcas. Esto se debe a que en realidad estamos pasando la estructura que contiene la matriz. Entonces el código final puede verse así.
fuente
Esta es una pregunta bastante antigua, pero voy a poner mis 2 centavos, ya que hay muchas respuestas, pero ninguna muestra todos los métodos posibles de una manera clara y concisa (no estoy seguro acerca del bit conciso, ya que esto obtuvo un poco fuera de control TL; DR 😉).
Supongo que el OP quería devolver la matriz que se pasó sin copiar, ya que algunos medios de pasar esto directamente al llamador para que se pase a otra función para que el código se vea más bonito.
Sin embargo, usar una matriz como esta es dejar que se descomponga en un puntero y que el compilador la trate como una matriz. Esto puede provocar errores sutiles si pasa en una matriz como, con la función esperando que tenga 5 elementos, pero su llamador realmente pasa algún otro número.
Hay algunas maneras en que puede manejar esto mejor. Pase en un
std::vector
ostd::array
(no estoy seguro sistd::array
existía en 2010 cuando se hizo la pregunta). Luego puede pasar el objeto como referencia sin copiar ni mover el objeto.Sin embargo, si insiste en jugar con matrices C, utilice una plantilla que mantenga la información de cuántos elementos hay en la matriz.
Excepto que parece feo y súper difícil de leer. Ahora uso algo para ayudar con lo que no existía en 2010, que también uso para los punteros de función:
Esto mueve el tipo donde uno esperaría que fuera, haciendo que esto sea mucho más legible. Por supuesto, usar una plantilla es superfluo si no va a usar nada más que 5 elementos, por lo que puede, por supuesto, codificarlo:
Como dije, mi
type_t<>
truco no hubiera funcionado cuando se hizo esta pregunta. Lo mejor que podría haber esperado en ese entonces era usar un tipo en una estructura:Lo que comienza a verse bastante feo nuevamente, pero al menos es aún más legible, aunque
typename
puede haber sido opcional en ese momento dependiendo del compilador, lo que resulta en:Y luego, por supuesto, podría haber especificado un tipo específico, en lugar de usar mi ayudante.
En aquel entonces, las funciones gratuitas
std::begin()
ystd::end()
no existían, aunque podrían haberse implementado fácilmente. Esto habría permitido iterar sobre la matriz de una manera más segura ya que tienen sentido en una matriz C, pero no en un puntero.En cuanto al acceso a la matriz, puede pasarla a otra función que tome el mismo tipo de parámetro o crear un alias (lo que no tendría mucho sentido ya que ya tiene el original en ese ámbito). Acceder a una referencia de matriz es como acceder a la matriz original.
o
Para resumir, es mejor no permitir que una matriz decaiga en un puntero si tiene la intención de iterar sobre ella. Es una mala idea, ya que evita que el compilador lo proteja de dispararse en el pie y hace que su código sea más difícil de leer. Siempre intente ayudar al compilador a ayudarlo manteniendo los tipos el mayor tiempo posible a menos que tenga una muy buena razón para no hacerlo.
Editar
Ah, y para completar, puede permitir que se degrade en un puntero, pero esto desacopla la matriz de la cantidad de elementos que contiene. Esto se hace mucho en C / C ++ y generalmente se mitiga al pasar el número de elementos en la matriz. Sin embargo, el compilador no puede ayudarlo si comete un error y pasa el valor incorrecto a la cantidad de elementos.
En lugar de pasar el tamaño, puede pasar el puntero final, que apuntará a uno más allá del final de su matriz. Esto es útil ya que crea algo que está más cerca de los algoritmos estándar, que toman un puntero de inicio y fin, pero lo que devuelve ahora es solo algo que debe recordar.
Alternativamente, puede documentar que esta función solo tomará 5 elementos y esperar que el usuario de su función no haga nada estúpido.
Tenga en cuenta que el valor de retorno ha perdido su tipo original y se degrada a un puntero. Debido a esto, ahora está solo para asegurarse de que no va a sobrepasar la matriz.
Podrías pasar un
std::pair<int*, int*>
, que puedes usar para comenzar y terminar y pasarlo, pero luego deja de parecer una matriz.o
Curiosamente, esto es muy similar a cómo
std::initializer_list
funciona (c ++ 11), pero no funcionan en este contexto.fuente
La forma más simple de hacer esto es devolverlo por referencia, incluso si no escribe el símbolo '&', se devuelve automáticamente por referencia
fuente
Todavía puedes usar el resultado como
fuente
Como se mencionó anteriormente, las rutas son correctas. Pero creo que si solo devolvemos una variable de matriz local de una función, a veces devuelve valores basura como sus elementos.
para evitar tener que crear la matriz dinámicamente y continuar. Que es algo como esto.
fuente
fuente
Fuente: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
C ++ no permite devolver una matriz completa como argumento para una función. Sin embargo, puede devolver un puntero a una matriz especificando el nombre de la matriz sin un índice.
Aplicando estas reglas a la pregunta actual, podemos escribir el programa de la siguiente manera:
La salida será:
fuente
y que hay con:
fuente
En realidad, cuando pasa una matriz dentro de una función, el puntero a la matriz original se pasa en el parámetro de la función y, por lo tanto, los cambios realizados en la matriz dentro de esa función se realizan realmente en la matriz original.
Ejecútalo y verás los cambios
fuente
y
sí se pasa como una copia de sí misma, pero debido a que es un puntero, operará directamente en la matriz. Por favor edite su respuesta.Aquí hay un ejemplo completo de este tipo de problema para resolver
fuente
Simplemente defina un tipo [] como valor de retorno, como:
. . . Llamada de función:
fuente