Ponteiro em C: Arrays

funções X macros compilação condicional Diagnóstico
Este post faz parte da série Ponteiro em C

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.

int v[] = {5, 10, 15, 3, 10, 76, 5, 13, 33, 45};
int * pt;

pt = v; //atribui o endereço do vetor

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.

pt = v;
pt = &v[0];

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

pt = &v[4];

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.

int v[] = {5, 10, 15, 3, 10, 76, 5, 13, 33, 45};
int * pt;
int i;

pt = v;

for(i = 0; i < 10; i++)
{
   printf("V[%i] = %i\r\n", i, *(pt + i));
}

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. 

int v[] = {5, 10, 15, 3, 10, 76, 5, 13, 33, 45};
int * pt;
int i;

pt = v;

for(i = 0; i < 10; i++)
{
   printf("V[%i] = %i\r\n", i, *pt++);
}

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

char *pointer1 = &table[0];
char *pointer2 = &table[49];

*pointer1++ = *--pointer2;

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.  

LD R16,-Z ; Pre-decrement Z pointer and load data
ST X+,R16 ; Store data and post increment

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.

int * pt [4]; //vetor de ponteiros do tipo inteiro
int v1[3] = {1, 2, 3}; //vetor 1 com três elementos
int v2[3] = {4, 5, 6}; //vetor 2 com três elementos
int v3[3] = {7, 8, 9}; //vetor 3 com três elementos
int v4[3] = {10, 11, 12}; //vetor 4 com três elementos

pt[0] = v1; //atribui o endereço do vetor1 para o ponteiro pt[0]
pt[1] = v2; //atribui o endereço do vetor2 para o ponteiro pt[1]
pt[2] = v3; //atribui o endereço do vetor3 para o ponteiro pt[2]
pt[3] = v4; //atribui o endereço do vetor4 para o ponteiro pt[3]

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: https://listamaze.com/top-10-programming-languages-for-job-security/

Ponteiro em C

Ponteiro em C: Aritmética de ponteiro Ponteiro em C: Funções
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
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.

vinifr
vinifr
17/01/2016 20:27

Ola,

Preciso colocar esse código para funcionar: https://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 »

vinifr
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 »

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

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

Home » Software » Linguagem C » Ponteiro em C: Arrays

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: