sábado, 9 de janeiro de 2010

Matrizes. Parte II (funções/alocação)

Continuando nossa série sobre matrizes, hoje vamos ver algumas operações básicas com matrizes.

Matrizes x Funções
Por serem intimamente relacionadas com os vetores, a operações entre matrizes e funções é praticamente idêntica, salvo o fato de termos uma (ou muitas) dimensão(ões) a mais.
Vamos ao código e você vai entender.


#include <stdio.h>
#include <stdlib.h>
 
const int LINHAS = 2;
const int COLUNAS = 2;
 
void preenche_mat_int(int [2][2]);
void exibe_mat_int(int [][2]);
 
int main(){
 int matriz[2][2];
 
 preenche_mat_int(matriz);
 exibe_mat_int(matriz);
 system("pause");
}
 
int ler_int(){
 int digitado;
 
 printf("Digite um valor inteiro: ");
 scanf("%d",&digitado);
 return digitado;
}
 
void mostra_int(int num){
 printf("%d ",num);
}
 
void preenche_mat_int(int mat[2][2]){
 int i, j;
 
 printf("\nPREENCHENDO A MATRIZ:\n");
 for(i = 0; i < LINHAS; i++)
    for(j = 0; j < COLUNAS; j++)
       mat[i][j] = ler_int();
}
 
void exibe_mat_int(int mat[][2]){
 int i, j;
 
 printf("\n");
 for(i = 0; i < LINHAS; i++){
    for(j = 0; j < COLUNAS; j++)
       mostra_int(mat[i][j]);
    printf("\n");
 }
 printf("\n\n");
}


O código acima tem bastante novidade!
A 1a delas é o uso de protótipos de função. Eu já deveria ter falado sobre eles, quando falei sobre funções (aqui), mas nunca é tarde (rsrs).

Faça sem saber como.
Em todos os códigos que vimos até agora usando funções, sempre criamos as funções antes de chamá-las na main. O código da nossa função main era sempre o último e, assim, as funções já eram 'conhecidas' dela.
No entanto é possível criar a main antes das outras funções. O único requisito é informar como essas funções serão chamadas, quais o seus retornos e parâmetros.
Esta é a função dos protótipos. Eles se parecem com o cabeçalho das funções, exceto que o nome dos parâmetros pode ser omitido.

A 2a novidade, que já aparece nos protótipos, é a forma de passar uma matriz para uma função. Deve ser informado o tipo de dados contido na matriz e o tamanho de suas dimensões. O tamanho da 1a dimensão pode ser omitido, somente da 1a. Se a matriz tiver 3 dimensões, por exemplo, o tamanho das 2a e 3a dimensões tem que ser informado.
A última é a forma de 'varrer' a matriz. Usamos um for para 'varrer' as linhas e, dentro dele, um outro for para 'varrer' todas as colunas desta linha antes de passar para a próxima. Por isso a necessidade de saber quantas linhas e colunas a matriz tem.
Como as dimensões da matriz já são conhecidas é uma ótima prática criar constantes globais que armazenem estes valores, o que facilita o acesso a elas em qualquer parte do programa.

Funções x Matrizes
Da mesma forma que um vetor pode ser alocado dinâmicamente, uma matriz também pode ser. Observe o código abaixo:


#include <stdio.h>
#include <stdlib.h>
 
int ler_int(){
 int digitado;
 
 printf("Digite um valor inteiro: ");
 scanf("%d",&digitado);
 return digitado;
}
 
void mostra_int(int num){
 printf("%d ",num);
}
 
int* preenche_mat_int(int linhas, int colunas){
 int *mat=0, i, j;
 
 if ((linhas * colunas) > 0)
    mat = (int *) malloc (linhas * colunas * sizeof(int));
 if (mat){
    printf("\nPREENCHENDO A MATRIZ:\n");
    for(i = 0; i < linhas; i++)
       for(j = 0; j < colunas; j++)
          *(mat + (i * colunas) + j) = ler_int();
 }
 else
    printf("NAO FOI POSSIVEL ALOCAR A MATRIZ!!!\n");
 return mat;
}
 
void exibe_mat_int(int* mat, int linhas, int colunas){
 int i, j;
 
 printf("\n");
 for(i = 0; i < linhas; i++){
    for(j = 0; j < colunas; j++)
       mostra_int(*(mat + (i * colunas) + j));
    printf("\n");
 }
 printf("\n\n");
}
 
int main(){
 int *matriz, linhas, colunas;
 
 printf("Digite o numero de linhas da matriz (maior que zero):\n");
 linhas = ler_int();
 printf("Digite o numero de colunas da matriz(maior que zero):\n");
 colunas = ler_int();
 matriz = preenche_mat_int(linhas, colunas);
 if(matriz){
    exibe_mat_int(matriz, linhas, colunas);
    free(matriz);
 }
 system("pause");
}


A diferença básica neste código é a permitir ao usuário que defina o número de linhas e colunas da matriz, por isto não pudemos armazenar estes valores em constantes globais (observe que tivemos que passar estes valores para todas as funções). Uma vez definidas, linhas e colunas, verificamos se os valores informados foram válidos e, alocamos espaço para a matriz.
Como o bloco de memória alocado não foi definido como uma matriz, ele não pode ser indexado como uma, usando os []. A solução para isso é o uso de ponteiros e da aritmética de ponteiros.
A linha 25 mostra como isto é feito. Observe a multiplicação de i, que contém o número da linha atual, pela quantidade de colunas. Dá pra entender o porquê, certo?

Por hoje é isto. Até o próximo post.

Nenhum comentário:

Postar um comentário