Curso de C
Listas e Matrizes


Você está em: MarMSX >> Cursos >> C   As variáveis cumprem bem com o seu papel quando se trata de dados simples. Entretanto, se desejarmos armazenar vários dados, como, por exemplo, o nome de 10 pessoas, o uso das variáveis se torna complicado. Exemplo:
#include <stdio.h>

char *nome1, *nome2, *nome3, *nome4, *nome5, *nome6, *nome7, *nome8, *nome9, *nome10;

void main(void)
{
  printf("Entre o nome da 1a. pessoa: ");
  scanf("%s",nome1);
  printf("\nEntre o nome da 2a. pessoa: ");
  scanf("%s",nome2);
  printf("\nEntre o nome da 3a. pessoa: ");
  scanf("%s",nome3);
  printf("\nEntre o nome da 4a. pessoa: ");
  scanf("%s",nome4);
  printf("\nEntre o nome da 5a. pessoa: ");
  scanf("%s",nome5);
  printf("\nEntre o nome da 6a. pessoa: ");
  scanf("%s",nome6);
  printf("\nEntre o nome da 7a. pessoa: ");
  scanf("%s",nome7);
  printf("\nEntre o nome da 8a. pessoa: ");
  scanf("%s",nome8);
  printf("\nEntre o nome da 9a. pessoa: ");
  scanf("%s",nome9);
  printf("\nEntre o nome da 10a. pessoa: ");
  scanf("%s",nome10);
}

  Imagine se desejássemos verificar nessa lista se há alguma pessoa chamada "Bruno". Seria mais uma dezena de linhas de código. E para 1000 pessoas ? :O
  É aí que entram os vetores (listas). Eles servem para armazenar vários dados do mesmo tipo em um lugar com o mesmo nome, onde cada dado é referenciado por um número, que indica sua posição na lista.
 Variáveis         Vetor

┌─────────┐      ┌─────────┐
│  nome1  │      │  nome   │
├─────────┤      ├─────────┤
│ "Carla" │      │ "Carla" │ 0
└─────────┘      ├─────────┤
                 │ "Pedro" │ 1
┌─────────┐      ├─────────┤
│  nome2  │      │   ...   │
├─────────┤      ├─────────┤
│ "Pedro" │      │ "Yago"  │ 9
└─────────┘      └─────────┘

    ...

┌─────────┐
│ nome10  │
├─────────┤
│ "Yago"  │
└─────────┘


  Vetor

  O vetor (em inglês "array") é uma lista, no qual é feita uma reserva de um espaço de memória para armazenar N variáveis do mesmo tipo e em posições contíguas.
  A sintaxe de declaração de vetores em C é a seguinte:
 <tipo_de_dado> <identificador>[<tamanho_do_vetor>];
  Onde:   Ex:
int nota[10];
  Cria um vetor de 10 posições de números inteiros, variando de 0 a 9.

  O vetor é acessado informando-se o número da posição em que desejamos ler ou inserir dados. Para isso, deve-se colocar o nome do vetor, mais o índice dentro dos colchetes. Exemplo:
printf("%d", nota[2]);

  Este mecanismo é semelhante ao DIM do Basic:
Basic			C
10 DIM NOTA(10)		int nota[10];
20 NOTA(2) = 8		nota[2] = 8;
30 PRINT NOTA(2)	printf("%d", nota[2]);

  Importante: Um vetor em C varia de 0 a N-1. Assim, "nota[2]" retorna o terceiro elemento da lista.
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│xxx│xxx│ 8 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
          ↑

  Podemos reescrever o programa dos 10 nomes de uma forma mais simples:
#include <stdio.h>

char *nome[10];

void main(void)
{
  int i;
  for (i=0; i<10; i++)
  {
    printf("\nEntre o nome da %da. pessoa: ",i);
    scanf("%s",nome[i]);
  }
}

  Atribuição inicial

  É possível declarar um vetor e ao mesmo tempo atribuir seus valores. Exemplo:
#include <stdio.h>

int notas[5] = { 8, 6, 7, 9, 10 };

main()
{
  int i;
  for (i=0; i<5; i++)
    printf("Nota %d: %d\n", i+1, notas[i]);
}
  Saída:
  Nota 1: 8
  Nota 2: 6
  Nota 3: 7
  Nota 4: 9
  Nota 5: 10

  Obs: o tamanho do vetor declarado deverá ser exatamente igual à quantidade de elementos inseridos entre as chaves.
int notas[5] = { 8, 6, 7, 9, 10 };
          |             ^
          |             |
          +-------------+


  Matriz

  Podemos criar uma matriz, isto é, um vetor com D dimensões, objetivando novas formas de organizar os dados.
  Para indicar uma matriz de D dimensões, colocamos D pares de colchetes ao lado do nome da variável. Por exemplo, uma matriz de três dimensões:
