O que você está dizendo em sua postagem está absolutamente correto. Eu diria que todo desenvolvedor C chega exatamente à mesma descoberta e exatamente à mesma conclusão quando (se) eles alcançam certo nível de proficiência com a linguagem C.
Quando as especificações de sua área de aplicativo exigem um array de tamanho fixo específico (o tamanho do array é uma constante de tempo de compilação), a única maneira adequada de passar esse array para uma função é usando um parâmetro de ponteiro para array
void foo(char (*p)[10]);
(na linguagem C ++ isso também é feito com referências
void foo(char (&p)[10]);
)
Isso habilitará a verificação de tipo no nível do idioma, o que garantirá que o array de tamanho correto seja fornecido como argumento. Na verdade, em muitos casos as pessoas usam essa técnica implicitamente, sem nem perceber, escondendo o tipo de array atrás de um nome de typedef
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
Além disso, observe que o código acima é invariável em relação ao Vector3d
tipo que é uma matriz ou a struct
. Você pode mudar a definição de Vector3d
a qualquer momento de uma matriz para umastruct
e vice-versa, e não será necessário alterar a declaração da função. Em qualquer um dos casos, as funções receberão um objeto agregado "por referência" (há exceções a isso, mas no contexto desta discussão isso é verdadeiro).
No entanto, você não verá esse método de passagem de array usado explicitamente com muita frequência, simplesmente porque muitas pessoas se confundem com uma sintaxe um tanto complicada e simplesmente não se sentem confortáveis o suficiente com tais recursos da linguagem C para usá-los apropriadamente. Por esse motivo, na vida real média, passar um array como um ponteiro para seu primeiro elemento é uma abordagem mais popular. Parece apenas "mais simples".
Mas, na realidade, usar o ponteiro para o primeiro elemento para a passagem de array é uma técnica de nicho, um truque, que serve a um propósito muito específico: seu único propósito é facilitar a passagem de arrays de tamanhos diferentes (ou seja, tamanho de tempo de execução) . Se você realmente precisa ser capaz de processar arrays de tamanho de tempo de execução, então a maneira adequada de passar tal array é por um ponteiro para seu primeiro elemento com o tamanho concreto fornecido por um parâmetro adicional
void foo(char p[], unsigned plen);
Na verdade, em muitos casos, é muito útil poder processar matrizes de tamanho de tempo de execução, o que também contribui para a popularidade do método. Muitos desenvolvedores C simplesmente nunca encontram (ou nunca reconhecem) a necessidade de processar um array de tamanho fixo, permanecendo assim alheios à técnica de tamanho fixo adequada.
No entanto, se o tamanho do array for fixo, passando-o como um ponteiro para um elemento
void foo(char p[])
é um grande erro no nível da técnica, que infelizmente é bastante comum nos dias de hoje. Uma técnica de ponteiro para array é uma abordagem muito melhor nesses casos.
Outro motivo que pode impedir a adoção da técnica de passagem de matriz de tamanho fixo é o domínio da abordagem ingênua para a digitação de matrizes alocadas dinamicamente. Por exemplo, se o programa chama matrizes fixas do tipo char[10]
(como em seu exemplo), um desenvolvedor médio usará malloc
matrizes como
char *p = malloc(10 * sizeof *p);
Esta matriz não pode ser passada para uma função declarada como
void foo(char (*p)[10]);
o que confunde o desenvolvedor médio e o faz abandonar a declaração do parâmetro de tamanho fixo sem pensar mais nisso. Na realidade, porém, a raiz do problema está na malloc
abordagem ingênua . O malloc
formato mostrado acima deve ser reservado para matrizes de tamanho de tempo de execução. Se o tipo de array tiver tamanho em tempo de compilação, uma maneira melhor de malloc
fazê - lo seria a seguinte
char (*p)[10] = malloc(sizeof *p);
Isso, é claro, pode ser facilmente passado para o acima declarado foo
foo(p);
e o compilador executará a verificação de tipo apropriada. Mas, novamente, isso é muito confuso para um desenvolvedor C despreparado, e é por isso que você não verá isso com muita frequência no código "típico" do dia a dia.
10
pode ser substituída por qualquer variável no escopo