Reforço de Algoritmos e Programação - Instituto de Informática (UFRGS) - Prof. Dennis Giovani Balreira



Aula 4 - Vetores

Nesta aula veremos os vetores (também chamados de arrays): a primeira estrutura de dados propriamente dita da disciplina, capaz de guardar vários valores do mesmo tipo sob um único nome. Vetores e laços de repetição (Aula 3) andam sempre juntos — praticamente tudo que faremos com vetores envolve percorrê-los com um for.


1. Por que precisamos de vetores?

Imagine um programa que precisa guardar as notas de 5 alunos. Sem vetores, seríamos obrigados a criar uma variável para cada nota:

float nota1, nota2, nota3, nota4, nota5;

Isso já é incômodo para 5 alunos, e se torna inviável para 50, 500, ou uma quantidade de alunos que só será conhecida durante a execução do programa. Um vetor resolve esse problema, guardando várias posições do mesmo tipo sob um único nome, acessadas por um índice:

float notas[5]; // um único nome, cinco posições

2. Declaração e inicialização

Para declarar um vetor, indicamos o tipo dos elementos, o nome do vetor, e a quantidade de posições entre colchetes:

int idades[10];    // vetor de 10 inteiros, sem valores iniciais definidos

Também é possível já inicializar os valores no momento da declaração:

int primos[5] = {2, 3, 5, 7, 11};
Tamanho fixo. O tamanho de um vetor declarado dessa forma (notas[5]) é definido em tempo de compilação e não pode ser alterado durante a execução do programa — se você precisar de mais posições do que o vetor comporta, é preciso declará-lo com um tamanho maior desde o início.

3. Índices, acesso e modificação

Em C, os índices de um vetor sempre começam em 0 e vão até N - 1, onde N é o tamanho do vetor. Um vetor notas[5] possui as posições notas[0], notas[1], notas[2], notas[3] e notas[4]nunca notas[5].

float notas[5];

notas[0] = 8.5;         // atribui a primeira posição
notas[1] = 7.0;
printf("%.1f\n", notas[0]); // lê a primeira posição: imprime 8.5
Cuidado: C não verifica os limites! Diferente de outras linguagens, C não impede que você acesse um índice fora do vetor, como notas[5] em um vetor de 5 posições. Isso não gera um erro de compilação nem, necessariamente, um erro imediato na execução — o programa pode ler ou escrever em uma posição de memória que não pertence ao vetor, com resultados imprevisíveis (valores errados, ou até o encerramento abrupto do programa, conhecido como Segmentation Fault). É responsabilidade de quem programa garantir que os índices usados sejam sempre válidos.

4. Percorrendo um vetor com for

Por sabermos exatamente quantas posições um vetor possui, o for (Aula 3) é a estrutura natural para percorrê-lo, de 0 até tamanho - 1:

#include <stdio.h>

int main() {
    int notas[5];
    int i;

    // preenchendo o vetor
    for (i = 0; i < 5; i++) {
        printf("Digite a nota %d: ", i + 1);
        scanf("%d", &notas[i]);
    }

    // exibindo o vetor
    for (i = 0; i < 5; i++) {
        printf("Nota %d: %d\n", i + 1, notas[i]);
    }

    return 0;
}

Note o &notas[i] dentro do scanf — assim como fazíamos com variáveis simples (Aula 1), o scanf precisa do endereço de onde guardar o valor lido, e &notas[i] é o endereço da posição i do vetor.


5. Vetores na memória

Assim como vimos na Aula 1 para variáveis simples, os elementos de um vetor também ficam na memória, mas com uma característica especial: eles ficam sempre em posições contíguas (uma exatamente depois da outra).

Considere um vetor int primos[5] = {2, 3, 5, 7, 11};. Como cada int ocupa 4 bytes, e o vetor começa (por exemplo) no endereço E2000 (usando a mesma notação decimal de endereços da Aula 1 — a letra E seguida de um número, em vez do tradicional 0x em hexadecimal), seus elementos ficam assim organizados:

Endereço Identificador Valor
E2000 primos[0] 2
E2004 primos[1] 3
E2008 primos[2] 5
E2012 primos[3] 7
E2016 primos[4] 11

É justamente por essa organização contígua que o acesso a qualquer posição do vetor é tão rápido: para acessar primos[i], o programa só precisa somar i * 4 bytes (o tamanho de um int) ao endereço inicial do vetor — não importa se i é 0 ou 4, o custo é sempre o mesmo.


6. Aplicações comuns com vetores

Soma e média dos elementos (acumulador)

