[Curso de AeED - Aula 03] - Vetores e Matrizes


Nesta aula iremos entender como funcionam as estruturas básicas de alocação de memória estática que são os vetores. Ao final desta aula você será capaz de entender:
·                    O que são vetores;
·                    Como os vetores são usados;
·                    Como os vetores se comportam na memória dos computadores;
·                    O que são matrizes;
·                    Como representar matrizes;


1.    Vetores

A forma mais simples de estruturarmos um conjunto de dados é por meio de vetores. Como a maioria das linguagens de programação, C permite a definição de vetores.

int v[10];

A declaração acima diz que v é um vetor de inteiros dimensionado com 10 elementos, isto é, reservamos um espaço de memória contínuo para armazenar 10 valores inteiros. Assim, se cada int ocupa 4 bytes, a declaração acima reserva um espaço de memória de 40 bytes, como ilustra a figura abaixo.
144
140
136
132
128
124
120
116
112
108
104

O acesso a cada elemento do vetor é feito através de uma indexação da variável v. Observamos que, em C, a indexação de um vetor varia de zero a n-1, onde n representa a dimensão do vetor. Assim:

v[0] → acessa o primeiro elemento de v
v[1] → acessa o segundo elemento de v
...
v[9] → acessa o último elemento de v

Mas:

v[10] → está ERRADO (invasão de memória)

A linguagem C também suporta aritmética de ponteiros. Podemos somar e subtrair ponteiros, desde que o valor do ponteiro resultante aponte para dentro da área reservada para o vetor. Se p representa um ponteiro para um inteiro, p+1 representa um ponteiro para o próximo inteiro armazenado na memória, isto é, o valor de p é incrementado de 4 (mais uma vez assumindo que um inteiro tem 4 bytes). Com isto, num vetor temos as seguintes equivalências:

v+0 → aponta para o primeiro elemento do vetor
v+1 → aponta para o segundo elemento do vetor
v+2 → aponta para o terceiro elemento do vetor
...
v+9 → aponta para o último elemento do vetor

Portanto, escrever &v[i] é equivalente a escrever (v+i). De maneira análoga, escrever v[i] é equivalente a escrever *(v+i) (é lógico que a forma indexada é mais clara e adequada). Devemos notar que o uso da aritmética de ponteiros aqui é perfeitamente válido, pois os elementos dos vetores são armazenados de forma contínua na memória.

Os vetores também podem ser inicializados na declaração:

int v[5] = { 5, 10, 15, 20, 25 };
ou simplesmente:

int v[] = { 5, 10, 15, 20, 25 };

Neste último caso, a linguagem dimensiona o vetor pelo número de elementos inicializados.

Poderíamos definir os vetores como:
Os vetores são espaços de memória que são alocados para armazenar um conjunto de dados que posteriormente pode ser acessado através de seu índice.

No entanto esta é uma abstração criada para melhorar a compreensão do programador da utilidade desta ferramenta. Os vetores são na verdade ponteiros de espaços de memória que são alocados e podem ser acessados posteriormente realizando operações de desreferenciação.

Passagem de vetores para funções

Passar um vetor para uma função consiste em passar o endereço da primeira posição do vetor. Se passarmos um valor de endereço, a função chamada deve ter um parâmetro do tipo ponteiro para armazenar este valor. Assim, se passarmos para uma função um vetor de int, devemos ter um parâmetro do tipo int*, capaz de armazenar endereços de inteiros. Salientamos que a expressão “passar um vetor para uma função” deve ser interpretada como “passar o endereço inicial do vetor”. Os elementos do vetor não são copiados para a função, o argumento copiado é apenas o endereço do primeiro elemento.

Acompanhe o exemplo:

#include <stdio.h>
#include <stdlib.h>

void imprimir_vetor ( int n , int *v ) {
    int i;
    for (i = 0; i < n ; i++)
         printf("|%d|", v[i]);
    printf("\n\n\n");
}

void imprimir_matriz ( int n , int m[][3] ) {
    int i,j;
    for (i = 0; i < n; i++){
        for (j = 0; j < n; j++){
            printf("|%d|", m[i][j]);
        }
        printf("\n");
    }
    printf("\n\n\n");

}

