Linguagem C: Matrizes, parte 1

A união faz a força

e as matrizes.

Quando utilizamos vetores, não existe muita confusão. É uma linha com N espaços para determinados valores. Claro, podemos perder uns bons minutos pensando em algoritmos eficazes para ordenação, busca e outros.

vetor

Mas e quando jogamos um vetor em cima do outro, colamos e dizemos que é uma coisa só?

matriz

Ai meu amigo, ai você começa a ter dores de cabeça gratuítas. A iteração passa a precisar de 2 loops em cascata (no mínimo), nas funções você precisa declarar pelo menos o número de colunas que vai utilizar:

No item 5.8, foi visto que, ao passar matrizes para uma função, não será necessário especificar o número de elementos na matriz. Em matrizes bidimensionais, não será necessário especificar o número de linha na matriz, mas, sim, especificar o número de colunas.
Fonte. Item 6.16

Além de receber um warning quando o valor da função não coincide com o que você está passando.

fig1

São Tomé? Clica pra ver.

E o Dev é meio de lua para esses warnings. As vezes somem, as vezes ficam.

Declarando e programando

A estrutura básica de uma matriz bidimensional é matriz[i][j], sendo i o número de linhas e j o número de colunas. A estrutura de uma matriz “A”, 3×2:

matriz3x2

3 linhas, 2 colunas. A primeira posição é A11 (1 linha, 1 coluna), a segunda A12 (1 linha, 2 coluna) e assim por diante.

Em C temos algo assim:

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

int main(int argc, char *argv[])
{
//tipo nome[linhas][colunas];
int a[3][2];
int b[2][2] = {{1,2},{3,4}};

system("PAUSE");
return 0;
}

No meu caso, é uma matriz de inteiros. A inicialização sempre é opcional, mas importante. Se uma variável não é zerada, corre o risco de pegar algum lixo da memória e ficar valendo, por exemplo, 19820.

Inicialização

“Na mão”, in code, você abre e fecha chaves. Dentro dessas, colocará mais um conjunto para cada linha. Esse conjunto pode ter, no máximo, o número de colunas em elementos.

int foo[i][j] = {{1,2,3, .. j}, .. i{}};

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

Às vezes é prático. Às vezes não. Para preencher com valores do usuário, precisamos iterar pelas linhas e colunas da matriz, mais difícil, porém mais interessante e utilizado.

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

int main(int argc, char *argv[])
{
  //tipo nome[linhas][colunas];
  int a[3][2];
  int b[2][2] = {{1,2},{3,4}};

  int i,j;

  //estou na linha 0... (i=0), indo até 2 (i < 3)
  for(i=0;i<3;i++)
  {
    //vou, da coluna 0 até j-1 pedindo valores
    for(j=0;j<2;j++)
    {
      printf("Matriz[%d][%d]: ",i,j);
      scanf("%d",&a[i][j]);
    }
  }

  system("PAUSE");
  return 0;
}

Importante: Veja que nos loops sempre usamos o operador lógico menor. É que a matriz não vai de 1 a 3, mas sim de 0 a 2. Sempre de 0 até n – 1 (como nos vetores).

A minha técnica preferida é fixar a linha e iterar pelas colunas, mas você pode fixar a coluna e preencher suas linhas, não é crime. A jogada para isso é deixar o laço das colunas em primeiro lugar.

O algoritmo funciona assim (fixando nas linhas):

“Estou na linha 0. Vou, da coluna 0 até a coluna 4, pedindo valores.”
As colunas acabam e volta no cabeçalho do primeiro laço…
“Estou na linha 1. Vou, da coluna 0 até a coluna 4, pedindo valores.”

“Estou na linha i-1. Vou, da coluna 0 até a coluna j-1, pedindo valores.”

Nas colunas é o contrário:

“Estou na coluna 0. Vou, da linha 0 até a linha 2, pedindo valores.”

Passando para função

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

void preencher(int m[][5],int linhas, int colunas);