int matriz_3d[10][20][2];
  Que representa um cubo, cuja largura é 10, altura é 20 e profundidade é igual a 2.

  No exemplo a seguir, vamos criar uma matriz de duas dimensões (tabela) para guardar o dia, o mês e o ano do nascimento de 20 pessoas.
  Em uma tabela, cada pessoa ocupa uma linha, enquanto que cada atributo (dia, mês e ano) ocupa uma coluna. Assim, é necessário criar uma tabela de 20 linhas por 3 colunas.
include <stdio.h>

int data[20][3];
int i;

void main(void)
{
  for (i =0; i<20; i++)
  {
    printf("Pessoa numero %d: ", i);
    printf("Dia: ");
    scanf("%d",&data[i][0]);
    printf("Mes: ");
    scanf("%d",&data[i][1]);
    printf("Ano: ");
    scanf("%d",&data[i][2]);
  }
}

  Ao criarmos a tabela acima, usamos o primeiro colchete para determinar o número total de linhas e o segundo para o número total de colunas.
  A aparência da tabela criada é a seguinte:

  DIA MES ANO
PESSOA 0      
PESSOA 1      
PESSOA 2      
PESSOA 3      
PESSOA 4      
PESSOA 5      
PESSOA 6      
PESSOA 7      
PESSOA 8      
PESSOA 9      
PESSOA 10      
PESSOA 11      
PESSOA 12      
PESSOA 13      
PESSOA 14      
PESSOA 15      
PESSOA 16      
PESSOA 17      
PESSOA 18      
PESSOA 19      

  A área de dados armazenada na memória é a área mais clara da tabela.

  O acesso aos dados da tabela é feito da seguinte maneira:

data[linha][coluna]

  Exemplo para o dia da pessoa 14:
printf("%d", data[14][0]);

  Atribuição inicial

  Assim como nos vetores, podemos atribuir os valores iniciais em uma matriz. Exemplo:
#include <stdio.h>

int tabela[3][2] = { {1,2},{3,4},{5,6} };
int i,j;

main()
{
  for (i=0; i<3; i++)
  {
    for (j=0; j<2; j++)
      printf("%d ",tabela[i][j]);
    printf("\n");
  }
}
  Saída:
  1 2
  3 4
  5 6

  A hirearquia das chaves na declaração é: coluna (mais interno), depois a linha (mais externo).


  Algumas considerações

  Só podemos criar listas ou tabelas com o mesmo tipo de variável (int, float, char, etc). Para utilizarmos múltiplos tipos de dados, devemos criar uma estrutura (struct).

  O tamanho do vetor/tabela é fixo. Deve ser definido antes de rodar o programa, em sua fase de construção. Isto pode levar ao desperdício ou falta de espaço.

  Quantas dimensões podemos criar a matriz?
  D dimensões. Basta colocar a quantidade de colchetes correspondente ao número de dimensões. Exemplo para 3 dimensões:
int a [5][3][2];
  Matriz de 3 dimensões criada:
    +--+--+--+--+--+
  +--+--+--+--+--+ |
  |  |  |  |  |  | +
  +--+--+--+--+--+ |
  |  |  |  |  |  | +
  +--+--+--+--+--+ |
  |  |  |  |  |  | +
  +--+--+--+--+--+

  Eu preciso usar o vetor / matriz todo?
  Não. Você pode projetar um vetor com 1000 posições, mas necessitar usar apenas 20. Daí o desperdício de espaço.


  Inicialização de vetores do tipo string

  O vetor ou matriz pode ser inicializado, através de chaves e os elementos separados por vírgulas. Exemplo:
char *nome[5] = { "Penguin", "Galious", "Noriko", "Matchday", "Konami" };
char nome[2][10] = {"Beatriz", "Ana" };

  A declaração char *nome[5] inidica um vetor de 5 posições, com strings de tamanho N (guarda 5 nomes).
  Já a declaração char nome[2][10] inidica um vetor de 2 posições, com strings de tamanho 10 (guarda 2 nomes com no máximo 10 letras).


  Inicialização de vetores de tamanho N

  É possível declarar um vetor de tamanho igual a N, sendo o valor de N estabelecido pelo número de elementos declarados na inicialização. Para isso, basta utilizar os colchetes vazios. Exemplo:
int v[] = { 1,2,3,4,5,6 };
  O vetor "v" terá tamanho igual a 6.

  O mesmo pode ser aplicado às strings:
char *nome[] = { "Penguin", "Galious", "Noriko", "Matchday", "Konami" };

  Esse tipo de declaração OBRIGA a inserção de valores iniciais, sob pena de dar erro. Exemplo:
char *nome[]; // Erro. Não foi iniciada!


  Utilizando "variáveis" para determinar o tamanho de vetores e matrizes

  Suponhamos que nosso programa necessite da criação de alguns vetores e/ou matrizes que possam ter suas dimensões facilmente alteradas em tempo de compilação. Entretanto, a linguagem C não permite a declaração de um vetor ou matriz utilizando variáveis. Veja o exemplo a seguir.
#include <stdio.h>

