paulo1205
(usa Ubuntu)
Enviado em 13/02/2022 - 19:26h
ApprenticeX escreveu:
Obrigado Paulo pela resposta.
O que eu estou tentando entender é justamente isso. As 4 declarações acima são semelhantes e produzem o mesmo resultado!
Vamos ver se entendi elas separadamente!
char aac[10][25]={};
char *apc[10];
char (*pac)[25];
char **ppc;
Entendo como uma lista de 10 linhas, onde cada linha possue 25 characteres. OK
char aac[10][25]={};
Cuidado com a terminologia! Evite usar “lista” para se referir a um
array (ou vetor), pois lista é um outro tipo de estrutura de dado.
Também “linha” não é muito próprio. No contexto do C e sua biblioteca padrão, esse conceito está mais ligado a entrada e saída de dados em modo texto (não-binário), e um
array com 25 elementos pode conter mais de uma linha de texto, ou mesmo não conter uma linha completa (e pode nem mesmo conter uma
string ).
O correto para a declaração acima é dizer que ela declara um
array com dez elementos, no qual cada elemento é um
array com vinte e cinco elementos do tipo
char .
O tipo, portanto, do identificador
aac é “
array com
10 elementos do tipo
array com
25 elementos do tipo
char ”. Isso implica que o tipo de cada elemento desse
array , designados por
aac[0] ,
aac[1] , …,
aac[9] é “
array com
25 elementos do tipo
char ”. Por conseguinte, para cada
array na forma
aac[n] (com
0 <=
n e
n <
10 ), cada uma das expressões
aac[n][0] ,
aac[n][1] , …,
aac[n][24] designam um único elemento do tipo
char .
Entendo como um ponteiro para uma lista com 10 linhas. E por ser ponteiro posso colocar qts characteres eu quiser em cada linha visto que será alocado qdo eu colocar.
char *apc[10];
Errado. Isso é um
array com dez elementos, no qual cada elemento é um ponteiro para caráter. No C, tanto no momento da declaração quanto também na hora de usar em expressões, os colchetes têm prioridade mais alta do que o asterisco. Por isso é que isso designa um
array de ponteiros.
E você não pode “colocar caracteres”, muito menos “quantos [você] quiser”, só por ser ponteiro. O que você pode fazer é com que cada ponteiro que é elemento do
array aponte para uma área de dados com uma quantidade de espaço devidamente alocado. No exemplo que eu construí na mensagem anterior, eu usei alocação dinâmica de memória para preencher o valor de endereço de cada um dos dez ponteiros que são elementos do
array apc (
apc[0] até
apc[9] ), e em cada uma dessas alocações (feitas com a função
calloc () dentro de um laço de repetição) eu pedi espaço para vinte e cinco caracteres.
Assim, por construção, eu consegui produzir um cenário no qual
apc ,
apc[m] e
apc[m][n] têm comportamentos análogos aos de
aac ,
aac[m] e
aac[m][n] .
Acho que entendi que é um ponteiro para um simples array de 25 characteres, e entendi que por estar entre parênteses o transforma em uma lista onde no momento de sua declaração não possue nenhuma linha!
char (*pac)[25];
De novo, você inverteu o que está dito. Como eu coloquei parênteses em volta da expressão contendo o asterisco, esta passou a ter prioridade maior do que os colchetes. Isso implica que agora temos em
pac um ponteiro para (um ou mais) dado(s) cujo tipo é “
array com vinte e cinco elementos do tipo
char ”.
Esse “um ou mais” é porque o C considera que o mesmo ponteiro pode ser usado para apontar para um bloco de elementos contíguos do mesmo tipo. Com isso, quando você aplica um deslocamento na forma de um valor inteiro ao endereço base do ponteiro, ele pode apontar para diferentes elementos dentro desse bloco de dados contíguos, de modo inteiramente análogo à aplicação de um índice inteiro sobre um
array — tão análogo, na verdade, que usa inclusive a mesma sintaxe: “
array[desloc] ” ou “
ponteiro[desloc] ”.
No exemplo da postagem anterior, eu faço uma única chamada a
calloc () para
pac , justamente para alocar espaço suficiente para dez ponteiros (o tipo de cada ponteiro é inferido pelo compilador quando eu uso a expressão “
sizeof *pac ”).
Então, por construção, eu consegui novamente produzir um comportamento análogo para
pac ,
pac[m] e
pac[m][n] aos de
aac ,
aac[m] e
aac[m][n] .
Aqui o que pude entender é que isso é equivalente a isso: char *ppc[] = {*Text, *Text, *Text};
Continuo sem entender o que você quis dizer com esse “
*Text, *Text, *Text ”.
Ou seria: char *ppc[*]
Também não.
ppc (que é uma abreviação de “ponteiro para ponteiro para
char ”, assim como
aac abrevia “
array de
array de
char ”,
apc abrevia “
array de ponteiros para
char ” e
pac abrevia “ponteiro para
array de
char ”).
Essa tentativa (inválida!) de declaração que você colocou acima faz pensar que você gostaria de um
array com tamanho flexível de ponteiros para
char . A sintaxe do C obviamente não permite isso, mas acaba que, POR CONSTRUÇÃO (com o perdão da ênfase repetitiva), é esse efeito que nós conseguimos para
ppc no meu exemplo da postagem anterior.
(Se bem que, dadas as inversões de compreensão dos dois casos anteriores, pode ser que você tenha imaginado outra coisa; temo que, em vez de um suposto
array com tamanho flexível de ponteiros para
char , você tenha imaginado algo ainda mais exótico, tal como um ponteiro para
arrays com tamanhos flexíveis.)
char **ppc;
Eu não consegui entender graficamente a equivalência dele com um array.
De novo, eu vou usar a expressão “POR CONSTRUÇÃO” (com perdão para a ênfase em maiúsculas, mas é preciso que fique claro) para explicar que após alocar o espaço para dez ponteiros e atribuir esse espaço a
ppc e após atribuir a cada um desses ponteiros um espaço dinamicamente alocado para conter vinte e cinco caracteres, podemos usar
ppc ,
ppc[m] e
ppc[m][n] de maneiras análogas a como usamos
aac ,
aac[m] e
aac[m][n] , respectivamente.
Explicando de uma outra forma: No programa que foi criado, no meu jeito de ver temos o seguinte:
• Uma lista com textos
• Essa lista pode ser aumentada em qtd linhas ou em qtd de characteres em cada linha
Essa sua terminologia confunde. insisto para que você não use “lista” ou “
list ” para referir-se a um vetor, nem “texto” ou “text” para referir-se a
strings ou a vetores de caracteres. Mude isso inclusive nos seus programas, para não criar nem arraigar esse mau hábito.
Então minha lista acima é equivalente à: (Onde posso ter várias linhas com textos)
char List[];
char *List[];
Você não pode ter as duas declarações ao mesmo tempo.
Além disso, nenhuma das duas declarações é válida em C fora do contexto de lista de parâmetros de uma função (que não é o caso, então são inválidas mesmo!).
Fora do contexto de lista de parâmetros, declarações de
arrays são obrigadas enquadrar-se em pelo menos uma das duas situações: (1) o número de elementos tem de estar expresso entre os colchetes, ou (2) deve haver uma lista de inicialização dos elementos acompanhando a declaração do
array .
No contexto de parâmetros de funções, os colchetes vazios não indicam
arrays , mas sim ponteiros. Assim sendo, um parâmetro de função declarado com colchetes (vazios ou não!) na forma “
char param[] ” é totalmente sinônimo de “
char *param ”. De modo semelhante, nesse mesmo contexto, algo na forma “
char *param[123] ” é sinônimo de “
char **param ”.
Qual a equivalência mais próxima para isso:
char **ppc;
char *ppc[] = {*Text, *Text, *Text}; // Ponteiro para array de ponteiro
char *ppc[] = {Text, Text, Text}; // Ponteiro de array simples
char ppc[] = {*Text, *Text, *Text}; // Array simples para ponteiros
char ppc[] = {Text, Text, Text}; // Simples array de strings (array de characteres)
Nenhuma das últimas quatro linhas é sintaticamente válida, e os comentários não têm relação com os tipos que poderiam ser conseguidos com uma sintaxe que fosse válida. Então fica difícil saber o que você quis dizer.
Mais acima, eu tentei desfazer o mal entendido, tentando detalhar cada construção. Espero que aquilo tenha ficado claro. Não se prenda ao seu entendimento anterior, mas procure entender o que eu expliquei novamente nesta postagem.
Tipo, até o momento só consigo entender graficamente os seguintes ponteiros
char *Text; // Ponteiro para um array de characteres ou para uma simples string
Não! A declaração acima indica um ponteiro para caráter (que pode sem um único caráter ou o primeiro caráter de um bloco de vários caracteres em posições adjacentes na memória).
Se for um ponteiro para bloco, esse fato permite que o ponteiro seja usado de modo
análogo à forma de se usar um
array . Como
arrays são usados para armazenar
strings , pode-se dizer que um ponteiro que se refira a esse bloco (apontando para seu primeiro elemento) se refere a uma
string .
Mas note o verbo que eu usei: “referir-se”. A qualificação de que o objeto apontado designa um
array ou uma
string é uma informação que não aparece sintaticamente no programa nem altera o tipo do dado. O tipo do identificador
Text continua sendo ponteiro para caráter, não ponteiro para
array de caracteres, pois isso teria uma sintaxe bem diferente, como já foi mostrado acima e em postagens anteriores.
char *List[]; // Ponteiro para uma lista de array de characteres ou Ponteiro para uma Lista de Strings
De novo, essa sintaxe não é válida, e o comentário está errado (e com a terminologia ruim, já apontada). Onde algo parecido poderia ser usado seria na lista de parâmetros de função, e o sentido seria que o tipo do parâmetro seria ponteiro para ponteiro para caracteres.
... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)