Ponteiro em C: Arrays

funções X macros compilação condicional Diagnóstico

Continuando o assunto abordado no segundo artigo, sobre Aritmética de ponteiro, veremos algumas aplicações envolvendo aritmética de ponteiros e a sua relação com arrays. Em um dos exemplos mostrados no artigo anterior foi demonstrada a operação de incremento, evidenciando que ao incrementar um ponteiro, ele era deslocado para o próximo dado. Diante disso, veremos que há uma estreita relação entre ponteiros e arrays.

Ponteiros e Arrays

Arrays unidimensionais, ou vetores, são um conjunto de dados de mesmo tipo e que são armazenados em posições contíguas da memória [1]. Considere, por exemplo, um vetor de inteiros com 10 elementos armazenados a partir do endereço 108. No código abaixo é mostrado o exemplo ilustrado na Figura 1.

Um ponteiro é criado e passa a apontar para o primeiro elemento do vetor. Para atribuir o endereço de um vetor para um ponteiro basta utilizar o próprio nome do vetor, isto é, o nome representa o endereço do primeiro elemento.

Arrays: Memória
Figura 1: Representação de um ponteiro com o endereço base de um vetor.

Para obter o endereço de outro índice é necessário utilizar o operador ‘&’. Portanto, as duas atribuições mostradas abaixo são equivalentes.

Logo, o endereço do quinto elemento pode ser obtido da seguinte forma:

Essa situação é ilustrada na Figura 2.

Arrays: Memória
Figura 2: Ponteiro com o endereço do quinto elemento do vetor.

Diante disso, verifica-se que o elemento de um vetor é armazenado numa posição de memória na qual o seu endereço é equivalente à soma do endereço base com o total de bytes dos elementos até a posição desejada. Dito de outra maneira, se pt aponta para o endereço base do vetor então ‘V[n]’ é equivalente ‘*(pt + n)’. Na figura 3 é ilustrado essa alteração do endereço apontado.

Arrays: Memória
Figura 3: Modificação do endereço apontado.

Por exemplo, para exibir os 10 elementos desse vetor.

De fato, as duas formas de indexar os elementos do vetor apresentam o mesmo resultado, contudo a aritmética de ponteiros pode ser mais rápida do que a indexação direta, pois na indexação direta o endereço do elemento que será acessado é sempre calculado (somar o endereço base com a posição desejada) [1]. Uma pequena alteração no exemplo acima faz o ponteiro alterar o endereço conforme a iteração. 

Outro exemplo com aritmética de ponteiros é mostrado abaixo.

Neste exemplo, dois ponteiros são utilizados numa operação de atribuição. O código assembly gerado (AVR 8 bits) para este código é mostrado abaixo.  

Esse exemplo mostra como os modos de endereçamento podem ser explorados utilizando operações com ponteiros. Note que as duas instruções utilizadas possuem as operações de incremento e decremento. 

De modo geral:

  • *(pt + i) é igual a V[i].
  • (pt + i) é igual a &V[i].

Array de Ponteiros

Os ponteiros também podem ser declarados na forma de vetores. Considere o exemplo abaixo que define um vetor de ponteiros com 4 elementos e mais quatros vetores de 3 elementos.

Esse exemplo é ilustrado na Figura 4.

Arrays: Memória
Figura 4: Vetor de ponteiros do tipo inteiro.

Agora, é necessário lembrar que ao acessar os elementos pt[0], pt[1], pt[2] e pt[3], estaremos manipulando ponteiros. Para acessar os elementos de cada vetor a partir dos ponteiros basta utilizar o operador ‘*’ e indicar o índice desejado. Considere os casos abaixo:

  • *pt[0] é o valor 1, pois estamos acessando o conteúdo do endereço 116, ou seja, v1[0];
  • *pt[1] é o valor 4, pois estamos acessando o conteúdo do endereço 128, ou seja, v2[0];
  • *pt[2] é o valor  7, pois estamos acessando o conteúdo do endereço 140, ou seja, v3[0];
  • *pt[3] é o valor  10, pois estamos acessando o conteúdo do endereço 152, ou seja, v4[0].

Esse mesmo resultado pode ser obtido da seguinte forma:

  • *(*(pt+0)) é o valor  1;
  • *(*(pt+1)) é o valor 4;
  • *(*(pt+2)) é o valor 7;
  • *(*(pt+3)) é o valor 10.

A parte destacada em negrito define o elemento de ‘pt’ que está sendo acessado. Esse termo é o endereço do vetor que queremos acessar, portanto ao fazer o uso do operador * indicamos que o conteúdo desse endereço deve ser acessado. O acesso aos outros elementos é mostrado na Figura 5.

Arrays: Memória
Figura 5: Acessando elementos do vetor de inteiros a partir do vetor de ponteiros.

Conclusão

