Na 9ª edição do livro de Deitel C. Como programar (cap. 7), uma função é declarada como
void bubbleSort(int * const array, size_t size)
e no texto é especificado que " bubbleSort
o cabeçalho da função declara array
as int * const array
em vez de int array[]
to indicar que bubbleSort
recebe um argumento de array unidimensional. Novamente, essas notações são intercambiáveis; no entanto, a notação de array geralmente é preferida para legibilidade". Como "nomes de array são ponteiros constantes para o primeiro elemento do array" (citando o mesmo capítulo), e como um ponteiro constante para um dado não constante é definido (por exemplo) com int * const myPtr
, faz sentido que array
as int * const array
seja equivalente à notação de array mais compacta ao lidar com arrays.
Entretanto, no início do mesmo capítulo sobre ponteiros, os autores afirmam que "Quando o compilador encontra um parâmetro de função para uma matriz unidimensional da forma int b[]
, o compilador converte o parâmetro para a notação de ponteiro int *b
. As duas formas são intercambiáveis".
Então, de acordo com os autores, ambos int * const array
e int *array
são equivalentes a int array[]
. Por que adicionar a const
palavra-chave se eles são nomes de arrays e, portanto, por definição, ponteiros constantes para o primeiro elemento do array? Ou isso não é verdade quando arrays são passados para uma função?
Parcialmente.
void foo(int array[])
evoid foo(int *array)
significa exatamente a mesma coisaint * const array
é algo diferente:array
éconst
um ponteiro paraint
A posição das
const
questões:const int *array;
-array
é um ponteiro paraconst
int
int * const array;
-array
é umconst
ponteiro paraint
const int * const array;
-array
é umconst
ponteiro paraconst
int
Não, não são. Arrays decaem para ponteiros para seu primeiro elemento quando usados em expressões ou como parâmetros de função. Mas não
const
ponteirosConclusão:
faça o mesmo
Estes:
Não, pois o parâmetro tem um tipo diferente.
Isto é falso. Um array é frequentemente convertido em um ponteiro para seu primeiro elemento (mas nem sempre), e isso pode levar os alunos a pensar em um array como um ponteiro, mas não é. Existem diferenças importantes.
sizeof array
para um array esizeof p
para um ponteiro são coisas diferentes e não podem ser usados de forma intercambiável. Um array não é convertido em um ponteiro quando é o operando desizeof
, é o operando de um operador typeof, é o operando de unário&
ou é um literal de string usado para inicializar um array.Esta é uma declaração incorreta dos autores em dois aspectos. Primeiro, esta mudança de um parâmetro de array para um parâmetro de ponteiro é chamada de ajuste, não de conversão. Isto porque “conversões” em C se referem a operações em valores, mas esta é uma mudança no tipo de uma função, não uma conversão de valores. Segundo, o ajuste é realizado na representação interna da função do compilador. Não é um ajuste a notação usada no código-fonte. O compilador muda suas estruturas de dados internas para registrar que o parâmetro é um ponteiro. É improvável que um compilador realmente use a notação
int b[]
ouint *b
para registrar esta informação.Sua declaração “Como nomes de array são ponteiros constantes…” estava fora das aspas, então você não a atribuiu aos autores. O texto que você citou não disse que nomes de array são ponteiros constantes, e duvido que o livro diga isso em algum lugar. Se disser, você deve citar essa passagem.
O texto citado diz “essas notações são intercambiáveis”, mas isso é apenas no contexto de uma declaração de parâmetro de função, e significa que uma declaração de um array será ajustada para ser uma declaração de um parâmetro. Isso é diferente de dizer que um array é equivalente a um ponteiro constante.
Quando o ajuste de um parâmetro de array para um parâmetro de ponteiro é realizado,
const
não é adicionado. Dentro do corpo de uma função declarada comvoid foo(size_t size, int array[])
, o tipo dearray
éint *
, e pode ser alterado.array += 1
mudariaarray
para apontar para o próximo elemento no array, e isso é código C totalmente definido válido (desde quearray
não estivesse já apontando para o fim do array).Um parâmetro de array pode ser declarado
const
colocandoconst
dentro dos colchetes:int array[const]
. Então esta declaração de parâmetro será ajustada para declarar umconst
ponteiro paraint
.Tanto a formulação de Deitel quanto sua compreensão estão um pouco confusas.
Primeiro de tudo, vamos falar sobre o que
na verdade faz -- ele irá disparar um diagnóstico se você tentar escrever para
array
(alterando-o para apontar para outra coisa). Ele permite que você escrevaenquanto não permite
IOW, isso previne que você acidentalmente sobrecarregue seu
array
ponteiro no corpo da função. Fazer isso não afetará o array apontado, mas não será ideal para sua função funcionar corretamente.No entanto, não é equivalente a
que é "ajustado" para
não
A declaração de parâmetro equivalente usando notação de matriz seria na verdade
Os nomes de array não são ponteiros; quando você declara um array como
isto é o que você obtém na memória (os endereços são apenas para ilustração e não refletem nenhuma plataforma real):
Nenhum armazenamento é reservado para um valor de ponteiro;
arr
é o array. Na maioria das circunstâncias , o compilador avaliará a expressãoarr
como algo equivalente a&arr[0]
; as exceções a esta regra ocorrem quandosizeof
,typeof
,typeof_unequal
, ou unários ;&
Então se você tem uma matriz
e você escreve
o compilador gera código equivalente a