Ponteiros e vetores

Nas aulas práticas, já discutimos parcialmente a relação entre vetores (ou matrizes) e ponteiros. Observe o seguinte comando em C, que solicitará quatro espaços contíguos de memória, capazes de armazenar quatro valores do tipo inteiro.

int vet[] = {1,2,3,4};

Quando começou a trabalhar com vetores em AED1, você provavelmente tentou executar o seguinte comando:

printf("%d", vet);

A resposta, como já sabemos, não era uma impressão bonita do vetor declarado anteriormente.

A seguir, vamos entender como funciona a alocação de memória para estruturas de dados homogêneas (vetores e matrizes) e o porquê de a impressão direta do vetor em C não funcionar como desejamos.

📚 Alocação de vetores

Uma característica importante com relação ao uso de vetores em C consiste no fato de que, ao declararmos um vetor, precisamos declarar também quantos elementos ele armazenará. Isso é fruto da necessidade de alocação de memória (afinal, precisa-se garantir n espaços contíguos de memória para armazenar os elementos daquele vetor), mas também nos oferece uma vantagem.

Vamos acompanhar o comando a seguir:

int vet[4] = {1,2,3,4};

Por regras especiais da linguagem de programação C, a variável que representa um vetor será um ponteiro, que contém o endereço de memória da primeira posição do vetor. Logo, a variável vet contém o endereço de memória que armazena o valor 1, equivalente à vet[0].

Vejamos:

#include <stdio.h>
int main()
{
    int vet[] = {1,2,3,4};
    printf("vet[0] => %p\n", &vet[0]);
    printf("vet => %p\n", vet);
    return 0;
}
#include <stdio.h>
int main()
{
    int vet[] = {1,2,3,4};
    printf("vet[0] => %p\n", &vet[0]);
    printf("vet => %p\n", vet);
    printf("&vet => %p\n", &vet);
    return 0;
}

Acessando elementos com ponteiros

Se vet é um ponteiro que aponta para a primeira posição do vetor, essa variável também está suscetível à aritmética de ponteiros. Observe o comando a seguir, que visa a imprimir o valor das duas primeiras posições do vetor:

#include <stdio.h>
int main()
{
    int vet[] = {1,2,3,4};
    printf("vet[0] => %d\n", *vet); // imprime a primeira posição
    printf("vet[1] => %d\n", *(vet+1)); // imprime a segunda posição
    return 0;
}

Passando vetores para funções

Embora a abordagem a seguir não seja necessária, já que vetores são naturalmente passados por referência, podemos passar um vetor como parâmetro a uma função que recebe ponteiro:

#include <stdio.h>

void receberVetor(int *euSouUmPonteiro){ // recebendo um ponteiro
    printf("Primeiro elemento: %d\n", *euSouUmPonteiro);
    printf("Segundo elemento: %d\n", *(euSouUmPonteiro+1));
    /* ou, alternativamente, da forma tradicional: */
    printf("Terceiro elemento: %d\n", euSouUmPonteiro[2]);
    printf("Quarto elemento: %d\n", euSouUmPonteiro[3]);
}

int main()
{
    int vet[] = {90,27,14,31};
    receberVetor(vet); // passando o vetor, como antes
    return 0;
}

Vamos provar que o oposto também é verdade:

#include <stdio.h>

void receberVetor(int euSouUmVetor[]){ 
    printf("Primeiro elemento: %d\n", *euSouUmVetor); // acessando como ponteiro
    printf("Segundo elemento: %d\n", *(euSouUmVetor+1));
}

int main()
{
    int vet[] = {90,27,14,31};
    receberVetor(vet); // passando o vetor, como antes
    return 0;
}