Pular para conteúdo

Semana 07 — Vetores (arranjos unidimensionais)

Nesta semana

Unidade 2 · Seg 21/09 · Qua 23/09 · Sex 25/09

Até agora, cada variável guardava um valor: uma idade, uma nota, um preço. Mas e quando o problema pede muitos valores do mesmo tipo ao mesmo tempo — as notas de 100 alunos, as temperaturas de um mês, os salários de uma empresa? Declarar nota1, nota2, …, nota100 é inviável. Nesta semana conhecemos o vetor (ou array): uma estrutura que guarda vários valores do mesmo tipo sob um único nome, acessados por um índice. É a nossa primeira estrutura de dados de verdade.

Vamos aprender a declarar, inicializar, percorrer, ler e escrever vetores, a realizar as operações fundamentais (soma, média, máximo, mínimo, busca) e — ponto central da semana — a passar vetores para funções, o que revela um comportamento surpreendente e diferente de tudo que vimos na Semana 04.

🎯 Objetivos de aprendizagem

Ao final desta semana, você deverá ser capaz de:

  • explicar por que vetores existem e quando usá-los, em vez de dezenas de variáveis separadas;
  • declarar um vetor, definir seu tamanho e inicializá-lo (total, parcial e "tudo zero");
  • entender por que os índices vão de 0 a n−1 e acessar/atribuir elementos com v[i];
  • percorrer um vetor com for, e ler/escrever seus elementos com scanf/printf;
  • implementar as operações fundamentais: soma, média, máximo, mínimo, busca linear e contagem condicional;
  • reconhecer o perigo dos limites — acessar fora de 0..n−1 é comportamento indefinido em C;
  • explicar por que passar um vetor para uma função é diferente de passar um int (o vetor "decai" para o endereço do primeiro elemento) e por que é preciso passar o tamanho junto.

📖 Segunda — Estudo do conteúdo

1. Motivação: por que precisamos de vetores?

Imagine que você precisa ler as notas de 100 alunos, calcular a média da turma e depois dizer quantos alunos ficaram acima da média. Repare no problema: para saber quem ficou acima da média, você precisa calcular a média primeiro — e, para isso, já precisa ter lido todas as notas. Ou seja, você precisa guardar as 100 notas ao mesmo tempo na memória.

Com o que sabíamos até a Semana 06, a única saída seria declarar 100 variáveis:

double nota1, nota2, nota3, /* ... */ nota100;   // inviável!

Isso é impraticável: 100 declarações, 100 scanf, e nenhum jeito de usar um laço para tratá-las (não dá para "somar 1" ao nome nota1 e obter nota2). O código ficaria gigante, repetitivo e impossível de manter.

O vetor resolve isso. Ele guarda vários valores do mesmo tipo sob um único nome, e cada valor é acessado por uma posição (o índice). O melhor: como o índice é um número, podemos percorrê-lo com um laço — exatamente a ferramenta que aprendemos na Semana 03.

double nota[100];   // um nome, cem posições

Quando usar um vetor?

A pista clássica é: "muitos valores do mesmo tipo, tratados de forma parecida". Se você se pegar pensando em valor1, valor2, valor3…, ou se precisar guardar uma coleção de dados para processá-la depois (ordenar, buscar, comparar entre si), é hora de usar um vetor.

2. Declaração, tamanho e inicialização

2.1 Declarando um vetor

A forma geral é:

tipo nome[quantidade];

Por exemplo:

int v[5];        // reserva 5 inteiros: v[0], v[1], v[2], v[3], v[4]
double temp[30]; // 30 numeros reais
char letras[26]; // 26 caracteres

A declaração int v[5]; faz o computador reservar, na memória, 5 posições contíguas (lado a lado), cada uma do tamanho de um int (tipicamente 4 bytes). É como uma fileira de 5 caixas idênticas, todas com o mesmo nome (v), numeradas de 0 a 4.

flowchart LR
    subgraph vetor["int v[5] — 5 posicoes contiguas"]
    direction LR
    A["v[0]"] --- B["v[1]"] --- C["v[2]"] --- D["v[3]"] --- E["v[4]"]
    end

O tamanho é fixo e definido na declaração