Nesse artigo foi demonstrado como acessar arrays utilizando ponteiros. Essa é uma técnica muito utilizada, pois é um meio mais rápido de acessar os elementos quando comparada com a indexação direta do vetor. Assim como no artigo anterior, destacou-se a importância do tipo de dado do ponteiro, já que as operações aritméticas realizadas dependem dessa informação. Outro caso demonstrado foi o de um array de ponteiros, caso semelhante ao de declaração de uma matriz de strings. Essas características podem aumentar a eficiência de rotinas e permitem estruturar melhor o código.

Referências

[1] – Livro: C, completo e total – 3ª edição revista e atualizada. Herbert Schildt.

[2] – AVR035: Efficient C coding for AVR

Fonte da imagem destacada: http://listamaze.com/top-10-programming-languages-for-job-security/

Outros artigos da série

<< Ponteiro em C: Aritmética de ponteiroPonteiro em C: Funções >>
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Software » Ponteiro em C: Arrays
Comentários:
Notificações
Notificar
guest
8 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Gustavo Massaneiro
Gustavo Massaneiro
01/03/2016 09:00

Muito bom! Uma dúvida Fernando: A partir do momento que eu incremento o ponteiro, ele passa a ter o valor do próximo endereço de memória do array, mais eu gostaria de saber se tem alguma maneira de ler o endereço base do ponteiro original após ele ter sido incrementado, ou a única maneira mesmo é guardando o endereço base do ponteiro em uma variável antes de incrementá-lo? Exemplo: unsigned long Time[DUMP_SIZE]; unsigned long Data[DUMP_SIZE]; //Pointers for Time and Data Arrays unsigned long * time_pt = Time; unsigned long * data_pt = Data; void SaveData() { //Calc variables static unsigned long… Leia mais »

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  Gustavo Massaneiro
01/03/2016 10:24

Olá, Gustavo. Neste caso, a operação de incremento sempre altera o conteúdo do ponteiro, pois o operador de incremento realiza a seguinte operação: data_pt++; –> data_pt = data_pt + 1; Assim, o endereço do ponteiro sempre é modificado. Portanto, o endereço base pode ser representado por uma constante ou por um ponteiro que não será modificado. No seu exemplo o ponteiro base_address é iniciado com: base_address = (long)&data_pt[0]; Que poderia ser trocado para &Data[0]. Esse endereço (&Data[0]) é constante, pois é o nome do vetor. Respondendo a sua pergunta, uma vez incrementado você modifica o endereço armazenado, logo perde a… Leia mais »

Gustavo Massaneiro
Gustavo Massaneiro
Reply to  Fernando Deluno Garcia
04/03/2016 09:12

Muito Obrigado Fernando, vou atualizar o código e usar o &Data[0] que é constante.

Vinicius Maciel
vinifr
17/01/2016 20:27

Ola,

Preciso colocar esse código para funcionar: http://pastebin.com/zDM0Zxmi … Ele é parte de um software maior, mas a lógica é a mesma. Está dando falha de segmentação na linha 12, no printf(). Antes quebrava na atribuição da linha 10, mas dessa forma passa: matrix = (int**)ptr; … Alguém tem uma ideia?

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  vinifr
18/01/2016 13:15

Olá, vinifr. Você declarou matrix como um ponteiro para ponteiro. Na atribuição de matrix você não passou o endereço de um ponteiro….você atribui o endereço do vetor. No primeiro artigo tem uma demonstração de indireção dupla. int main() { char buf[10] = {‘0′,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9’}; char *ptr; int **matrix; ptr = buf; //conteúdo de ptr é o endereço de buf matrix = (int**)&ptr; //conteúdo de matrix é o endereço do ponteiro ptr printf(“%c %cn”, matrix[0][0], matrix[0][1]); return 0; } Cabe ressaltar que ao declarar como int, o vetor será acessado como inteiro e não char. Alterando matrix para char o acesso fica… Leia mais »

Vinicius Maciel
vinifr
Reply to  Fernando Deluno Garcia
18/01/2016 13:53

Ola Fernando,

Muito obrigado pela ajuda, realmente dá certo como você disse. Interessante, realmente usando int ele imprime “0 4” e não “0 1”. 😀

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  vinifr
18/01/2016 16:44

É que usando o ponteiro do tipo int o acesso a memória é realizado com base no tamanho desse tipo de dado. Neste caso, utilizando ponteiro char somente um byte é manipulado, já no ponteiro int são 4 bytes. Ponteiro char: matrix[0][0] -> endereço base matrix[0][1] -> endereço base + 1 Ponteiro int: matrix[0][0] -> endereço base matrix[0][1] -> endereço base + 4 / que é o valor 4 O problema é que ao fazer a operação como int você manipula os quatro bytes. No printf você leu o índice [0] mas na verdade leu o valor ‘0123’ e depois… Leia mais »

Vinicius Maciel
vinifr
Reply to  Fernando Deluno Garcia
19/01/2016 14:09

Ah, muito interessante! Obrigado pela explicação!

Talvez você goste:

Séries



Outros da Série

Menu

WEBINAR
 

BlueNRG-LP – Bluetooth 5.2 de longo alcance para aplicações industriais

Data: 05/11 às 15:00h - Apoio: STMicroelectronics
 
INSCREVA-SE AGORA »



 
close-link