int main(int argc, char *argv[])
{
  int a[20][20];

  preencher(a,5,2);

  system("PAUSE");
  return 0;
}

void preencher(int m[][5], int linhas, int colunas)
{
  int i, j;

  for(i=0;i<linhas;i++)
  {
      for(j=0;j<colunas;j++)
      {
        printf("matriz[%d][%d]: ",i,j);
        scanf("%d",&m[i][j]);
      }
  }
}

Repare que meu a é de 20 por 20. Por alguma razão que não entendo, o dev insiste em dar falha quando utilizo 3 linhas e duas colunas, 5 linhas e duas colunas e outros valores “aleatórios”. Então resolvi usar o conselho de minha professora em suas super aulas de c:

“Coloca mais do que vai precisar que evita qualquer tipo de erro.”

Já que não vai arrancar um braço (só um fígado), fica a gambiarra ai.

A função é void, pois não retorna nada. Precisamos apenas passar a matriz, o numero de linhas e colunas.

“Ei, mas se não tem retorno, como os dados ficam na matriz?”

Quando você passa uma matriz, está passando o seu endereço de memória, na verdade. O “a” ali nunca chega a função, o que chega é um número maluco como 2292016, ou algo assim. A função “mascara” esse numero com o “m”, mas estamos atribuindo os valores para 2292016.

São Tomé?! Adoro seus discípulos! (especialmente porque sou um deles)

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

void saoTome(int m[][10]);

int main(int argc, char *argv[])
{
  int a[20][20];

  //preencher(a,3,2);

  printf("Endereco de a:          %d\n",a);
  saoTome(a);

  system("PAUSE");
  return 0;
}

void saoTome(int m[][10])
{
  printf("Endereco de m:          %d\n",&m);
  printf("Endereco que m recebeu: %d\n",m);
}

Claro, você pode fazer a função devolvendo int, dando return em m para a, por consequencia ela pegaria o endereço de memória de m e os valores passariam normalmente, mas para que complicar?

Exibindo os valores

Criamos, preenchemos, agora é exibicionismo. Digo, exibição.

A lógica é a mesma: Fixo numa linha, mostro suas colunas, mudo de linha, mostro suas colunas, até o fim. Vou mostrar direto na função.

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

void preencher(int m[][10],int linhas, int colunas);
void saoTome(int m[][10]);
void mostrar(int m[][10],int linhas, int colunas);

int main(int argc, char *argv[])
{
  int a[20][20];

  preencher(a,3,2);

  printf("\n\n");

  mostrar(a,3,2);

  system("PAUSE");
  return 0;
}

void saoTome(int m[][10])
{
  printf("Endereco de m:          %d\n",&m);
  printf("Endereco que m recebeu: %d\n",m);
}

void preencher(int m[][10], int linhas, int colunas)
{
  int i, j;

  for(i=0;i<linhas;i++)
  {
      for(j=0;j<colunas;j++)
      {
        printf("matriz[%d][%d]: ",i,j);
        scanf("%d",&m[i][j]);
      }
  }
}

void mostrar(int m[][10],int linhas, int colunas)
{
  int i, j;

  for(i=0;i<linhas;i++)
  {
      for(j=0;j<colunas;j++)
      {
        printf("matriz[%d][%d]= %d\n",i,j,m[i][j]);
      }
  }
}

Pode perceber que a função é praticamente igual a de preencher. Só que tiramos o scanf e adicionamos um identificador e um valor no printf.

  for(i=0;i<linhas;i++)
  {
      for(j=0;j<colunas;j++)
      {
        printf("matriz[%d][%d]= %d\n",i,j,m[i][j]);
      }
  }

Bom pessoal, ficou extenso, mas é isso ai.

Para o próximo artigo: Operações entre matrizes (multiplicação vai dar dor de cabeça XD).

Qualquer dúvida, erro, mandem um pombo correio.

Cya!

Um pensamento sobre “Linguagem C: Matrizes, parte 1

  1. Pingback: Linguagem C: Matrizes, parte 2 « Diego Doná | Designer, Developer

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s