O número entre colchetes é a quantidade de posições — e, com o que sabemos agora, ele precisa ser uma constante conhecida na hora de escrever o programa. Não dá para, mais tarde, "aumentar" o vetor. (Criar vetores cujo tamanho é decidido durante a execução é possível, mas depende de alocação dinâmica de memória, tema da Unidade 3.)

2.2 Inicialização

Assim como variáveis comuns, um vetor declarado mas não inicializado contém lixo (veja a Semana 01). Podemos dar valores iniciais na própria declaração, entre chaves:

int v[5] = {10, 20, 30, 40, 50};   // v[0]=10, v[1]=20, ..., v[4]=50

A ordem dos valores segue a ordem das posições. Há três atalhos muito úteis:

// 1) Inicializacao PARCIAL: o resto e preenchido com 0 automaticamente
int a[5] = {10, 20, 30};   // a[0]=10, a[1]=20, a[2]=30, a[3]=0, a[4]=0

// 2) Zerar o vetor inteiro (idioma muito comum em C)
int z[100] = {0};          // TODAS as 100 posicoes viram 0

// 3) Deixar o compilador contar o tamanho a partir dos valores
int b[] = {1, 2, 3, 4};    // o compilador entende que o tamanho e 4
Forma Resultado
int v[5] = {10,20,30,40,50}; todas as posições recebem os valores dados
int a[5] = {10,20,30}; as primeiras recebem os valores; o resto vira 0
int z[100] = {0}; todas as posições viram 0
int b[] = {1,2,3,4}; tamanho deduzido dos valores (aqui, 4)
int c[5]; lixo em todas as posições — perigoso!

A inicialização parcial só zera o resto — não o começo

int a[5] = {7}; não preenche o vetor com sete. Ele coloca 7 em a[0] e zera a[1] até a[4]. Para zerar tudo, use {0}. Para colocar o mesmo valor não-nulo em todas as posições, é preciso um laço (não existe atalho para isso na declaração).

3. Índices: por que começam em 0?

Cada posição do vetor tem um índice (um número inteiro). Em C — como na maioria das linguagens — os índices vão de 0 até n-1, onde n é o tamanho. Num vetor de 5 posições, os índices válidos são 0, 1, 2, 3, 4. Não existe v[5] num vetor de 5 elementos!

int v[5] = {10, 20, 30, 40, 50};
printf("%d\n", v[0]);   // 10  (o PRIMEIRO elemento)
printf("%d\n", v[4]);   // 50  (o ULTIMO elemento, indice 4)

v[2] = 99;              // ATRIBUICAO: muda o terceiro elemento
printf("%d\n", v[2]);   // 99

Repare em dois usos de v[i]: ler o valor (printf("%d", v[0])) e atribuir um valor (v[2] = 99;). Nos dois casos, i é a posição.

Mas por que começar em 0, e não em 1, como seria mais "natural" para um humano? A razão é profunda e vale entender desde já.

Curiosidade 💡 — por que o índice começa em 0?

O índice não é bem um "número de ordem" — ele é um deslocamento (em inglês, offset) a partir do início do vetor. O nome v, internamente, representa o endereço da primeira caixa. O elemento v[0] está a zero posições do início (é o próprio início); v[1] está a uma posição adiante; v[i] está a i posições adiante. Ou seja, o índice responde à pergunta "quantas posições devo andar a partir do começo?". O primeiro elemento está no próprio começo — logo, deslocamento 0.

Essa relação entre índice, endereço e deslocamento é o coração dos ponteiros, que veremos na Unidade 3. Guarde a ideia: índice = "quantos passos a partir do início". Ela vai fazer todo o sentido em algumas semanas.

O último índice é n−1, nunca n

Num vetor int v[5], o último elemento é v[4]. Escrever v[5] acessa uma posição que não pertence ao vetor — e isso é uma das fontes de bug mais perigosas de C (veja a seção 7). Memorize: tamanho n ⇒ índices de 0 a n-1.

4. Percorrendo um vetor com for

A verdadeira força do vetor aparece quando o combinamos com um laço. O padrão canônico para percorrer um vetor de tamanho n é:

for (int i = 0; i < n; i++) {
    // aqui, v[i] e o elemento da posicao i
}

Observe cada parte, porque este for aparecerá em praticamente todo programa com vetores:

  • i = 0 — começa no primeiro índice (0);
  • i < n — continua enquanto i for menor que n (e para em n-1);
  • i++ — avança uma posição por vez.

