Resumo
Esta aula abre a oitava e última unidade do curso, dedicada aos programas maiores. Explica seu propósito: organizar, verificar e depurar programas que já não cabem em um arquivo nem na cabeça; apresenta suas três aulas e o fio que as une, que fecha o círculo aberto na primeira aula do curso (especificar, construir, verificar); recorda o que a unidade dá por sabido, que é o curso inteiro; formula o problema que a unidade resolve, o de um programa de um só arquivo que funciona com os dados com que foi testado e cala um defeito na borda de sua especificação; antecipa a diferença entre testar e demonstrar; e mostra aonde conduz, no projeto final e em Programação em C++ II.
Objetivos de aprendizagem
- Descrever a sequência de conteúdos da unidade e explicar o que cada aula traz à seguinte.
- Recordar, com um exemplo, a diferença entre declarar e definir uma função, o contrato que a especifica e as etapas (compilação e ligação) que convertem vários arquivos em um programa.
- Antecipar, com um exemplo, a diferença entre testar um programa com alguns casos e demonstrar que ele é correto para todos os admissíveis.
- Reconhecer o que se espera saber fazer ao terminar a unidade e o curso, e distingui-lo do que se aprenderá em Programação em C++ II.
Avaliação de entrada
Antes de percorrer a unidade, convém medir o ponto de partida. Esta avaliação não é pontuada: orienta o estudo. As sete primeiras perguntas verificam o que a unidade dá por sabido (declarar e definir, a pré-condição, o contrato de uma função da unidade 6, as mensagens do ligador, os casos de uma busca binária, a tabela de rastreamento (teste de mesa) e a leitura fora de um vetor); as três seguintes tocam, na ordem das aulas, as ideias centrais da unidade, e nelas “ainda não sei” é uma resposta honesta. Cada resposta explica o ponto e nomeia a aula que o trata; as mesmas habilidades voltam a ser medidas na aula de síntese.
Antes de começar a unidade, meça seu ponto de partida. É uma autoavaliação breve: não recebe nota e seu resultado fica guardado apenas no seu navegador.
Pergunta 1De unidades anterioresO que faz a linha
int gcd(int a, int b);escrita antes demain?Confunde declaração e definição: sem corpo não há nada que executar, e nenhuma função se executa por estar escrita, mas ao ser chamada.Confunde declarar com chamar: uma chamada não leva os tipos dos parâmetros.Ignora que ao compilador basta a assinatura para verificar uma chamada; a falta do corpo, se ninguém o escreve, é descoberta pelo ligador, não pelo compilador.Uma declaração basta para que o compilador verifique cada chamada; a definição, com o corpo, pode estar mais abaixo ou em outro arquivo. Toda a aula Vários arquivos e bibliotecas próprias se apoia nessa separação: o cabeçalho declara, o arquivo de implementação define.Revisar: Funções
Pergunta 2De unidades anterioresA função
toBase(n, base)tem a pré-condição “n >= 0e2 <= base <= 10”. Quem deve garanti-la?Confunde a pré-condição com a validação de entradas: validar é tarefa da fronteira do programa, não de cada função.Acredita que os comentários são verificados; o compilador os descarta.Não vê que o contrato reparte obrigações; sem ele, ninguém sabe quem se enganou quando algo falha.Pergunta 3De unidades anterioresA função
binarySearch(values, target)da aula 6.4 devolve uma posição detarget, ouvalues.size()se ele não está. Qual é sua pré-condição?Com o vetor vazio, o laço não dá nenhuma iteração e a função devolve 0, que évalues.size(): o caso está coberto pela pós-condição.A função informa a ausência; exigir a presença a tornaria inútil.Com repetidos, a função devolve uma das posições do valor, o que a pós-condição admite.Cada iteração descarta a metade do intervalo comparando com o elemento central, e isso só é válido se o vetor está ordenado. Com dados desordenados, a função responde, sem aviso, algo falso. A pré-condição se escreve no contrato, onde quem chama a vê.Revisar: Buscar e ordenar
Pergunta 4De unidades anterioresUm programa compila sem erros e, ao construir o executável, aparece
undefined reference to `tetrahedral(int)'. Que etapa falhou?Não distingue as mensagens do compilador, que citam um arquivo e uma linha, das do ligador, que citam objetos e nomes.O programa não chegou a existir: sem executável não há execução.Um#includeausente produzwas not declared in this scopeao compilar, não esta mensagem.O compilador aceitou cada chamada porque viu uma declaração; o ligador procurou a definição em todos os objetos e nas bibliotecas, e não a encontrou. A aula Vários arquivos e bibliotecas próprias explica suas causas habituais: um arquivo que não foi compilado, ou uma declaração copiada com outro tipo.Revisar: Programas, compiladores e C++
Pergunta 5De unidades anterioresQual destes conjuntos de casos põe melhor à prova uma busca binária?
Confunde quantidade com cobertura: nunca testa a ausência nem as bordas, onde costumam estar os defeitos.Um caso que já passou é o que menos probabilidade tem de descobrir algo novo.São infinitos, ou astronomicamente muitos dentro dos limites do tipo: testar exige escolher.Cada caso exercita uma borda distinta do intervalo : o intervalo vazio desde o começo, o que se reduz a um elemento, os extremos e as três maneiras de não estar. Escolher os casos a partir da especificação, por regiões e bordas, é o tema da aula Testar.Revisar: Buscar e ordenar
Pergunta 6De unidades anterioresQuanto valem
aebdepois deint a{0}; int b{1}; for (int i{0}; i < 4; ++i) { const int t{a + b}; a = b; b = t; }?Conta uma iteração a mais: comi < 4, o corpo se executa quatro vezes, não cinco.Conta uma iteração a menos, o erro de um a mais (off-by-one) simétrico.Esquece quetguarda a soma calculada antes deamudar: na última iteração,arecebe o 3 deb, masbrecebe essa soma, 5, e não o novo valor dea.Pergunta 7De unidades anterioresPor que
std::vector<int> v{1, 2}; std::println("{}", v[2]);para com as opções do curso e, compilado só com-O2, sem os detectores (sanitizers), pode escrever um número qualquer?Acredita que a otimização repara erros; ela só tira verificações e supõe que o programa não viola a norma.Inverte o efeito: a verificação que para o programa é a da biblioteca sem otimizar.É o erro de um a mais dos índices: os de um vetor de dois elementos são 0 e 1.Pergunta 8Um cabeçalho com guardas de inclusão define (não apenas declara)
double scale(double x), seminline, e o incluemmain.cppereport.cpp. O que acontece ao construir o programa?Acredita que as guardas atuam entre arquivos; atuam dentro de cada unidade de tradução.Confunde o arquivo que se compila com o programa inteiro: dentro de cada arquivo há uma só definição.É uma resposta honesta: a aula 8.1 o mostra com a mensagem real do ligador.As guardas impedem que um cabeçalho entre duas vezes em um mesmo arquivo, mas cada.cppé compilado separadamente e recebe sua cópia da definição: o ligador encontra duas. É a regra de uma definição, da aula Vários arquivos e bibliotecas próprias.Pergunta 9Uma função passa em quinhentos testes automáticos escolhidos com cuidado. O que se pode afirmar?
Confunde abundância com demonstração; um defeito em uma borda que nenhum caso tocou sobrevive a qualquer número de casos interiores.Os casos não são uma amostra ao acaso dos defeitos possíveis, e a frequência de acertos não mede a probabilidade de o programa estar certo.É uma resposta honesta: a aula 8.2 começa por esta pergunta.Um teste pode mostrar a presença de um defeito, nunca sua ausência: afirmar a correção para todos os casos exige um argumento, como o invariante da aula 4.3, não uma lista de casos. Os testes bem escolhidos tornam improvável que um defeito comum passe, e por isso valem tanto. A aula Testar desenvolve essa distinção.Revisar: Testar
Pergunta 10Um ponto de interrupção está na linha
total += k;, dentro de um laço, e o programa para ali pela terceira vez. O que indica a linha destacada?Confunde a parada com o passo já dado.Confunde o lugar onde o programa para, que quem depura escolhe, com a causa da falha.É uma resposta honesta: a aula 8.3 trata dos pontos de interrupção e dos passos.
Carregando o conteúdo…