estritamente falando neste contexto, você não precisa retornar a matriz, uma vez que a matriz é passada por referência; portanto, quaisquer alterações nos elementos dentro de 'arr' serão vistas fora da função.
BuggerMe
12
retornar o array é conveniente para encadear funções.
seand
5
Desde que você não cometa o erro de criar uma matriz na pilha e retornar um ponteiro para ela.
detly 13/08/10
2
@ismail: não pode retornar uma nova matriz, a menos que essa matriz tenha sido alocada dinamicamente. E se for esse o caso, use std::vector.
GManNickG
4
@ BuggerMe: matrizes não são passadas por referência (a menos que você solicite com uma sintaxe muito mais engraçada); no código, a matriz decai em um ponteiro para o primeiro elemento e que é passado para a função. A 5assinatura na função é descartada pelo compilador.
David Rodríguez - dribeas 13/08/10
Respostas:
204
Nesse caso, sua variável de matriz arrtambém pode ser tratada como um ponteiro para o início do bloco da matriz na memória, por uma conversão implícita. Esta sintaxe que você está usando:
int fillarr(int arr[])
É uma espécie de açúcar sintático. Você poderia realmente substituí-lo por isso e ainda funcionaria:
int fillarr(int* arr)
Portanto, no mesmo sentido, o que você deseja retornar da sua função é na verdade um ponteiro para o primeiro elemento da matriz:
int* fillarr(int arr[])
E você ainda poderá usá-lo exatamente como faria em um array normal:
int main(){int y[10];int*a = fillarr(y);
cout << a[0]<< endl;}
Para esclarecer, essa "declaração clássica de C ++" é falsa; matrizes não são ponteiros.
GManNickG
25
lembre-se a uma [i] == * (a + i) regra
seand
8
@Brent Nash, não. uma matriz é uma matriz. Um ponteiro para o início da matriz é um ponteiro. Acontece que o compilador tem um pouco de açúcar sintático que faz a tradução para você em algumas situações. arraye &arraysão intercambiáveis em muitos casos.
Carl Norum
20
@Brent: Não. Uma matriz é do seu próprio tipo, não é um tipo especial de ponteiro. O tipo de aem int a[10]é int[10]. O que você pode dizer é que as matrizes "deterioram" em ponteiros para o primeiro elemento. (Esta é uma conversão implícita de matriz em ponteiro.) Então sua resposta seguirá as linhas que a minha faz. Se você editar sua resposta para diferenciar matrizes, conversão de matriz para ponteiro e ponteiros, excluirei minha resposta, pois elas teriam as mesmas informações principais e você foi o primeiro.
GManNickG
8
@seand lembrar a a [i] == * (a + sizeof (a) * i) regra
Amir
114
As funções C ++ não podem retornar matrizes no estilo C por valor. O mais próximo é retornar um ponteiro. Além disso, um tipo de matriz na lista de argumentos é simplesmente convertido em um ponteiro.
int*fillarr(int arr[]){// arr "decays" to type int *return arr;}
Você pode aprimorá-lo usando referências de matriz para o argumento e retorno, o que impede a deterioração:
int(&fillarr(int(&arr)[5]))[5]{// no decay; argument must be size 5return arr;}
Com o Boost ou o C ++ 11, a passagem por referência é apenas opcional e a sintaxe é menos preocupante:
array<int,5>&fillarr(array<int,5>&arr ){return arr;// "array" being boost::array or std::array}
O arraymodelo simplesmente gera um que structcontém uma matriz no estilo C, para que você possa aplicar a semântica orientada a objetos e ainda manter a simplicidade original da matriz.
+1 para dar um exemplo de como uma matriz pode ser transmitida por referência. Mas você está errado, pois não pode retornar uma matriz por referência. A sintaxe mais simples de conseguir isso é usando um typedef: typedef int array[5]; array& foo();Mas você não precisa mesmo do typedef se o cuidado de escrever isto: int (&foo())[5] { static int a[5] = {}; return a; }o exemplo na pergunta seria: int (&foo( int (&a)[5] ))[5] { return a; }. Simples, não é?
David Rodríguez - dribeas 13/08
@ David: obrigado, eu recebi a impressão errada da mensagem do Comeau error: function returning array is not allowedque ocorre se você deixar de fora os parâmetros externos na sintaxe não digitada. Felizmente, hoje revi a regra da direita para a esquerda para outra pergunta e consegui construir a coisa certa ... depois de ver você dizer que é possível ... antes de ver que você deu o código: vP.
Potatoswatter 13/08/10
1
A resposta de chubsdad tem a citação correta do padrão: você não pode retornar uma matriz, mas pode retornar uma referência ou ponteiro para uma matriz. As matrizes não são copiáveis (como um tipo) e, como tal, não podem ser retornadas - o que implicaria uma cópia - e quando essa sintaxe estiver presente, o compilador converterá o argumento em um ponteiro.
David Rodríguez - dribeas 13/08
3
@ David: O mesmo acontece. Esta página está ficando estranhamente longa. Nunca tantas pessoas escreveram voluntariamente tantas funções triviais retornando uma matriz em um só lugar.
Potatoswatter 13/08/10
@Potatoswatter Eu sou novo no cpp. Você pode explicar o segundo trecho de código em detalhes? Não sou capaz de dividi-lo em partes por uma questão de compreensão.
Citando OP:(...) you can consider the array returned arr2, totally another array (...)
cubuspl42
22
$ 8.3.5 / 8 estados-
"As funções não devem ter um tipo de retorno de matriz ou função de tipo, embora possam ter um tipo de retorno de ponteiro de tipo ou referência a essas coisas. Não deve haver matrizes de funções, embora possa haver matrizes de ponteiros para funções".
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);}
Sua segunda função retorna um ponteiro para um int, não um array.
GManNickG
novamente, por que retornar o tipo quando a matriz real é atualizada dentro da função? É uma questão de boas práticas?
Dan
14
a resposta pode depender um pouco de como você planeja usar essa função. Para a resposta mais simples, vamos decidir que, em vez de uma matriz, o que você realmente deseja é um vetor. Os vetores são bons porque a aparência de todo o mundo é como valores comuns e chatos que você pode armazenar em indicadores regulares. Veremos outras opções e por que você as deseja posteriormente:
std::vector<int> fillarr( std::vector<int> arr ){// do somethingreturn arr;}
Isso fará exatamente o que você espera. A vantagem é que std::vectorse certifica de que tudo seja tratado de maneira limpa. A desvantagem é que isso copia uma quantidade muito grande de dados, se sua matriz for grande. De fato, ele copia todos os elementos da matriz duas vezes. primeiro copia o vetor para que a função possa usá-lo como parâmetro. depois o copia novamente para devolvê-lo ao chamador. Se você conseguir gerenciar o vetor você mesmo, poderá fazer as coisas com mais facilidade. (ele pode ser copiado uma terceira vez se o chamador precisar armazená-lo em uma variável de algum tipo para fazer mais cálculos)
Parece que o que você realmente está tentando fazer é preencher uma coleção. se você não tiver um motivo específico para retornar uma nova instância de uma coleção, não o faça. podemos fazer assim
dessa forma, você obtém uma referência à matriz passada para a função, não uma cópia particular dela. todas as alterações feitas no parâmetro são vistas pelo chamador. Você pode retornar uma referência a ela, se quiser, mas isso não é realmente uma ótima idéia, pois implica que você está recebendo algo diferente do que passou.
Se você realmente precisa de uma nova instância da coleção, mas deseja evitar tê-la na pilha (e em todas as cópias que isso implica), é necessário criar algum tipo de contrato para o tratamento dessa instância. a maneira mais fácil de fazer isso é usar um ponteiro inteligente, que mantém a instância referenciada por mais tempo que alguém a esteja segurando. Ele desaparece de forma limpa se sair do escopo. Isso seria assim.
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;}
Na maioria das vezes, o uso *myArrfunciona de forma idêntica ao uso de um vetor de baunilha comum. Este exemplo também modifica a lista de parâmetros adicionando a constpalavra - chave. Agora você obtém uma referência sem copiá-la, mas não pode modificá-la, portanto o chamador sabe que será o mesmo de antes da função.
Tudo isso é ótimo, mas o c ++ idiomático raramente funciona com coleções como um todo. Mais normalmente, você usará iteradores sobre essas coleções. que seria algo mais parecido com isto
A sintaxe está incorreta, o &símbolo deve aparecer após o tipo:void fillarr(std::vector<int> & arr)
David Rodríguez - dribeas 13/08
9
Este:
int fillarr(int arr[])
é realmente tratado da mesma forma que:
int fillarr(int*arr)
Agora, se você realmente deseja retornar uma matriz, pode alterar essa linha para
int* fillarr(int arr[]){// do something to arrreturn arr;}
Não está realmente retornando uma matriz. você está retornando um ponteiro para o início do endereço da matriz.
Mas lembre-se de que quando você passa na matriz, está passando apenas um ponteiro. Portanto, quando você modifica os dados da matriz, na verdade está modificando os dados para os quais o ponteiro está apontando. Portanto, antes de passar na matriz, você deve perceber que já possui fora o resultado modificado.
Sugiro que você considere colocar um comprimento em sua função fillarr dessa maneira.
int* fillarr(int arr[],int length)
Dessa forma, você pode usar o comprimento para preencher a matriz com seu comprimento, não importa qual seja.
Para realmente usá-lo corretamente. Faça algo parecido com isto:
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.
Se tudo o que você deseja fazer é definir a matriz com alguns valores padrão, considere usar a função memset integrada.
Enquanto eu estou no assunto, no entanto. Você diz que está usando C ++. Dê uma olhada no uso de vetores stl. É provável que seu código seja mais robusto.
Também podemos retornar a matriz. Para retornar a matriz, o tipo de retorno da função deve ser do tipo estrutura, ou seja, marcas. Isso ocorre porque, na realidade, estamos passando a estrutura que contém a matriz. Portanto, o código final pode ficar assim.
Essa é uma pergunta bastante antiga, mas vou colocar meus 2 centavos, pois há muitas respostas, mas nenhuma mostrando todos os métodos possíveis de maneira clara e concisa (não tenho certeza do que é conciso, pois isso tem uma pouco fora de mão TL; DR 😉).
Estou assumindo que o OP queria retornar a matriz que foi passada sem copiar, como forma de passar isso diretamente para o chamador a ser passado para outra função para tornar o código mais bonito.
No entanto, usar uma matriz como essa é permitir que ela se decomponha em um ponteiro e faça com que o compilador a trate como uma matriz. Isso pode resultar em erros sutis se você passar em uma matriz como, com a função esperando que ela tenha 5 elementos, mas o chamador realmente passa em algum outro número.
Existem algumas maneiras de lidar melhor com isso. Passe um std::vectorou std::array(não tenho certeza se std::arrayexistia em 2010 quando a pergunta foi feita). Você pode então passar o objeto como uma referência sem copiar / mover o 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;}
No entanto, se você insistir em jogar com matrizes C, use um modelo que manterá as informações de quantos itens na 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;}
Exceto que parece feio e super difícil de ler. Agora uso algo para ajudar com o que não existia em 2010, que também uso para ponteiros de função:
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;}
Isso move o tipo onde se esperaria, tornando isso muito mais legível. Obviamente, o uso de um modelo é supérfluo se você não usar nada além de cinco elementos, portanto é possível codificá-lo:
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 eu disse, meu type_t<>truque não teria funcionado no momento em que essa pergunta foi feita. O melhor que você poderia esperar naquela época era usar um tipo em uma estrutura:
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;}
O que começa a parecer muito feio novamente, mas pelo menos ainda é mais legível, embora typenamepossa ter sido opcional na época, dependendo do compilador, resultando em:
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;}
E então é claro que você poderia ter especificado um tipo específico, em vez de usar meu ajudante.
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;}
Naquela época, as funções livres std::begin()e std::end()não existiam, embora poderiam ter sido facilmente implementadas. Isso permitiria iterar sobre a matriz de uma maneira mais segura, pois eles fazem sentido em uma matriz C, mas não em um ponteiro.
Quanto ao acesso ao array, você pode passá-lo para outra função que usa o mesmo tipo de parâmetro ou criar um alias para ele (o que não faria muito sentido, pois você já tem o original nesse escopo). Acessar uma referência de matriz é como acessar a matriz original.
void other_function(type_t<int(&)[5]> x){/* do something else */}void fn(){intarray[5];
other_function(fillarr(array));}
ou
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, é melhor não permitir que uma matriz decaia em um ponteiro se você pretende iterar sobre ele. É apenas uma má idéia, pois impede o compilador de protegê-lo de dar um tiro no pé e torna seu código mais difícil de ler. Sempre tente ajudar o compilador, mantendo os tipos o maior tempo possível, a menos que você tenha um bom motivo para não fazê-lo.
Editar
Ah, e para garantir a integridade, você pode degradar para um ponteiro, mas isso desacopla a matriz do número de elementos que ela contém. Isso é feito muito em C / C ++ e geralmente é atenuado passando o número de elementos na matriz. No entanto, o compilador não pode ajudá-lo se você cometer um erro e passar o valor errado para o número de elementos.
// separate size valueint* fillarr(int* arr,size_t size){for(int* it = arr; it != arr + size;++it){/* do stuff */}return arr;}
Em vez de passar o tamanho, você pode passar o ponteiro final, que apontará para um após o final da sua matriz. Isso é útil, pois contribui para algo mais próximo dos algoritmos std, que levam um ponteiro de início e fim, mas o que você retorna agora é apenas algo que você deve lembrar.
// separate end pointerint* fillarr(int* arr,int* end){for(int* it = arr; it != end;++it){/* do stuff */}return arr;}
Como alternativa, você pode documentar que essa função terá apenas 5 elementos e espere que o usuário da sua função não faça 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;}
Observe que o valor de retorno perdeu seu tipo original e é degradado em um ponteiro. Por causa disso, agora você está por conta própria para garantir que não exceda a matriz.
Você pode passar um std::pair<int*, int*>, que você pode usar para começar, terminar e passar por aí, mas depois ele realmente para de parecer uma 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];}
ou
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])));}
Engraçado o bastante, isso é muito parecido com o std::initializer_listtrabalho (c ++ 11), mas eles não funcionam nesse contexto.
a maneira mais simples de fazer isso é retorná-lo por referência, mesmo que você não escreva o símbolo '&', ele será retornado automaticamente por referência
Eu não acho que o 'int [] fillarr ...' seja legal. O 'int * fillarr' é o que você usaria devido à equivalência de ponteiro de matriz.
seand
1
Como os caminhos mencionados acima estão corretos. Mas acho que, se retornarmos uma variável de matriz local de uma função, algumas vezes ela retornará valores de lixo como seus elementos.
para evitar que eu tivesse que criar a matriz dinamicamente e continuar. O que é algo assim.
C ++ não permite retornar uma matriz inteira como argumento para uma função. No entanto, você pode retornar um ponteiro para uma matriz especificando o nome da matriz sem um índice.
Se você deseja retornar uma matriz de dimensão única de uma função, teria que declarar uma função retornando um ponteiro, como no exemplo a seguir:
int* myFunction(){...}
O C ++ não recomenda retornar o endereço de uma variável local para fora da função; portanto, você deve definir a variável local como variável estática.
Aplicando essas regras na pergunta atual, podemos escrever o programa da seguinte maneira:
# 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;}
Na verdade, quando você passa uma matriz dentro de uma função, o ponteiro para a matriz original é passado no parâmetro function e, portanto, as alterações feitas na matriz dentro dessa função são realmente feitas na matriz original.
Por favor, use o texto em inglês adequado (em vez de você) e omita frases vazias como "amigo".
hellow
Além disso: "então, na verdade, é passado como referência" está errado. A variável em ysi é passada como uma cópia de si mesma, mas como é um ponteiro, você operará diretamente na matriz. Edite sua resposta.
std::vector
.5
assinatura na função é descartada pelo compilador.Respostas:
Nesse caso, sua variável de matriz
arr
também pode ser tratada como um ponteiro para o início do bloco da matriz na memória, por uma conversão implícita. Esta sintaxe que você está usando:É uma espécie de açúcar sintático. Você poderia realmente substituí-lo por isso e ainda funcionaria:
Portanto, no mesmo sentido, o que você deseja retornar da sua função é na verdade um ponteiro para o primeiro elemento da matriz:
E você ainda poderá usá-lo exatamente como faria em um array normal:
fonte
array
e&array
são intercambiáveis em muitos casos.a
emint a[10]
éint[10]
. O que você pode dizer é que as matrizes "deterioram" em ponteiros para o primeiro elemento. (Esta é uma conversão implícita de matriz em ponteiro.) Então sua resposta seguirá as linhas que a minha faz. Se você editar sua resposta para diferenciar matrizes, conversão de matriz para ponteiro e ponteiros, excluirei minha resposta, pois elas teriam as mesmas informações principais e você foi o primeiro.As funções C ++ não podem retornar matrizes no estilo C por valor. O mais próximo é retornar um ponteiro. Além disso, um tipo de matriz na lista de argumentos é simplesmente convertido em um ponteiro.
Você pode aprimorá-lo usando referências de matriz para o argumento e retorno, o que impede a deterioração:
Com o Boost ou o C ++ 11, a passagem por referência é apenas opcional e a sintaxe é menos preocupante:
O
array
modelo simplesmente gera um questruct
contém uma matriz no estilo C, para que você possa aplicar a semântica orientada a objetos e ainda manter a simplicidade original da matriz.fonte
typedef int array[5]; array& foo();
Mas você não precisa mesmo do typedef se o cuidado de escrever isto:int (&foo())[5] { static int a[5] = {}; return a; }
o exemplo na pergunta seria:int (&foo( int (&a)[5] ))[5] { return a; }
. Simples, não é?error: function returning array is not allowed
que ocorre se você deixar de fora os parâmetros externos na sintaxe não digitada. Felizmente, hoje revi a regra da direita para a esquerda para outra pergunta e consegui construir a coisa certa ... depois de ver você dizer que é possível ... antes de ver que você deu o código: vP.No C ++ 11, você pode retornar
std::array
.fonte
(...) you can consider the array returned arr2, totally another array (...)
$ 8.3.5 / 8 estados-
"As funções não devem ter um tipo de retorno de matriz ou função de tipo, embora possam ter um tipo de retorno de ponteiro de tipo ou referência a essas coisas. Não deve haver matrizes de funções, embora possa haver matrizes de ponteiros para funções".
fonte
int
, não um array.a resposta pode depender um pouco de como você planeja usar essa função. Para a resposta mais simples, vamos decidir que, em vez de uma matriz, o que você realmente deseja é um vetor. Os vetores são bons porque a aparência de todo o mundo é como valores comuns e chatos que você pode armazenar em indicadores regulares. Veremos outras opções e por que você as deseja posteriormente:
Isso fará exatamente o que você espera. A vantagem é que
std::vector
se certifica de que tudo seja tratado de maneira limpa. A desvantagem é que isso copia uma quantidade muito grande de dados, se sua matriz for grande. De fato, ele copia todos os elementos da matriz duas vezes. primeiro copia o vetor para que a função possa usá-lo como parâmetro. depois o copia novamente para devolvê-lo ao chamador. Se você conseguir gerenciar o vetor você mesmo, poderá fazer as coisas com mais facilidade. (ele pode ser copiado uma terceira vez se o chamador precisar armazená-lo em uma variável de algum tipo para fazer mais cálculos)Parece que o que você realmente está tentando fazer é preencher uma coleção. se você não tiver um motivo específico para retornar uma nova instância de uma coleção, não o faça. podemos fazer assim
dessa forma, você obtém uma referência à matriz passada para a função, não uma cópia particular dela. todas as alterações feitas no parâmetro são vistas pelo chamador. Você pode retornar uma referência a ela, se quiser, mas isso não é realmente uma ótima idéia, pois implica que você está recebendo algo diferente do que passou.
Se você realmente precisa de uma nova instância da coleção, mas deseja evitar tê-la na pilha (e em todas as cópias que isso implica), é necessário criar algum tipo de contrato para o tratamento dessa instância. a maneira mais fácil de fazer isso é usar um ponteiro inteligente, que mantém a instância referenciada por mais tempo que alguém a esteja segurando. Ele desaparece de forma limpa se sair do escopo. Isso seria assim.
Na maioria das vezes, o uso
*myArr
funciona de forma idêntica ao uso de um vetor de baunilha comum. Este exemplo também modifica a lista de parâmetros adicionando aconst
palavra - chave. Agora você obtém uma referência sem copiá-la, mas não pode modificá-la, portanto o chamador sabe que será o mesmo de antes da função.Tudo isso é ótimo, mas o c ++ idiomático raramente funciona com coleções como um todo. Mais normalmente, você usará iteradores sobre essas coleções. que seria algo mais parecido com isto
Usá-lo parece um pouco estranho se você não está acostumado a ver esse estilo.
foo agora 'aponta para' o início do modificado
arr
.O que é realmente bom nisso é que ele funciona igualmente bem em vetores, como em matrizes C simples e em muitos outros tipos de coleção, por exemplo
Que agora se parece muito com os exemplos simples de ponteiros dados em outras partes desta questão.
fonte
&
símbolo deve aparecer após o tipo:void fillarr(std::vector<int> & arr)
Este:
é realmente tratado da mesma forma que:
Agora, se você realmente deseja retornar uma matriz, pode alterar essa linha para
Não está realmente retornando uma matriz. você está retornando um ponteiro para o início do endereço da matriz.
Mas lembre-se de que quando você passa na matriz, está passando apenas um ponteiro. Portanto, quando você modifica os dados da matriz, na verdade está modificando os dados para os quais o ponteiro está apontando. Portanto, antes de passar na matriz, você deve perceber que já possui fora o resultado modificado.
por exemplo
Sugiro que você considere colocar um comprimento em sua função fillarr dessa maneira.
Dessa forma, você pode usar o comprimento para preencher a matriz com seu comprimento, não importa qual seja.
Para realmente usá-lo corretamente. Faça algo parecido com isto:
Se tudo o que você deseja fazer é definir a matriz com alguns valores padrão, considere usar a função memset integrada.
algo como: memset ((int *) & arr, 5, sizeof (int));
Enquanto eu estou no assunto, no entanto. Você diz que está usando C ++. Dê uma olhada no uso de vetores stl. É provável que seu código seja mais robusto.
Existem muitos tutoriais. Aqui está um que lhe dá uma idéia de como usá-los. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
fonte
std::copy
maismemset
, é mais seguro e fácil. (. E tão rápido se não mais rápido)para retornar uma matriz de uma função, vamos definir essa matriz em uma estrutura; Então parece algo assim
Agora vamos criar variáveis da estrutura de tipos.
Podemos passar a matriz para uma função da seguinte maneira e atribuir valor a ela:
Também podemos retornar a matriz. Para retornar a matriz, o tipo de retorno da função deve ser do tipo estrutura, ou seja, marcas. Isso ocorre porque, na realidade, estamos passando a estrutura que contém a matriz. Portanto, o código final pode ficar assim.
fonte
Essa é uma pergunta bastante antiga, mas vou colocar meus 2 centavos, pois há muitas respostas, mas nenhuma mostrando todos os métodos possíveis de maneira clara e concisa (não tenho certeza do que é conciso, pois isso tem uma pouco fora de mão TL; DR 😉).
Estou assumindo que o OP queria retornar a matriz que foi passada sem copiar, como forma de passar isso diretamente para o chamador a ser passado para outra função para tornar o código mais bonito.
No entanto, usar uma matriz como essa é permitir que ela se decomponha em um ponteiro e faça com que o compilador a trate como uma matriz. Isso pode resultar em erros sutis se você passar em uma matriz como, com a função esperando que ela tenha 5 elementos, mas o chamador realmente passa em algum outro número.
Existem algumas maneiras de lidar melhor com isso. Passe um
std::vector
oustd::array
(não tenho certeza sestd::array
existia em 2010 quando a pergunta foi feita). Você pode então passar o objeto como uma referência sem copiar / mover o objeto.No entanto, se você insistir em jogar com matrizes C, use um modelo que manterá as informações de quantos itens na matriz.
Exceto que parece feio e super difícil de ler. Agora uso algo para ajudar com o que não existia em 2010, que também uso para ponteiros de função:
Isso move o tipo onde se esperaria, tornando isso muito mais legível. Obviamente, o uso de um modelo é supérfluo se você não usar nada além de cinco elementos, portanto é possível codificá-lo:
Como eu disse, meu
type_t<>
truque não teria funcionado no momento em que essa pergunta foi feita. O melhor que você poderia esperar naquela época era usar um tipo em uma estrutura:O que começa a parecer muito feio novamente, mas pelo menos ainda é mais legível, embora
typename
possa ter sido opcional na época, dependendo do compilador, resultando em:E então é claro que você poderia ter especificado um tipo específico, em vez de usar meu ajudante.
Naquela época, as funções livres
std::begin()
estd::end()
não existiam, embora poderiam ter sido facilmente implementadas. Isso permitiria iterar sobre a matriz de uma maneira mais segura, pois eles fazem sentido em uma matriz C, mas não em um ponteiro.Quanto ao acesso ao array, você pode passá-lo para outra função que usa o mesmo tipo de parâmetro ou criar um alias para ele (o que não faria muito sentido, pois você já tem o original nesse escopo). Acessar uma referência de matriz é como acessar a matriz original.
ou
Para resumir, é melhor não permitir que uma matriz decaia em um ponteiro se você pretende iterar sobre ele. É apenas uma má idéia, pois impede o compilador de protegê-lo de dar um tiro no pé e torna seu código mais difícil de ler. Sempre tente ajudar o compilador, mantendo os tipos o maior tempo possível, a menos que você tenha um bom motivo para não fazê-lo.
Editar
Ah, e para garantir a integridade, você pode degradar para um ponteiro, mas isso desacopla a matriz do número de elementos que ela contém. Isso é feito muito em C / C ++ e geralmente é atenuado passando o número de elementos na matriz. No entanto, o compilador não pode ajudá-lo se você cometer um erro e passar o valor errado para o número de elementos.
Em vez de passar o tamanho, você pode passar o ponteiro final, que apontará para um após o final da sua matriz. Isso é útil, pois contribui para algo mais próximo dos algoritmos std, que levam um ponteiro de início e fim, mas o que você retorna agora é apenas algo que você deve lembrar.
Como alternativa, você pode documentar que essa função terá apenas 5 elementos e espere que o usuário da sua função não faça nada estúpido.
Observe que o valor de retorno perdeu seu tipo original e é degradado em um ponteiro. Por causa disso, agora você está por conta própria para garantir que não exceda a matriz.
Você pode passar um
std::pair<int*, int*>
, que você pode usar para começar, terminar e passar por aí, mas depois ele realmente para de parecer uma matriz.ou
Engraçado o bastante, isso é muito parecido com o
std::initializer_list
trabalho (c ++ 11), mas eles não funcionam nesse contexto.fonte
a maneira mais simples de fazer isso é retorná-lo por referência, mesmo que você não escreva o símbolo '&', ele será retornado automaticamente por referência
fonte
Você ainda pode usar o resultado como
fonte
Como os caminhos mencionados acima estão corretos. Mas acho que, se retornarmos uma variável de matriz local de uma função, algumas vezes ela retornará valores de lixo como seus elementos.
para evitar que eu tivesse que criar a matriz dinamicamente e continuar. O que é algo assim.
fonte
fonte
Fonte: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
C ++ não permite retornar uma matriz inteira como argumento para uma função. No entanto, você pode retornar um ponteiro para uma matriz especificando o nome da matriz sem um índice.
Aplicando essas regras na pergunta atual, podemos escrever o programa da seguinte maneira:
A saída será:
fonte
e sobre:
fonte
Na verdade, quando você passa uma matriz dentro de uma função, o ponteiro para a matriz original é passado no parâmetro function e, portanto, as alterações feitas na matriz dentro dessa função são realmente feitas na matriz original.
Execute-o e você verá as alterações
fonte
y
si é passada como uma cópia de si mesma, mas como é um ponteiro, você operará diretamente na matriz. Edite sua resposta.Aqui está um exemplo completo deste tipo de problema para resolver
fonte
Apenas defina um tipo [] como valor de retorno, como:
. . . chamada de função:
fonte