O uso de i < n (e não i <= n) é intencional e crucial: com i <= n, a última volta tentaria acessar v[n], que está fora do vetor. Este é o famoso erro de "um a mais" (off-by-one).

O erro clássico do <= no laço de vetor

int v[5] = {10, 20, 30, 40, 50};
for (int i = 0; i <= 5; i++)     // ERRADO: i chega a 5
    printf("%d ", v[i]);         // na ultima volta acessa v[5] (fora!)
O correto é i < 5 (ou i < n). Este erro quase nunca é apontado pelo compilador — ele só se manifesta como um comportamento estranho em tempo de execução. Fique atento.

5. Lendo e escrevendo vetores

Ler um vetor do teclado é, essencialmente, um scanf dentro de um laço — um por posição. O & continua valendo: &v[i] é o endereço da posição i.

ler_escrever.c
#include <stdio.h>
#define TAM 5

int main(void) {
    int v[TAM];

    // LEITURA: um scanf por posicao
    for (int i = 0; i < TAM; i++) {
        printf("Digite v[%d]: ", i);
        scanf("%d", &v[i]);        // note o & antes de v[i]
    }

    // ESCRITA: um printf por posicao
    printf("Vetor lido: ");
    for (int i = 0; i < TAM; i++) {
        printf("%d ", v[i]);
    }
    printf("\n");

    return 0;
}

Repare no uso de #define TAM 5: damos um nome ao tamanho. Se um dia o vetor precisar ter 10 posições, mudamos um único lugar e todo o resto se ajusta. Voltaremos a esse hábito na seção 9.

Leitura de double num vetor

Nada muda em relação à Semana 01: na leitura de reais, o especificador continua sendo %lf; na impressão, %f:

double x[TAM];
for (int i = 0; i < TAM; i++) scanf("%lf", &x[i]);   // leitura: %lf
for (int i = 0; i < TAM; i++) printf("%.2f ", x[i]); // impressao: %f/%.2f

6. Operações fundamentais com vetores

Quase tudo o que fazemos com vetores é uma variação de percorrê-los acumulando ou comparando valores. Vamos ver os padrões essenciais — memorize-os, pois são "tijolos" que você combinará o semestre inteiro.

6.1 Soma e média dos elementos

int v[TAM] = {10, 20, 30, 40, 50};
int soma = 0;
for (int i = 0; i < TAM; i++) {
    soma += v[i];               // acumula
}
double media = (double) soma / TAM;   // cast evita divisao inteira (Semana 01!)
printf("Soma = %d, Media = %.2f\n", soma, media);

O (double) antes de soma é essencial: sem ele, soma / TAM seria divisão inteira e a média sairia truncada. Este é exatamente o cuidado da Semana 01, agora aplicado a vetores.

6.2 Máximo e mínimo

A ideia: comece supondo que o primeiro elemento é o maior (e o menor); depois percorra o resto comparando e atualizando quando achar algo melhor.

int v[TAM] = {30, 10, 50, 20, 40};
int maior = v[0];
int menor = v[0];
for (int i = 1; i < TAM; i++) {     // comeca em 1: v[0] ja foi o "chute inicial"
    if (v[i] > maior) maior = v[i];
    if (v[i] < menor) menor = v[i];
}
printf("Maior = %d, Menor = %d\n", maior, menor);

Não inicialize o máximo com 0

Um erro comum é fazer int maior = 0;. Se todos os elementos forem negativos, o resultado sairia errado (nenhum seria maior que 0). Inicializar com v[0] é sempre seguro, porque v[0] é um elemento real do vetor.

6.3 Busca linear (procurar um valor)

Percorrer o vetor comparando cada elemento com o valor procurado. Guardamos a posição onde ele foi encontrado (ou -1, um valor que sabemos ser um índice inválido, para sinalizar "não achei").

int v[TAM] = {10, 20, 30, 40, 50};
int alvo = 30;
int pos = -1;                       // -1 = "ainda nao encontrado"
for (int i = 0; i < TAM; i++) {
    if (v[i] == alvo) {
        pos = i;
        break;                      // achou: nao precisa continuar
    }
}
if (pos != -1) printf("Encontrado na posicao %d\n", pos);
else           printf("Valor nao encontrado\n");

O break faz o laço parar assim que encontra a primeira ocorrência — uma otimização simples e importante. Esta técnica se chama busca linear (ou sequencial) porque olha os elementos um a um, em sequência.

