pouco conhecido: O operador unary plus pode ser usado como um "operador de decaimento": Dado int a[10]; int b(void);, então +aé um ponteiro int e +bé um ponteiro de função. Útil se você deseja passá-lo para um modelo que aceita uma referência.
Johannes Schaub - litb 22/09/09
3
@litb - parens faria o mesmo (por exemplo, (a) deve ser uma expressão avaliada como um ponteiro), certo?
Michael Burr
21
std::decaydo C ++ 14 seria uma maneira menos obscura de deteriorar uma matriz sobre o + unário.
legends2k
21
@ JohannesSchaub-litb uma vez que esta questão é marcado C e C ++, eu gostaria de esclarecer que, embora +ae +bsão legais em C ++, é ilegal em C (C11 6.5.3.3/1 "O operando da unário +ou -operador deve ter tipo aritmético ")
MM
5
@lege Right. Mas suponho que isso não seja tão pouco conhecido quanto o truque do + unário. A razão pela qual eu mencionei não foi apenas porque deteriora, mas porque é algo divertido de se brincar;)
Johannes Schaub - litb
Respostas:
283
Dizem que matrizes "decaem" em ponteiros. Uma matriz C ++ declarada como int numbers [5]não pode ser apontada novamente, ou seja, você não pode dizer numbers = 0x5a5aff23. Mais importante ainda, o termo decadência significa perda de tipo e dimensão; numbersdecaia int*perdendo as informações da dimensão (contagem 5) e o tipo não existe int [5]mais. Veja aqui os casos em que a deterioração não acontece .
Se você estiver passando uma matriz por valor, o que realmente está fazendo é copiar um ponteiro - um ponteiro para o primeiro elemento da matriz é copiado para o parâmetro (cujo tipo também deve ser um ponteiro para o tipo de elemento da matriz). Isso funciona devido à natureza em decomposição da matriz; uma vez deteriorado, sizeofnão fornece mais o tamanho completo da matriz, porque se torna essencialmente um ponteiro. É por isso que é preferível (entre outros motivos) passar por referência ou ponteiro.
Três maneiras de passar em uma matriz 1 :
void by_value(const T* array)// const T array[] means the samevoid by_pointer(const T (*array)[U])void by_reference(const T (&array)[U])
Os dois últimos fornecerão sizeofinformações apropriadas , enquanto o primeiro não fornecerá , desde que o argumento do array tenha se deteriorado para ser atribuído ao parâmetro.
1 A constante U deve ser conhecida em tempo de compilação.
by_value está passando um ponteiro para o primeiro elemento da matriz; no contexto dos parâmetros de função, T a[]é idêntico a T *a. by_pointer está passando a mesma coisa, exceto que o valor do ponteiro agora está qualificado const. Se você deseja passar um ponteiro para a matriz (em oposição a um ponteiro para o primeiro elemento da matriz), a sintaxe é T (*array)[U].
John Bode
4
"com um ponteiro explícito para essa matriz" - isso está incorreto. Se aé uma matriz de char, então aé do tipo char[N]e decairá para char*; mas &aé do tipo char(*)[N]e não se deteriora.
Pavel Minaev 22/09/09
5
@FredOverflow: Então, se as Ualterações não forem necessárias, lembre-se de alterá-las em dois lugares ou corra o risco de erros silenciosos ... Autonomia!
Corridas de leveza em órbita
4
"Se você está passando uma matriz por valor, o que realmente está fazendo é copiar um ponteiro" Isso não faz sentido, porque as matrizes não podem ser passadas por valor, ponto final.
Juanchopanza # 20/15
103
Matrizes são basicamente os mesmos que ponteiros em C / C ++, mas não exatamente. Depois de converter uma matriz:
constint a[]={2,3,5,7,11};
em um ponteiro (que funciona sem conversão e, portanto, pode ocorrer inesperadamente em alguns casos):
constint* p = a;
você perde a capacidade do sizeofoperador de contar elementos na matriz:
assert(sizeof(p)!=sizeof(a));// sizes are not equal
Essa habilidade perdida é chamada de "deterioração".
Matrizes não são basicamente iguais a ponteiros; eles são animais completamente diferentes. Na maioria dos contextos, uma matriz pode ser tratada como se fosse um ponteiro, e um ponteiro pode ser tratado como se fosse uma matriz, mas isso é o mais próximo possível.
John Bode
20
@ John, por favor, perdoe minha linguagem imprecisa. Eu estava tentando chegar à resposta sem ficar atolado em uma longa história de fundo, e "basicamente ... mas não exatamente" é uma explicação tão boa quanto eu já tive na faculdade. Tenho certeza de que qualquer pessoa interessada pode obter uma imagem mais precisa do seu comentário votado.
system PAUSE
"obras sem vazamento" significa o mesmo que "acontecem implicitamente" ao falar sobre conversões de tipo
MM
47
Aqui está o que o padrão diz (C99 6.3.2.1/3 - Outros operandos - Lvalues, matrizes e designadores de função):
Exceto quando é o operando do operador sizeof ou o operador unary &, ou é uma cadeia de caracteres literal usada para inicializar uma matriz, uma expressão que tem o tipo '' matriz do tipo '' é convertida em uma expressão com o tipo '' ponteiro para digite '' que aponta para o elemento inicial do objeto da matriz e não é um lvalue.
Isso significa que praticamente sempre que o nome do array é usado em uma expressão, ele é automaticamente convertido em um ponteiro para o 1º item do array.
Observe que os nomes das funções agem de maneira semelhante, mas os ponteiros de função são usados muito menos e de uma maneira muito mais especializada que não causa tanta confusão quanto a conversão automática de nomes de matriz em ponteiros.
O padrão C ++ (conversão de matriz para ponteiro 4.2) afrouxa o requisito de conversão para (ênfase minha):
Um lvalue ou rvalue do tipo "array of NT" ou "array de limite desconhecido de T" pode ser convertido em um rvalue do tipo "apontador para T."
Portanto, a conversão não precisa acontecer como acontece quase sempre em C (isso permite sobrecarga de funções ou modelos correspondentes no tipo de matriz).
É também por isso que em C você deve evitar o uso de parâmetros de matriz em protótipos / definições de funções (na minha opinião - não tenho certeza se há algum acordo geral). Eles causam confusão e são uma ficção de qualquer maneira - use parâmetros de ponteiro e a confusão pode não desaparecer completamente, mas pelo menos a declaração de parâmetro não está mentindo.
O que é um exemplo de linha de código em que uma "expressão que tem o tipo 'matriz do tipo'" é "uma literal de seqüência de caracteres usada para inicializar uma matriz"?
Garrett
4
@Garrett char x[] = "Hello";. A matriz de 6 elementos "Hello"não decai; em vez disso, xobtém tamanho 6e seus elementos são inicializados a partir dos elementos de "Hello".
MM
30
"Decaimento" refere-se à conversão implícita de uma expressão de um tipo de matriz para um tipo de ponteiro. Na maioria dos contextos, quando o compilador vê uma expressão de matriz, ele converte o tipo da expressão de "matriz do elemento N de T" em "ponteiro para T" e define o valor da expressão para o endereço do primeiro elemento da matriz . As excepções a esta regra são quando uma matriz é um operando de ambos os sizeofou &operadores, ou a matriz é uma string literal sendo usado como um inicializador em uma declaração.
Suponha o seguinte código:
char a[80];
strcpy(a,"This is a test");
A expressão aé do tipo "matriz de 80 elementos do caractere" e a expressão "Este é um teste" é do tipo "matriz de 16 elementos do caractere" (em C; na string C ++, literais são matrizes de const char). No entanto, na chamada para strcpy(), nenhuma expressão é um operando de sizeofou &, portanto, seus tipos são implicitamente convertidos em "ponteiro para char" e seus valores são definidos no endereço do primeiro elemento em cada um. O que strcpy()recebe não são matrizes, mas ponteiros, como visto em seu protótipo:
char*strcpy(char*dest,constchar*src);
Isso não é a mesma coisa que um ponteiro de matriz. Por exemplo:
Ambos ptr_to_first_elemente ptr_to_arraytêm o mesmo valor ; o endereço base de a. No entanto, são tipos diferentes e são tratados de maneira diferente, conforme mostrado abaixo:
Recordar que a expressão a[i]é interpretada como *(a+i)(que só funciona se o tipo de matriz é convertido para um tipo de ponteiro), de modo que ambos a[i]e ptr_to_first_element[i]trabalho a mesma. A expressão (*ptr_to_array)[i]é interpretada como *(*a+i). As expressões *ptr_to_array[i]e ptr_to_array[i]podem levar a avisos ou erros do compilador, dependendo do contexto; eles definitivamente farão a coisa errada se você espera que eles avaliem a[i].
sizeof a ==sizeof*ptr_to_array ==80
Novamente, quando uma matriz é um operando de sizeof, não é convertida em um tipo de ponteiro.
sizeof*ptr_to_first_element ==sizeof(char)==1sizeof ptr_to_first_element ==sizeof(char*)== whatever the pointer size
is on your platform
ptr_to_first_element é um ponteiro simples para char.
Não é "This is a test" is of type "16-element array of char"um "15-element array of char"? (comprimento 14 + 1 para \ 0)
chux - Reinstala Monica 7/13
16
Matrizes, em C, não têm valor.
Onde quer que o valor de um objeto seja esperado, mas o objeto seja uma matriz, o endereço do seu primeiro elemento será usado com type pointer to (type of array elements).
Em uma função, todos os parâmetros são passados por valor (matrizes não são exceção). Quando você passa um array em uma função, "decai em um ponteiro" (sic); quando você compara uma matriz com outra coisa, ela "decai em um ponteiro" (sic); ...
void foo(int arr[]);
A função foo espera o valor de uma matriz. Mas, em C, matrizes não têm valor! Então, fooobtém o endereço do primeiro elemento da matriz.
int arr[5];int*ip =&(arr[1]);if(arr == ip){/* something; */}
Na comparação acima, arrnão tem valor, então se torna um ponteiro. Torna-se um ponteiro para int. Esse ponteiro pode ser comparado com a variável ip.
Na sintaxe de indexação de array que você está acostumado a ver, novamente, o arr é 'deteriorado para um ponteiro'
arr[42];/* same as *(arr + 42); *//* same as *(&(arr[0]) + 42); */
As únicas vezes em que uma matriz não se decompõe em um ponteiro é quando é o operando do operador sizeof, ou o operador & (o operador 'address of'), ou como uma string literal usada para inicializar uma matriz de caracteres.
"Matrizes não têm valor" - o que isso significa? De matrizes curso tem valor ... eles são objetos, você pode ter ponteiros, e, em C ++, as referências a eles, etc.
Pavel Minaev
2
Creio que, estritamente, "Valor" é definido em C como a interpretação dos bits de um objeto de acordo com um tipo. Eu tenho dificuldade em descobrir um significado útil disso com um tipo de matriz. Em vez disso, você pode dizer que converte em um ponteiro, mas isso não está interpretando o conteúdo da matriz, apenas obtém sua localização. O que você obtém é o valor de um ponteiro (e é um endereço), não o valor de uma matriz (isso seria "a sequência de valores dos itens contidos", conforme usado na definição de "string"). Dito isto, acho justo dizer "valor da matriz" quando se quer dizer o ponteiro que se recebe.
Johannes Schaub - litb 22/09/09
de qualquer forma, acho que há uma pequena ambiguidade: valor de um objeto e valor de uma expressão (como em "rvalue"). Se interpretada da última maneira, uma expressão de matriz certamente tem um valor: é a resultante da decomposição em um rvalor e é a expressão do ponteiro. Mas se interpretado da maneira anterior, é claro que não há significado útil para um objeto de matriz.
Johannes Schaub - litb 22/09/09
11
+1 para a frase com uma pequena correção; para matrizes, nem sequer é um trigêmeo, apenas um dístico [local, tipo]. Você tinha outra coisa em mente para o terceiro local no caso da matriz? Não consigo pensar em nada.
legends2k
11
@ legends2k: Acho que usei o terceiro local em matrizes para evitar torná-los um caso especial de ter apenas um dístico. Talvez [localização, tipo, vazio ] tivesse sido melhor.
pmg
8
É quando o array apodrece e está sendo apontado para ;-)
Na verdade, é só que, se você deseja passar uma matriz em algum lugar, mas o ponteiro é passado (porque quem diabos passaria toda a matriz por você), as pessoas dizem que essa matriz pobre se deteriorou para apontar.
Bem dito. O que seria uma boa matriz que não decaia para um ponteiro ou uma que é impedida de decair? Você pode citar um exemplo em C? Obrigado.
Unheilig
@ Unheilig, com certeza, pode-se compactar uma matriz no struct e passar a estrutura.
Michael Krelin - hacker de
Não tenho certeza do que você quer dizer com "trabalho". Não é permitido acessar além da matriz, embora funcione conforme o esperado, se você espera o que realmente deve acontecer. Esse comportamento (embora, novamente, oficialmente indefinido) é preservado.
Michael Krelin - hacker de
A deterioração também ocorre em muitas situações que não passam a matriz em nenhum lugar (conforme descrito por outras respostas). Por exemplo a + 1,.
MM
3
A deterioração da matriz significa que, quando uma matriz é passada como parâmetro para uma função, ela é tratada de forma idêntica a ("decai para") um ponteiro.
void do_something(int*array){// We don't know how big array is here, because it's decayed to a pointer.
printf("%i\n",sizeof(array));// always prints 4 on a 32-bit machine}int main (int argc,char**argv){int a[10];int b[20];int*c;
printf("%zu\n",sizeof(a));//prints 40 on a 32-bit machine
printf("%zu\n",sizeof(b));//prints 80 on a 32-bit machine
printf("%zu\n",sizeof(c));//prints 4 on a 32-bit machine
do_something(a);
do_something(b);
do_something(c);}
Existem duas complicações ou exceções ao acima.
Primeiro, ao lidar com matrizes multidimensionais em C e C ++, apenas a primeira dimensão é perdida. Isso ocorre porque as matrizes são dispostas de forma contígua na memória; portanto, o compilador deve conhecer tudo, exceto a primeira dimensão, para poder calcular as compensações nesse bloco de memória.
void do_something(int array[][10]){// We don't know how big the first dimension is.}int main(int argc,char*argv[]){int a[5][10];int b[20][10];
do_something(a);
do_something(b);return0;}
Segundo, em C ++, você pode usar modelos para deduzir o tamanho das matrizes. A Microsoft usa isso para as versões C ++ das funções Secure CRT, como strcpy_s , e você pode usar um truque semelhante para obter com segurança o número de elementos em uma matriz .
Eu posso ser tão ousado ao pensar que existem quatro (4) maneiras de passar uma matriz como argumento de função. Também aqui está o código curto, mas funcional, para sua leitura.
#include<iostream>#include<string>#include<vector>#include<cassert>usingnamespace std;// test data// notice native array init with no copy aka "="// not possible in Cconstchar* specimen[]{ __TIME__, __DATE__, __TIMESTAMP__ };// ONE// simple, dangerous and uselesstemplate<typename T>void as_pointer(const T*array){// a pointer
assert(array!=nullptr);};// TWO// for above const T array[] means the same// but and also , minimum array size indication might be given too// this also does not stop the array decay into T *// thus size information is losttemplate<typename T>void by_value_no_size(const T array[0xFF]){// decayed to a pointer
assert(array!=nullptr);}// THREE// size information is preserved// but pointer is asked fortemplate<typename T,size_t N>void pointer_to_array(const T (*array)[N]){// dealing with native pointer
assert(array!=nullptr);}// FOUR// no C equivalent// array by reference// size is preservedtemplate<typename T,size_t N>void reference_to_array(const T (&array)[N]){// array is not a pointer here// it is (almost) a container// most of the std:: lib algorithms // do work on array reference, for example// range for requires std::begin() and std::end()// on the type passed as range to iterate overfor(auto&& elem :array){
cout << endl << elem ;}}int main(){// ONE
as_pointer(specimen);// TWO
by_value_no_size(specimen);// THREE
pointer_to_array(&specimen);// FOUR
reference_to_array( specimen );}
Eu também acho que isso mostra a superioridade de C ++ vs C. Pelo menos em referência (trocadilhos) de passar uma matriz por referência.
É claro que existem projetos extremamente rígidos, sem alocação de heap, sem exceções e sem std :: lib. O tratamento de array nativo em C ++ é um recurso de linguagem de missão crítica, pode-se dizer.
int a[10]; int b(void);
, então+a
é um ponteiro int e+b
é um ponteiro de função. Útil se você deseja passá-lo para um modelo que aceita uma referência.std::decay
do C ++ 14 seria uma maneira menos obscura de deteriorar uma matriz sobre o + unário.+a
e+b
são legais em C ++, é ilegal em C (C11 6.5.3.3/1 "O operando da unário+
ou-
operador deve ter tipo aritmético ")Respostas:
Dizem que matrizes "decaem" em ponteiros. Uma matriz C ++ declarada como
int numbers [5]
não pode ser apontada novamente, ou seja, você não pode dizernumbers = 0x5a5aff23
. Mais importante ainda, o termo decadência significa perda de tipo e dimensão;numbers
decaiaint*
perdendo as informações da dimensão (contagem 5) e o tipo não existeint [5]
mais. Veja aqui os casos em que a deterioração não acontece .Se você estiver passando uma matriz por valor, o que realmente está fazendo é copiar um ponteiro - um ponteiro para o primeiro elemento da matriz é copiado para o parâmetro (cujo tipo também deve ser um ponteiro para o tipo de elemento da matriz). Isso funciona devido à natureza em decomposição da matriz; uma vez deteriorado,
sizeof
não fornece mais o tamanho completo da matriz, porque se torna essencialmente um ponteiro. É por isso que é preferível (entre outros motivos) passar por referência ou ponteiro.Três maneiras de passar em uma matriz 1 :
Os dois últimos fornecerão
sizeof
informações apropriadas , enquanto o primeiro não fornecerá , desde que o argumento do array tenha se deteriorado para ser atribuído ao parâmetro.1 A constante U deve ser conhecida em tempo de compilação.
fonte
T a[]
é idêntico aT *a
. by_pointer está passando a mesma coisa, exceto que o valor do ponteiro agora está qualificadoconst
. Se você deseja passar um ponteiro para a matriz (em oposição a um ponteiro para o primeiro elemento da matriz), a sintaxe éT (*array)[U]
.a
é uma matriz dechar
, entãoa
é do tipochar[N]
e decairá parachar*
; mas&a
é do tipochar(*)[N]
e não se deteriora.U
alterações não forem necessárias, lembre-se de alterá-las em dois lugares ou corra o risco de erros silenciosos ... Autonomia!Matrizes são basicamente os mesmos que ponteiros em C / C ++, mas não exatamente. Depois de converter uma matriz:
em um ponteiro (que funciona sem conversão e, portanto, pode ocorrer inesperadamente em alguns casos):
você perde a capacidade do
sizeof
operador de contar elementos na matriz:Essa habilidade perdida é chamada de "deterioração".
Para mais detalhes, consulte este artigo sobre decaimento de matriz .
fonte
Aqui está o que o padrão diz (C99 6.3.2.1/3 - Outros operandos - Lvalues, matrizes e designadores de função):
Isso significa que praticamente sempre que o nome do array é usado em uma expressão, ele é automaticamente convertido em um ponteiro para o 1º item do array.
Observe que os nomes das funções agem de maneira semelhante, mas os ponteiros de função são usados muito menos e de uma maneira muito mais especializada que não causa tanta confusão quanto a conversão automática de nomes de matriz em ponteiros.
O padrão C ++ (conversão de matriz para ponteiro 4.2) afrouxa o requisito de conversão para (ênfase minha):
Portanto, a conversão não precisa acontecer como acontece quase sempre em C (isso permite sobrecarga de funções ou modelos correspondentes no tipo de matriz).
É também por isso que em C você deve evitar o uso de parâmetros de matriz em protótipos / definições de funções (na minha opinião - não tenho certeza se há algum acordo geral). Eles causam confusão e são uma ficção de qualquer maneira - use parâmetros de ponteiro e a confusão pode não desaparecer completamente, mas pelo menos a declaração de parâmetro não está mentindo.
fonte
char x[] = "Hello";
. A matriz de 6 elementos"Hello"
não decai; em vez disso,x
obtém tamanho6
e seus elementos são inicializados a partir dos elementos de"Hello"
."Decaimento" refere-se à conversão implícita de uma expressão de um tipo de matriz para um tipo de ponteiro. Na maioria dos contextos, quando o compilador vê uma expressão de matriz, ele converte o tipo da expressão de "matriz do elemento N de T" em "ponteiro para T" e define o valor da expressão para o endereço do primeiro elemento da matriz . As excepções a esta regra são quando uma matriz é um operando de ambos os
sizeof
ou&
operadores, ou a matriz é uma string literal sendo usado como um inicializador em uma declaração.Suponha o seguinte código:
A expressão
a
é do tipo "matriz de 80 elementos do caractere" e a expressão "Este é um teste" é do tipo "matriz de 16 elementos do caractere" (em C; na string C ++, literais são matrizes de const char). No entanto, na chamada parastrcpy()
, nenhuma expressão é um operando desizeof
ou&
, portanto, seus tipos são implicitamente convertidos em "ponteiro para char" e seus valores são definidos no endereço do primeiro elemento em cada um. O questrcpy()
recebe não são matrizes, mas ponteiros, como visto em seu protótipo:Isso não é a mesma coisa que um ponteiro de matriz. Por exemplo:
Ambos
ptr_to_first_element
eptr_to_array
têm o mesmo valor ; o endereço base de a. No entanto, são tipos diferentes e são tratados de maneira diferente, conforme mostrado abaixo:Recordar que a expressão
a[i]
é interpretada como*(a+i)
(que só funciona se o tipo de matriz é convertido para um tipo de ponteiro), de modo que ambosa[i]
eptr_to_first_element[i]
trabalho a mesma. A expressão(*ptr_to_array)[i]
é interpretada como*(*a+i)
. As expressões*ptr_to_array[i]
eptr_to_array[i]
podem levar a avisos ou erros do compilador, dependendo do contexto; eles definitivamente farão a coisa errada se você espera que eles avaliema[i]
.Novamente, quando uma matriz é um operando de
sizeof
, não é convertida em um tipo de ponteiro.ptr_to_first_element
é um ponteiro simples para char.fonte
"This is a test" is of type "16-element array of char"
um"15-element array of char"
? (comprimento 14 + 1 para \ 0)Matrizes, em C, não têm valor.
Onde quer que o valor de um objeto seja esperado, mas o objeto seja uma matriz, o endereço do seu primeiro elemento será usado com type
pointer to (type of array elements)
.Em uma função, todos os parâmetros são passados por valor (matrizes não são exceção). Quando você passa um array em uma função, "decai em um ponteiro" (sic); quando você compara uma matriz com outra coisa, ela "decai em um ponteiro" (sic); ...
A função foo espera o valor de uma matriz. Mas, em C, matrizes não têm valor! Então,
foo
obtém o endereço do primeiro elemento da matriz.Na comparação acima,
arr
não tem valor, então se torna um ponteiro. Torna-se um ponteiro para int. Esse ponteiro pode ser comparado com a variávelip
.Na sintaxe de indexação de array que você está acostumado a ver, novamente, o arr é 'deteriorado para um ponteiro'
As únicas vezes em que uma matriz não se decompõe em um ponteiro é quando é o operando do operador sizeof, ou o operador & (o operador 'address of'), ou como uma string literal usada para inicializar uma matriz de caracteres.
fonte
É quando o array apodrece e está sendo apontado para ;-)
Na verdade, é só que, se você deseja passar uma matriz em algum lugar, mas o ponteiro é passado (porque quem diabos passaria toda a matriz por você), as pessoas dizem que essa matriz pobre se deteriorou para apontar.
fonte
a + 1
,.A deterioração da matriz significa que, quando uma matriz é passada como parâmetro para uma função, ela é tratada de forma idêntica a ("decai para") um ponteiro.
Existem duas complicações ou exceções ao acima.
Primeiro, ao lidar com matrizes multidimensionais em C e C ++, apenas a primeira dimensão é perdida. Isso ocorre porque as matrizes são dispostas de forma contígua na memória; portanto, o compilador deve conhecer tudo, exceto a primeira dimensão, para poder calcular as compensações nesse bloco de memória.
Segundo, em C ++, você pode usar modelos para deduzir o tamanho das matrizes. A Microsoft usa isso para as versões C ++ das funções Secure CRT, como strcpy_s , e você pode usar um truque semelhante para obter com segurança o número de elementos em uma matriz .
fonte
tl; dr: Quando você usa uma matriz que você define, na verdade você usa um ponteiro para o primeiro elemento.
Portanto:
arr[idx]
está realmente apenas dizendo*(arr + idx)
.Exceções de tipo a esta regra:
struct
.sizeof()
fornece o tamanho ocupado pela matriz, não o tamanho de um ponteiro.fonte
Eu posso ser tão ousado ao pensar que existem quatro (4) maneiras de passar uma matriz como argumento de função. Também aqui está o código curto, mas funcional, para sua leitura.
Eu também acho que isso mostra a superioridade de C ++ vs C. Pelo menos em referência (trocadilhos) de passar uma matriz por referência.
É claro que existem projetos extremamente rígidos, sem alocação de heap, sem exceções e sem std :: lib. O tratamento de array nativo em C ++ é um recurso de linguagem de missão crítica, pode-se dizer.
fonte