int n=15;
double vetor[n];
double matriz[n][4];

main()
{
  vetor[0] = 1;
}
  Ao tentarmos compilar o código acima, o compilador retorna um erro.

  Para resolver esse problema, podemos utilizar a diretiva #define (vide capítulo 2).
#include <stdio.h>

#define n 15

double vetor[n];
double matriz[n][4];

main()
{
  vetor[0] = 1;
}
  Agora, o programa compila com sucesso.

  Observe que apesar de n possuir valor fixo ao compilarmos o programa, podemos alterar o valor dele no código, impactando em todos os vetores e matrizes a ele associados. Isto significa que, se eu necessitar aumentar o tamanho de vetor ou matriz, não preciso mais realizar alterações de dimensão em cada um deles, mas sim na definição de n.

  Você deve estar se perguntando: como eu faço para criar um vetor ou matriz redimensionável em tempo de execução (quando o programa está rodando)?
  Podemos resolver isso de duas maneiras: uma, através de vetores e matrizes, que será abordada na próxima seção. A outra é utilizar variáveis dinâmicas através de ponteiros. Essa solução é mais eficiente, porém mais difícil de se implementar.


  Listas de tamanho variável

  Já sabemos que o vetor não permite o redimensionamento de seu tamanho em tempo de execução. Entretanto, é possível criar listas com o tamanho variável. Para isso, devemos criar um vetor com o tamanho máximo previsto para essa lista e utilizar somente a quantidade de campos necessários.

  Principais características:
  Inserção

  Há dois modos de inserção: o primeiro insere sempre ao final da lista, não sendo necessário o deslocamento dos elementos, enquanto que o segundo insere o elemento em uma posição P da lista, sendo necessário o deslocamento dos outros elementos, uma vez que não podemos sobrescrever sobre uma informação que já ocupa a posição P.

  Exemplo de inserção do valor "7" ao final da lista:
tamanho = 3

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9

Insere:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │ 7 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9

tamanho = 4

  Exemplo de inserção do valor "7" na posição "1" da lista:
tamanho = 3

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9

Desloca (abre espaço):
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
      ↑

Insere:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 7 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
      ↑

tamanho = 4

  O deslocamento DEVERÁ sempre começar pelo último elemento. Se fosse começado pelo primeiro elemento a ser deslocado, ele sobrescreveria o próximo elemento.
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
Procedimento correto:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
          ---->

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
      ---->
Procedimento Errado:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 5 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
      ---->

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 5 │ 5 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
          ---->

  Programa exemplo, que possui as ferramentas de inserção ao final (push) e inserção em qualquer posição.
#include <stdio.h>

int v[10] = { 4,5,9,0,0,0,0,0,0,0 };
int total=3;

void push(int valor)
{
  if (total>= 10)
    return;

  v[total] = valor;
  total++;
}

void insere(int valor, int pos)
{
  int i;

  if ((total>= 10) || (pos < 0) || (pos > total))
    return;

  for (i=total-1; i>=pos; i--)
    v[i+1] = v[i];

  v[pos] = valor;
  total++;
}

void imprime()
{
  int i;

  for (i=0; i<total; i++)
    printf("%d ", v[i]);
  printf("\n");
}

main()
{
  imprime();
  push(7);
  imprime();
  insere(6,1);
  imprime();
}
  Saída:
  4 5 9
  4 5 9 7
  4 6 5 9 7


  Remoção

  Há dois modos de remoção: o primeiro remove sempre ao final da lista, não sendo necessário o deslocamento dos elementos, enquanto que o segundo remove o elemento em uma posição P da lista, sendo necessário o deslocamento dos outros elementos.

  Exemplo de remoção do último elemento da lista:
tamanho = 4

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │ 7 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
              ↑

Remove:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │ 7 │xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
          ↑

tamanho = 3

  Exemplo de remoção do item da posição "1" da lista:
tamanho = 3

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 5 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
          ↑

Desloca:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 4 │ 9 │ 9 │xxx│xxx│xxx│xxx│xxx│xxx│xxx│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  0   1   2   3   4   5   6   7   8   9
      ↑

tamanho = 2

  Em ambos os casos, o "lixo" permanece na antiga última posição. Entretanto, o tamanho da lista diminuiu e esse "lixo" é ignorado.

  Diferente da inserção, o deslocamento agora deverá começar pelo primeiro elemento a ser deslocado.

  Adicionar ao programa anterior:
void pop()
{
  if (total<=0)
    return;

  total--;
}

void remover(int pos)
{
  int i;

  if ((total<= 0) || (pos < 0) || (pos >= total))
    return;

  for (i=pos+1; i<total; i++)
    v[i-1] = v[i];

  total--;
}
  E na função "main()":
pop();
imprime();
remover(0);
imprime();
  Saída:
  4 5 9
  4 5 9 7
  4 6 5 9 7
  4 6 5 9
  6 5 9



<< Anterior Linguagem C Próxima >>