6.4 Contagem condicional

Contar quantos elementos satisfazem uma condição: um contador que cresce só quando a condição é verdadeira.

int v[TAM] = {12, 7, 30, 5, 44};
int pares = 0;
for (int i = 0; i < TAM; i++) {
    if (v[i] % 2 == 0) pares++;     // conta so os pares
}
printf("Quantidade de pares: %d\n", pares);
Operação Ideia central Cuidado principal
Soma / Média acumulador soma += v[i] cast para double na média
Máximo / Mínimo "chute" com v[0], comparar o resto não inicializar com 0
Busca linear comparar com o alvo, guardar posição usar -1 para "não achei"
Contagem contador que cresce sob condição inicializar o contador em 0

7. O PERIGO dos limites (comportamento indefinido)

Chegamos ao ponto que mais causa dor de cabeça a quem começa em C. Vamos ser diretos:

C NÃO verifica os limites do vetor

Se você acessar v[i] com i fora do intervalo 0..n-1, o C não avisa, não reclama e não trava na hora. Ele simplesmente lê ou escreve na região da memória que estaria ali se o vetor fosse maior — memória que, na verdade, pertence a outra coisa (outra variável, dados internos do programa...).

O resultado é o temido comportamento indefinido (undefined behavior): o programa pode

  • imprimir um valor de lixo;
  • corromper silenciosamente outra variável (e você vai caçar o bug no lugar errado);
  • travar com um erro do tipo segmentation fault;
  • ou até parecer funcionar — o que é o pior dos casos, porque o bug fica escondido.

Um exemplo que ilustra o desastre:

fora_do_limite.c
#include <stdio.h>

int main(void) {
    int v[5] = {1, 2, 3, 4, 5};
    printf("%d\n", v[5]);    // ERRADO: v[5] nao existe (validos: v[0]..v[4])
    v[10] = 99;              // PIOR: escreve em memoria que nao e do vetor!
    return 0;
}

Ao contrário de linguagens como Python ou Java (que verificam e lançam um erro claro), C troca essa segurança por velocidade: não gastar tempo checando cada acesso torna o programa mais rápido. O preço é que a responsabilidade de não sair dos limites é inteiramente sua. Por isso o padrão for (int i = 0; i < n; i++) é tão importante: ele mantém i sempre dentro do intervalo válido.

Curiosidade 💡 — estouro de buffer e segurança

Escrever fora dos limites de um vetor tem um nome famoso: estouro de buffer (buffer overflow). Além de bugs, ele é uma das vulnerabilidades de segurança mais exploradas da história da computação. Um atacante que consegue fazer um programa escrever além de um vetor pode, em certos casos, sobrescrever dados de controle do programa e até executar código malicioso. Muitas invasões célebres (como o worm Morris, de 1988) exploraram exatamente isso. É por essa razão que linguagens modernas dão tanta ênfase a checar limites — e que, em C, você precisa ser disciplinado(a) com índices.

8. Vetores como parâmetros de funções

Aqui está a grande novidade da semana — e ela contrasta diretamente com o que aprendemos sobre funções na Semana 04.

Lembre-se: na Semana 04 vimos que C usa passagem por valor — a função recebe uma cópia do argumento, e alterá-lo dentro da função não afeta a variável original. Com vetores, a história é diferente.

8.1 O vetor não é copiado — passa-se o endereço

Quando você passa um vetor para uma função, C não copia todos os elementos. Em vez disso, a função recebe o endereço do primeiro elemento (por isso dizemos que o vetor "decai" para um ponteiro). Na prática, a função passa a trabalhar sobre o mesmo vetor de quem a chamou — não sobre uma cópia.

Consequência direta e importantíssima: alterações feitas nos elementos dentro da função persistem depois que ela retorna!

preenche.c
#include <stdio.h>
#define TAM 5

// recebe o vetor e o tamanho; PREENCHE cada posicao
void preenche(int v[], int n) {
    for (int i = 0; i < n; i++) {
        v[i] = i * 10;        // altera o vetor ORIGINAL de quem chamou
    }
}

int main(void) {
    int numeros[TAM];
    preenche(numeros, TAM);   // passa o vetor (na verdade, seu endereco)

    for (int i = 0; i < TAM; i++)
        printf("%d ", numeros[i]);   // 0 10 20 30 40  -> a mudanca PERSISTIU!
    printf("\n");
    return 0;
}

