Por que matrizes não podem ser passadas como argumentos de função em C?

12

Após esse comentário , tentei pesquisar no Google por que, mas meu google-fu falhou.

Comentário do link:

[...] Mas o importante é que matrizes e ponteiros são coisas diferentes em C.

Supondo que você não esteja usando nenhuma extensão do compilador, geralmente não é possível passar um array em si para uma função, mas você pode passar um ponteiro e indexar um ponteiro como se fosse um array.

Você está efetivamente reclamando que os ponteiros não têm comprimento anexado. Você deve reclamar que matrizes não podem ser passadas como argumentos de função ou que matrizes são degradadas em ponteiros implicitamente.

Florian Margaine
fonte
Não tenho certeza de que é a resposta, mas parte do tipo de uma matriz é seu tamanho, então acredito que você precisaria definir uma função para cada tamanho que você deseja aceitar.
Clcto
Você quer dizer ponteiros de função ? Por favor, esclareça a pergunta.
user949300
2
@ user949300 Não, do contexto do comentário é bastante claro; você não pode passar uma matriz para uma função porque ela se torna um ponteiro, e ele quer saber por que esse é o caso.
Doval
O @DocBrown rlemon propôs uma edição para isso.
Florian Margaine

Respostas:

18

Meu primeiro palpite pelo motivo foi simplesmente por motivos de desempenho e economia de memória e também pela facilidade de implementação do compilador (especialmente para o tipo de computadores no momento em que C foi inventado). A passagem de grandes matrizes "por valor" parecia ter um grande impacto na pilha, ela precisa de uma operação de cópia de matriz completa para cada chamada de função e, provavelmente, o compilador deve ser mais inteligente para produzir o código de montagem correto (embora o último ponto seja discutível) . Também seria mais difícil tratar matrizes alocadas dinamicamente da mesma maneira que matrizes alocadas estaticamente (do ponto de vista da sintaxe do idioma).

EDIT: depois de ler algumas partes a partir deste link , eu acho que a razão real (ea razão pela qual matrizes em estruturas são tratados como tipos de valor, enquanto matrizes únicos não são) é a compatibilidade com versões anteriores ao do C predecessor B . Aqui está a citação de Dennis Ritchie:

[...} A solução constituiu o salto crucial na cadeia evolutiva entre o BCPL sem tipo e o tipo C. Ele eliminou a materialização do ponteiro no armazenamento e causou a criação do ponteiro quando o nome do array é mencionado em uma expressão. A regra, que sobrevive no C atual, é que os valores do tipo de matriz são convertidos, quando aparecem em expressões, em ponteiros para o primeiro dos objetos que compõem a matriz.

Esta invenção permitiu que a maioria dos códigos B existentes continuasse a funcionar, apesar da mudança subjacente na semântica da linguagem. [..]

Doc Brown
fonte
5
A struct Foo { int array[N]; } pode ser passado por valor. E a última parte sobre o tratamento de alocações dinâmicas e estáticas da mesma forma parece suspeito (uma matriz no sentido mais estrito sempre inclui um tamanho, os conceitos unificadores para coisas como indexação de matrizes são ponteiros associados à deterioração de matriz para ponteiro), você poderia elaborar?
@ delnan: Eu acho que os princípios gerais declarados aqui são sólidos. Claramente, se você agrupar sua matriz em uma estrutura, estará especificando sua intenção. No caso geral, você quase sempre passa por referência.
Robert Harvey
Também acho o comentário referenciado no OP desnecessariamente pedante. Claramente, você está passando um ponteiro em vez de uma matriz por valor. O que é igualmente verdade, porém, é que você está efetivamente passando uma matriz por referência. Se a objeção é que não há comprimento anexado, é fácil passar isso também.
Robert Harvey
@RobertHarvey Isso ainda é uma assimetria no sistema de tipos: tudo é passado por valor, exceto tipos de matriz (mesmo que as matrizes que fazem parte de um tipo de estrutura sejam passados ​​por valor), e ele ainda usa a mesma notação exata (ambas no site de chamada e na assinatura da função).
@ delnan: Por que isso é relevante, além de você precisar se lembrar?
Robert Harvey
9

Um minicomputador PDP com apenas 8 kB de memória não pode alocar uma pilha muito grande. Portanto, em uma máquina como essa, é preciso ter cuidado em um design de linguagem (ou evolução) para minimizar o que precisa ser colocado na pilha para o uso esperado de chamadas de sub-rotina comum. Atualmente, o C ainda é usado para programar sistemas embarcados com muita restrição de memória (alguns kB), portanto, o trade-off é geralmente bom.

Em uma arquitetura de processador que possui muito poucos registros, passar qualquer matriz por ponteiro, em vez de por valor, com mais frequência permite que um registro seja usado como uma otimização de chamada de sub-rotina.

hotpaw2
fonte
2
Eu tenho algumas placas que possuem 256 bytes de RAM para os dados e 2K EEPROM para o código. Você não deseja fazer uma cópia de uma matriz lá.
Jerry Jeremiah