int main(){
    int v1[5] = { 5, 10, 15, 20, 25 };
    int v2[] = { 5, 10, 15, 20, 25 };
    int m1[4][3] =  {{5,10,15},
                    {20,25,30},
                    {35,40,45},
                    {50,55,60}};
    int m2[4][3] = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
    int m3[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};

    imprimir_vetor(5, v1);
    imprimir_vetor(5, v2);

    imprimir_matriz(4, m1);
    imprimir_matriz(4, m2);
    imprimir_matriz(4, m3);

    system("pause");

}

A saída do programa é 2 4 6, pois os elementos do vetor serão incrementados dentro da função.

2 – Matrizes

Já discutimos em capítulos anteriores a construção de conjuntos unidimensionais através do uso de vetores. A linguagem C também permite a construção de conjuntos bi ou multidimensionais. Matrizes representadas por conjuntos bidimensionais de valores numéricos. As construções apresentadas aqui podem ser estendidas para conjuntos de dimensões maiores.

A linguagem C permite a criação de vetores bidimensionais, declarados estaticamente. Por exemplo, para declararmos uma matriz de valores reais com 4 linhas e 3 colunas, fazemos:

float mat[4][3];

Esta declaração reserva um espaço de memória necessário para armazenar os 12 elementos da matriz, que são armazenados de maneira contínua, organizados linha a linha.

60.0
55.0
50.0
45.0
40.0
35.0
30.0
25.0
20.0
15.0
10.0
5.0












float m[4][3] = {{5.0,10.0,15.0},
      {20.0,25.0,30.0},
      {35.0,40.0,45.0},
      {50.0,55.0,60.0}};

Os elementos da matriz são acessados com indexação dupla: mat[i][j]. O primeiro índice, i, acessa a linha e o segundo, j, acessa a coluna. Como em C a indexação começa em zero, o elemento da primeira linha e primeira coluna é acessado por mat[0][0]. Após a declaração estática de uma matriz, a variável que representa a matriz, mat no exemplo acima, representa um ponteiro para o primeiro “vetor-linha”, composto por 3 elementos. Com isto, mat[1] aponta para o primeiro elemento do segundo “vetor-linha”, e assim por diante.

 As matrizes também podem ser inicializadas na declaração:

float mat[4][3] = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}};

Ou podemos inicializar sequencialmente:

float mat[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};

O número de elementos por linha pode ser omitido numa inicialização, mas o número de colunas deve, obrigatoriamente, ser fornecido:

float mat[][3] = {1,2,3,4,5,6,7,8,9,10,11,12};


Passando matrizes por funções

Conforme dissemos acima, uma matriz criada estaticamente é representada por um ponteiro para um “vetor-linha” com o número de elementos da linha. Quando passamos uma matriz para uma função, o parâmetro da função deve ser deste tipo. Infelizmente, a sintaxe para representar este tipo é obscura. O protótipo de uma função que recebe a matriz declarada acima seria:

void f (..., float (*mat)[3], ...);

Uma segunda opção é declarar o parâmetro como matriz, podendo omitir o número de linhas:

void f (..., float mat[][3], ...);

De qualquer forma, o acesso aos elementos da matriz dentro da função é feito da forma usual, com indexação dupla. Na próxima seção, examinaremos formas de trabalhar com matrizes alocadas dinamicamente. No entanto, vale salientar que recomendamos, sempre que possível, o uso de matrizes alocadas estaticamente. Em diversas aplicações, as matrizes têm dimensões fixas e não justificam a criação de estratégias para trabalhar com alocação dinâmica. Em aplicações da área de Computação Gráfica, por exemplo, é comum trabalharmos com matrizes de 4 por 4 para representar transformações geométricas e projeções. Nestes casos, é muito mais simples definirmos as matrizes estaticamente (float mat[4][4];), uma vez que sabemos de antemão as dimensões a serem usadas. Nestes casos, vale a pena definirmos um tipo próprio, pois nos livramos das construções sintáticas confusas explicitadas acima. Por exemplo, podemos definir o tipo Matrix4.

typedef float Matrix4[4][4];

Com esta definição podemos declarar variáveis e parâmetros deste tipo:
Matrix4 m;  
void f (..., Matrix4 m, ...);

Referências

CELES, Waldemar e RANGEL, Lucas; Apostila de estrutura de dados; 2002; Pontifícia Universidade Católica; Rio de Janeiro; 2002.



[Curso de AeED - Aula 03] - Vetores e Matrizes [Curso de AeED - Aula 03] - Vetores e Matrizes Reviewed by Vinicius dos Santos on 08:44:00 Rating: 5

Nenhum comentário

Escreve ai sua opinião!