segunda-feira, 30 de novembro de 2009

Juntos somos mais eficientes! (vetores)

Até agora vimos somente os tipos básicos do C (aqui), e fizemos muita coisa com eles. Mas chega um momento em que eles não são eficientes para resolver alguns problemas. Quer um exemplo?
Imagine um programa que receba 100 valores inteiros digitados por um usuário. Imaginou? Se não, veja como ele seria usando o que vimos até agora.


//PROGRAMA QUE RECEBE 100 NÚMEROS INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int val001, val002, val003, val004, val005, ... , val100;
 
 printf("Digite 100 numeros inteiros:\n");
 scanf("%d",&val001);
 scanf("%d",&val002);
 scanf("%d",&val003);
 scanf("%d",&val004);
 scanf("%d",&val005);
    .
    .
    .
 scanf("%d",&val100);
 system("pause");
}


Percebeu a quantidade de linhas que esse programa teria? Sabia que é possível fazer este mesmo programa com 16 linhas (até menos) e de forma muito mais inteligente?
Dê uma olhada nesse exemplo.


//PROGRAMA QUE RECEBE 100 NÚMEROS INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int vetor[100], i;
 
 printf("Digite 100 numeros inteiros:\n");
 for(i=0; i < 100; i++){
    printf ("Valor %d: ",i+1);
    scanf("%d",&vetor[i]);
 }
 
 system("pause");
}


Este código acima está completo e funciona perfeitamente (não faz muita coisa, é verdade, mas funciona ;). Vamos ver o 'segredo' por trás disto.

Observe a linha 6. Nela é declarado um vetor de 100 inteiros. Vetor???

Um grupo de iguais.

Um vetor é um tipo estruturado homogêneo.(???)
Estruturado significa que ele é uma composição de tipos básicos, ou seja, tipos básicos organizados em um grupo/agrupamento. E homogêneo, significa que esses tipos básicos são iguais; no nosso exemplo, são 100 inteiros (é possível criar agrupamentos heterogêneos, como veremos em outro momento).
Não entendeu ainda? Quer que eu desenhe?



A figura acima representa um vetor de 4 inteiros armazenado na memória. Observe que o armazenamento é consecutivo, ou seja, cada valor inteiro está armazenado num endereço da memória, e estes endereços estão em sequência. Se tivéssemos declarado 4 variáveis inteiras não poderíamos garantir que elas ficariam armazenadas em sequência na memória.
Por estarem armazenados em sequência na memória, podemos acessar o conteúdo de cada endereço também em sequência. Esse é o 'truque' do vetor.
Mas como é feito esse acesso?

Leia o índice!

Com certeza você já teve contato com algum livro (se não, aconselho que o faça rsrs). Podemos generalizar um livro como uma sequência de páginas (escritas ou não) agrupadas. Todas as páginas tem o mesmo tamanho (não me lembro de ter visto algum em que isto não fosse verdadeiro).
Quando queremos encontrar alguma informação específica num livro temos duas opções: ou folheamos o livro, página por página, analisando uma a uma; ou vamos ao seu índice e localizamos o número exato da página onde está a informação que procuramos. Qual delas você considera mais eficiente?
Em termos de comparação, tirando as muitas diferenças, um vetor se assemelha muito a um livro. São posições de memória do mesmo tamanho agrupadas contendo algum valor válido (ou não). Já que são tão parecidos, por que não usar um índice também com um vetor? Facilitaria muito, não concorda? Pois é exatamente assim que funciona.
Vamos a outro desenho.



Para acessar o conteúdo da 1a posição do vetor da figura acima, é só se referir ao nome do vetor e ao índice 0 (zero). Os vetores em C SEMPRE começam com o índice 0 (zero).
Digamos que o nome do vetor da figura acima seja vet. Para exibir o conteúdo da sua 1a posiçao, usamos o comando:

 printf("%d", vet[0]);

Seria impresso o valor 67.

Fácil, não? Só devemos prestar atenção a 2 pontos importantíssimos:

1o. O primeiro índice de um vetor em C SEMPRE começa em 0 (zero)
2o. O último índice de um vetor em C é SEMPRE o tamanho do vetor menos 1.

Isso não significa que não se possa acessar um elemento fora do vetor.
Se usássemos no vetor dos desenhos acima o comando:

 printf("%d",vet[4]);

Algo seria impresso na tela. Não temos como saber o que seria, mas que funcionaria, funcionaria. Por quê?

Um nome de um vetor seguido de um índice i significa que queremos acessar o endereço que está i posições depois do endereço inicial do vetor.
Se um vetor de 4 inteiros está armazenado na memória, por exemplo, a partir do endereço 44 e o tamanho de um inteiro é 4 bytes; o elemento de índice 3 deste vetor estará no endereço 56.

 endereço inicial do vetor(44) + 3 * (tamanho do tipo do vetor (4)

Se tentarmos acessar o índice 4, que sabemos 'não existir', na verdade estaremos acessando o endereço 60 da memória, e 'interpretando' o seu conteúdo como um valor inteiro (este conteúdo pode ser qualquer coisa que esteja na memória, possivelmente deixada por algum outro programa, frequentemente no referimos a ele como 'lixo').
Algumas linguagens de programação não permitem esse tipo de acesso, mas o C não faz restrições. É sua responsabilidade como programador evitar esse tipo de coisa.

Agora que conhecemos o tipo vetor, ficou fácil entender o código do nosso exemplo. Certo?

3 comentários:

  1. Cara, você, explica, muito Bem...
    Obrigado. Ajuda para Caramba !

    ResponderExcluir
  2. Muito bom seu blog cara, continue assim me ajuda muito nas minhas aulas.

    ResponderExcluir
  3. estou com um problema, preciso criar 2 vetores e em um terceiro vetor intercalar esses numeros que foram digitados no 1° e 2° vetor...

    tem alguma dica?

    ResponderExcluir