int vetor[5] = {10, 20, 5, 8, 12};
int i, soma = 0;

for (i = 0; i < 5; i++) {
    soma += vetor[i];
}

printf("Soma: %d\n", soma);
printf("Media: %.2f\n", soma / 5.0);

Maior e menor elemento

int vetor[5] = {10, 20, 5, 8, 12};
int i, maior, menor;

maior = vetor[0]; // começa "otimista", assumindo o primeiro elemento
menor = vetor[0];

for (i = 1; i < 5; i++) { // começa em 1: o índice 0 já foi usado acima
    if (vetor[i] > maior) {
        maior = vetor[i];
    }
    if (vetor[i] < menor) {
        menor = vetor[i];
    }
}

printf("Maior: %d\n", maior);
printf("Menor: %d\n", menor);

Busca sequencial

Para descobrir se um valor está presente no vetor (e em qual posição), percorremos o vetor comparando cada elemento com o valor procurado — uma flag (ou a própria posição encontrada) guarda o resultado:

int vetor[5] = {10, 20, 5, 8, 12};
int i, procurado = 8;
int posicaoEncontrada = -1; // -1 significa "ainda não encontrado"

for (i = 0; i < 5; i++) {
    if (vetor[i] == procurado) {
        posicaoEncontrada = i;
    }
}

if (posicaoEncontrada != -1) {
    printf("Encontrado na posicao %d\n", posicaoEncontrada);
} else {
    printf("Nao encontrado\n");
}

Essa técnica — percorrer os elementos um a um, comparando com o valor procurado — é chamada de busca sequencial, e será revisitada e aprofundada em uma aula futura, junto com técnicas de ordenação.


Resumo

  • Vetor: conjunto de posições do mesmo tipo, sob um único nome, com tamanho fixo definido na declaração.
  • Índices sempre começam em 0 e vão até tamanho - 1; C não verifica automaticamente se um índice usado é válido.
  • Memória: os elementos de um vetor ficam em posições contíguas, o que torna o acesso a qualquer posição igualmente rápido.
  • for e vetores andam juntos: como o tamanho do vetor é conhecido, o for é a estrutura natural para percorrê-lo.
  • Aplicações comuns: soma/média (acumulador), maior/menor elemento, busca sequencial (percorrer comparando com um valor procurado).

Exercícios

Nível fácil

  1. Escreva um programa que declare um vetor de 5 inteiros, leia os 5 valores do usuário, e depois os imprima na ordem em que foram lidos.
  2. Escreva um programa que leia um vetor de 10 inteiros e imprima quantos deles são pares.
  3. Escreva um programa que leia um vetor de 5 números reais e imprima a soma e a média deles.

Nível médio

  1. Escreva um programa que leia um vetor de 10 inteiros e imprima o maior e o menor valor encontrado, e em quais posições (índices) eles estão.
  2. Escreva um programa que leia um vetor de n inteiros (com n também lido do usuário) e um valor a ser procurado, e informe se o valor está presente no vetor e, em caso afirmativo, quantas vezes ele aparece.
  3. Escreva um programa que leia um vetor de 10 inteiros e crie um segundo vetor, do mesmo tamanho, contendo apenas os valores do primeiro vetor multiplicados por 2. Imprima os dois vetores ao final.

Nível difícil

  1. Escreva um programa que leia um vetor de n inteiros e o inverta (o primeiro elemento passa a ser o último, e assim por diante), sem usar um segundo vetor — troque os elementos diretamente dentro do próprio vetor original.
  2. Escreva um programa que leia um vetor de n inteiros e remova todas as ocorrências de um valor x informado pelo usuário, deslocando os elementos seguintes para preencher os espaços abertos, e informando ao final quantos elementos restaram no vetor.

Sugestões de Respostas dos Exercícios

Exercício 1
#include <stdio.h>

int main() {
    int vetor[5];
    int i;

    for (i = 0; i < 5; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
    }

    for (i = 0; i < 5; i++) {
        printf("%d\n", vetor[i]);
    }

    return 0;
}

Exercício 2
#include <stdio.h>

int main() {
    int vetor[10];
    int i, contadorPares = 0;

    for (i = 0; i < 10; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
        if (vetor[i] % 2 == 0) {
            contadorPares++;
        }
    }

    printf("Numeros pares: %d\n", contadorPares);

    return 0;
}

Exercício 3
#include <stdio.h>

int main() {
    float vetor[5];
    float soma = 0;
    int i;

    for (i = 0; i < 5; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%f", &vetor[i]);
        soma += vetor[i];
    }

    printf("Soma: %.2f\n", soma);
    printf("Media: %.2f\n", soma / 5);

    return 0;
}