Compare com o exemplo tenta_dobrar da Semana 04: lá, mexer no parâmetro não mudava o original; aqui, mexer em v[i] muda o vetor de main. A diferença é exatamente essa: o int é copiado; o vetor não — a função recebe o acesso ao original.

flowchart LR
    subgraph antes["Semana 04 — int por valor"]
    N1["main: n = 10"] -->|copia o VALOR| X1["funcao: x = 10"]
    X1 -. nao afeta .-> N1
    end
    subgraph agora["Semana 07 — vetor"]
    V1["main: numeros[]"] -->|passa o ENDERECO| F1["funcao: v[] (o mesmo!)"]
    F1 -->|altera de verdade| V1
    end

Curiosidade 💡 — o vetor 'não sabe' o próprio tamanho

Repare que sempre passamos n (o tamanho) junto com o vetor. Isso não é opcional: dentro da função, v é apenas o endereço do começo — não há nenhuma informação guardada sobre quantos elementos existem. O vetor, literalmente, não sabe seu próprio tamanho. (Curiosamente, sizeof(v) funciona na main, onde v é um vetor de verdade, mas não dentro da função, onde v já virou um endereço.) Por isso a regra de ouro: ao passar um vetor para uma função, passe o tamanho junto.

8.2 Protegendo o vetor com const

E se a função só precisa ler o vetor, sem alterá-lo (como uma soma)? Podemos — e devemos — deixar isso explícito com a palavra const. Ela diz ao compilador: "esta função promete não modificar o vetor". Se, por engano, você tentar escrever em v[i], o compilador acusa o erro.

soma_const.c
#include <stdio.h>
#define TAM 5

// const: promete NAO alterar o vetor (so leitura)
int soma(const int v[], int n) {
    int total = 0;
    for (int i = 0; i < n; i++) {
        total += v[i];
        // v[i] = 0;   // se descomentar, o COMPILADOR reclama: v e const!
    }
    return total;
}

int main(void) {
    int numeros[TAM] = {10, 20, 30, 40, 50};
    printf("Soma = %d\n", soma(numeros, TAM));   // 150
    return 0;
}

Usar const em parâmetros de vetor que são só de leitura é uma excelente prática: documenta a intenção, protege contra erros acidentais e ajuda o compilador. Regra prática: se a função vai alterar o vetor, use int v[]; se só vai lê-lo, use const int v[].

As três notações equivalentes de parâmetro-vetor

Você verá vetores declarados como parâmetro de três formas — as duas primeiras são idênticas, e a terceira (ponteiro) fará sentido na Unidade 3:

int soma(int v[], int n)      // forma mais comum e legivel
int soma(int v[5], int n)     // o "5" e IGNORADO pelo compilador (nao confie nele!)
int soma(int *v, int n)       // ponteiro — mesma coisa por baixo (Unidade 3)
Prefira int v[]: é a mais clara. E note por que o 5 da segunda forma é enganoso — ele reforça que o tamanho real precisa vir pelo parâmetro n.

9. Boa prática: #define para o tamanho

Você já viu #define TAM 100 nos exemplos. Esse hábito merece destaque:

#define TAM 100

int main(void) {
    int v[TAM];
    for (int i = 0; i < TAM; i++) { /* ... */ }
    // ...
}

Vantagens de dar um nome ao tamanho, em vez de espalhar o número 100 pelo código:

  • Um lugar só para mudar: se o vetor precisar crescer, altere o #define e tudo se ajusta (declaração e todos os laços).
  • Legibilidade: for (i = 0; i < TAM; i++) diz "percorra o vetor inteiro"; já i < 100 não deixa claro que 100 é o tamanho daquele vetor.
  • Menos bugs: evita o risco de declarar int v[100] e, num laço distante, escrever i < 10 por engano.

Números 'mágicos' são inimigos da manutenção

Um número solto no meio do código (como 100) é chamado de número mágico — ninguém sabe de onde veio nem o que significa. Dar-lhe um nome com #define (ou const) é uma das formas mais baratas de tornar o código profissional.

10. Erros comuns desta semana (resumão)

