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 comscanf/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:
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.
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 é:
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:
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 é:
Observe cada parte, porque este for aparecerá em praticamente todo programa com
vetores:
i = 0— começa no primeiro índice (0);i < n— continua enquantoifor menor quen(e para emn-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!)
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.
#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:
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:
#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!
#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.
#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)
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:
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
#definee tudo se ajusta (declaração e todos os laços). - Legibilidade:
for (i = 0; i < TAM; i++)diz "percorra o vetor inteiro"; jái < 100não deixa claro que100é o tamanho daquele vetor. - Menos bugs: evita o risco de declarar
int v[100]e, num laço distante, escreveri < 10por 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 tamanhon(o último válido év[n-1]). - Usar
i <= nno laço em vez dei < n(erro de "um a mais", off-by-one). - Esquecer o
&noscanfde um elemento:scanf("%d", &v[i]);. - Inicializar
maior = 0(quebra se todos os valores forem negativos) — usev[0]. - Divisão inteira na média — faça
(double) soma / n. - Não passar o tamanho
njunto 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). -
%lfna leitura de vetor dedouble(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:
- Revisão relâmpago: declaração, índices
0..n-1, o padrãofor (i=0; i<n; i++). - 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.
- 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.
- 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.
#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.
| Nº | 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¶
- Notas acima da média: leia
Nnotas, imprima a média e quantas ficaram acima dela. (Dica: é preciso guardar todas as notas antes de comparar — por isso o vetor!) - 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]comv[n-1-i]). - Maior e menor: leia um vetor e imprima seu maior e menor elemento (use
v[0]como chute inicial). - 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
-1para "não encontrado". - Contar pares e ímpares: leia um vetor de inteiros e conte quantos são pares e
quantos são ímpares (
v[i] % 2). - Vetor ordenado? leia um vetor e responda se ele está em ordem crescente. (Dica:
compare cada
v[i]comv[i+1], cuidando parainão ultrapassarn-2.)
Para investigar (curiosidade prática)¶
- O limite na prática: num vetor
int v[TAM], imprimav[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. somacom e semconst: escreva asoma(const int v[], int n). Agora tente, de propósito, escreverv[i] = 0;dentro dela. O que o compilador diz? Remova oconste repita: qual a diferença? Isso mostra o valor deconstcomo 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/printfem laço (com&v[i]e%lfpara 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
constem 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.