Exercício 4
#include <stdio.h>

int main() {
    int vetor[10];
    int i, maior, menor, posicaoMaior = 0, posicaoMenor = 0;

    for (i = 0; i < 10; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
    }

    maior = vetor[0];
    menor = vetor[0];

    for (i = 1; i < 10; i++) {
        if (vetor[i] > maior) {
            maior = vetor[i];
            posicaoMaior = i;
        }
        if (vetor[i] < menor) {
            menor = vetor[i];
            posicaoMenor = i;
        }
    }

    printf("Maior: %d (posicao %d)\n", maior, posicaoMaior);
    printf("Menor: %d (posicao %d)\n", menor, posicaoMenor);

    return 0;
}

Exercício 5
#include <stdio.h>

int main() {
    int vetor[100]; // capacidade máxima; n informa quantas posições serão usadas
    int n, i, procurado, ocorrencias = 0;

    printf("Quantos elementos? ");
    scanf("%d", &n);

    for (i = 0; i < n; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
    }

    printf("Qual valor procurar? ");
    scanf("%d", &procurado);

    for (i = 0; i < n; i++) {
        if (vetor[i] == procurado) {
            ocorrencias++;
        }
    }

    if (ocorrencias > 0) {
        printf("Encontrado %d vez(es)\n", ocorrencias);
    } else {
        printf("Nao encontrado\n");
    }

    return 0;
}

Como C exige que o tamanho de um vetor comum seja fixado na declaração, declaramos um vetor "grande o suficiente" (100 posições) e usamos apenas as primeiras n — uma limitação que será superada mais adiante na disciplina, quando estudarmos alocação dinâmica de memória.


Exercício 6
#include <stdio.h>

int main() {
    int vetor[10];
    int dobrado[10];
    int i;

    for (i = 0; i < 10; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
        dobrado[i] = vetor[i] * 2;
    }

    printf("Original: ");
    for (i = 0; i < 10; i++) {
        printf("%d ", vetor[i]);
    }
    printf("\n");

    printf("Dobrado:  ");
    for (i = 0; i < 10; i++) {
        printf("%d ", dobrado[i]);
    }
    printf("\n");

    return 0;
}

Exercício 7
#include <stdio.h>

int main() {
    int vetor[100];
    int n, i, inicio, fim, temp;

    printf("Quantos elementos? ");
    scanf("%d", &n);

    for (i = 0; i < n; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
    }

    inicio = 0;
    fim = n - 1;

    while (inicio < fim) {
        // troca vetor[inicio] com vetor[fim]
        temp = vetor[inicio];
        vetor[inicio] = vetor[fim];
        vetor[fim] = temp;

        inicio++;
        fim--;
    }

    printf("Vetor invertido: ");
    for (i = 0; i < n; i++) {
        printf("%d ", vetor[i]);
    }
    printf("\n");

    return 0;
}

A ideia é usar dois índices que "andam um em direção ao outro": inicio começa no início do vetor e avança; fim começa no final e recua. A cada passo, trocamos os elementos dessas duas posições (usando uma variável temp auxiliar, para não perder um dos valores durante a troca) e continuamos até os dois índices se cruzarem no meio do vetor.


Exercício 8
#include <stdio.h>

int main() {
    int vetor[100];
    int n, i, j, x;
    int tamanhoFinal;

    printf("Quantos elementos? ");
    scanf("%d", &n);

    for (i = 0; i < n; i++) {
        printf("Digite o valor %d: ", i + 1);
        scanf("%d", &vetor[i]);
    }

    printf("Qual valor remover? ");
    scanf("%d", &x);

    tamanhoFinal = 0; // vai contar quantos elementos sobram

    for (i = 0; i < n; i++) {
        if (vetor[i] != x) {
            vetor[tamanhoFinal] = vetor[i]; // copia para a próxima posição livre
            tamanhoFinal++;
        }
    }

    printf("Restaram %d elementos: ", tamanhoFinal);
    for (j = 0; j < tamanhoFinal; j++) {
        printf("%d ", vetor[j]);
    }
    printf("\n");

    return 0;
}

Em vez de "abrir buracos" no vetor a cada remoção, usamos um segundo índice, tamanhoFinal, que só avança quando encontramos um elemento que deve permanecer — cada elemento mantido é copiado para a próxima posição livre à esquerda. Ao final, tamanhoFinal indica exatamente quantos elementos restaram, e todos eles estarão organizados nas primeiras posições do vetor.