Checklist de armadilhas

  • Acessar v[n] num vetor de tamanho n (o último válido é v[n-1]).
  • Usar i <= n no laço em vez de i < n (erro de "um a mais", off-by-one).
  • Esquecer o & no scanf de um elemento: scanf("%d", &v[i]);.
  • Inicializar maior = 0 (quebra se todos os valores forem negativos) — use v[0].
  • Divisão inteira na média — faça (double) soma / n.
  • Não passar o tamanho n junto com o vetor para a função.
  • Esperar que passar um vetor copie os dados (ele não copia — a função altera o original!).
  • Confiar no int v[5] do parâmetro como se ele "guardasse" o tamanho (não guarda).
  • %lf na leitura de vetor de double (e não %f).

👥 Quarta — Encontro

Chegue ao encontro tendo estudado o material acima e tendo executado os exemplos — em especial o preenche e o soma, que revelam o comportamento novo dos vetores em funções. Roteiro previsto:

  1. Revisão relâmpago: declaração, índices 0..n-1, o padrão for (i=0; i<n; i++).
  2. Ao vivo: implementamos, do zero, as operações fundamentais (soma, média, máximo, mínimo, busca) numa função cada, praticando a decomposição da Semana 04.
  3. Demonstração do perigo: provocamos, de propósito, um acesso fora do limite para observar o comportamento indefinido — e discutimos por que C não avisa.
  4. O contraste-chave: passagem por valor (Semana 04) × vetor em função (esta semana).

Problema-guia do encontro — boletim da turma: ler N notas (com N fixado por #define), calcular a média, dizer quantas notas ficaram acima da média e apontar a maior e a menor nota — tudo organizado em funções que recebem o vetor e o tamanho.

boletim.c
#include <stdio.h>
#define N 5

// preenche o vetor lendo do teclado (ALTERA o vetor -> sem const)
void ler_notas(double v[], int n) {
    for (int i = 0; i < n; i++) {
        printf("Nota do aluno %d: ", i + 1);
        scanf("%lf", &v[i]);       // %lf na leitura de double; note o &
    }
}

// so LE o vetor -> const
double media(const double v[], int n) {
    double soma = 0.0;
    for (int i = 0; i < n; i++) soma += v[i];
    return soma / n;               // n e int, mas soma e double -> divisao real
}

// conta quantos elementos sao maiores que um limite dado
int conta_acima(const double v[], int n, double limite) {
    int c = 0;
    for (int i = 0; i < n; i++) {
        if (v[i] > limite) c++;
    }
    return c;
}

double maior_nota(const double v[], int n) {
    double maior = v[0];           // "chute" com o primeiro elemento
    for (int i = 1; i < n; i++)
        if (v[i] > maior) maior = v[i];
    return maior;
}

double menor_nota(const double v[], int n) {
    double menor = v[0];
    for (int i = 1; i < n; i++)
        if (v[i] < menor) menor = v[i];
    return menor;
}

int main(void) {
    double notas[N];

    ler_notas(notas, N);

    double m = media(notas, N);
    printf("\nMedia da turma: %.2f\n", m);
    printf("Notas acima da media: %d\n", conta_acima(notas, N, m));
    printf("Maior nota: %.2f\n", maior_nota(notas, N));
    printf("Menor nota: %.2f\n", menor_nota(notas, N));
    return 0;
}

Perguntas para pensar antes do encontro: por que ler_notas não usa const, mas media usa? Se ler_notas recebe apenas o endereço do vetor, como as notas digitadas "aparecem" na main? O que mudaria se esquecêssemos de passar N?


✍️ Sexta — Estudo dirigido

Reserve este tempo para praticar de verdade. Vetores só entram na cabeça com dedos no teclado: escreva, erre nos índices, corrija e execute.

Exercícios guiados (Beecrowd)

Crie/entre na sua conta do Beecrowd e resolva, em C, a trilha de vetores. A faixa 1172–1180 é dedicada a arranjos; resolva na ordem sugerida (dificuldade crescente). Se o número exato variar no site, use a descrição como guia.

Problema O que exercita
1172 Array de Rebeca (Vetor de 10) declarar e imprimir um vetor pequeno
1173 Preenchimento de Vetor I preencher com um padrão simples via laço
1174 Array Selection I percorrer e imprimir só os que satisfazem uma condição
1175 Array Change I inverter / rearranjar posições de um vetor
1176 Fibonacci Array preencher usando valores já calculados no próprio vetor
1177 Array Fill II preenchimento com regra um pouco mais elaborada
1179 Array Fill IV distribuir valores conforme uma condição (par/ímpar)
1180 Menor Valor e Posição mínimo e a posição onde ele ocorre

Como atacar problemas de vetor no Beecrowd

Quase todos seguem o mesmo esqueleto: (1) declarar o vetor com o tamanho do enunciado, (2) preencher com um for, (3) processar com outro for, (4) imprimir. Identifique essas quatro etapas antes de digitar.

Desafios para escrever do zero

  1. Notas acima da média: leia N notas, imprima a média e quantas ficaram acima dela. (Dica: é preciso guardar todas as notas antes de comparar — por isso o vetor!)
  2. Inverter um vetor: leia um vetor e imprima-o de trás para frente. Depois, tente invertê-lo no próprio vetor (trocando v[i] com v[n-1-i]).
  3. Maior e menor: leia um vetor e imprima seu maior e menor elemento (use v[0] como chute inicial).
  4. Busca com posição: leia um vetor e um valor-alvo; diga se ele existe e, se sim, em qual posição (a primeira ocorrência). Use -1 para "não encontrado".
  5. Contar pares e ímpares: leia um vetor de inteiros e conte quantos são pares e quantos são ímpares (v[i] % 2).
  6. Vetor ordenado? leia um vetor e responda se ele está em ordem crescente. (Dica: compare cada v[i] com v[i+1], cuidando para i não ultrapassar n-2.)

Para investigar (curiosidade prática)

  • O limite na prática: num vetor int v[TAM], imprima v[TAM] (uma posição fora do limite). Rode várias vezes. O valor muda? O programa às vezes trava? Relacione com a seção 7 (comportamento indefinido) — e note que "funcionar" uma vez não significa estar correto.
  • soma com e sem const: escreva a soma(const int v[], int n). Agora tente, de propósito, escrever v[i] = 0; dentro dela. O que o compilador diz? Remova o const e repita: qual a diferença? Isso mostra o valor de const como rede de proteção.

✅ Checklist de autoavaliação

Marque com sinceridade — se algum item não estiver ✅, volte à seção correspondente.

  • Explico por que um vetor é melhor que dezenas de variáveis para "muitos valores do mesmo tipo".
  • Sei declarar (int v[5]) e inicializar um vetor (total, parcial e {0}).
  • Entendo que os índices vão de 0 a n−1 e sei explicar por que começam em 0.
  • Percorro um vetor com for (int i = 0; i < n; i++) sem sair dos limites.
  • Leio e escrevo vetores com scanf/printf em laço (com &v[i] e %lf para double).
  • Implemento soma, média, máximo, mínimo, busca linear e contagem.
  • Sei que acessar fora de 0..n−1 é comportamento indefinido e por que C não avisa.
  • Explico por que passar um vetor a uma função difere da passagem por valor da Semana 04, e por que passo o tamanho junto.
  • Uso const em parâmetros de vetor somente de leitura.

🔗 Referências e para se aprofundar

  • Material 2026.1 — Aula 05: Vetores (Arrays).
  • BACKES, André. Linguagem C: completa e descomplicada (capítulo de vetores/arranjos).
  • KERNIGHAN, B.; RITCHIE, D. The C Programming Language (o clássico "K&R"), cap. 1 (vetores) e cap. 5 (a relação entre vetores e ponteiros).
  • MIZRAHI, Victorine V. Treinamento em Linguagem C (vetores).
  • Referência: cppreference — arrays (avançado, bom para consultar detalhes).
  • Prática: Beecrowd — trilha de vetores (faixa 1172–1180).
  • Retomada útil: Semana 04 — Funções (passagem por valor) e o plano de curso.

Antes de seguir para a Semana 08

Você acabou de conhecer sua primeira estrutura de dados — e um vetor de char tem um nome especial: string (uma cadeia de caracteres, isto é, um texto). Tudo o que você aprendeu aqui — índices de 0 a n−1, percorrer com for, passar para funções pelo endereço, o perigo dos limites — vale igualzinho para strings. Na Semana 08 veremos o que há de especial nelas (o marcador de fim '\0', as funções de <string.h>, a leitura de texto) e por que, no fundo, uma string é apenas um vetor de char. Domine os vetores agora: metade do caminho para as strings já estará andado.