4 erros de programação C++ que são difíceis de encontrar

4 erros de programação C++ que são difíceis de encontrar

Uma parte significativa do trabalho de um programador é encontrar e eliminar erros. Aplica-se o princípio de que os erros devem ser encontrados o mais cedo possível no processo de desenvolvimento. Claro, é ainda melhor evitar erros em primeiro lugar. Este artigo mostra quatro erros típicos que geralmente não são detectados pelo compilador e, portanto, são difíceis de encontrar. Se você não sabia desses erros antes, poderá programar um pouco melhor depois de ler este artigo.

Resumo

  • Variável não inicializada: Em C++, as variáveis ​​não são inicializadas automaticamente quando são criadas, o que pode levar a um comportamento indefinido.
  • Confusão entre operador de atribuição e operador de comparação (=/==): A confusão pode levar a erros fatais porque o operador de atribuição (=) é usado em vez do operador de comparação (==).
  • Sem interrupção na instrução switch: A ausência da instrução break em uma instrução switch pode resultar na execução de todas as instruções a seguir após a correspondência da constante case.
  • Divisão Inteira: Ao dividir valores inteiros, o resultado também se torna um número inteiro, o que pode resultar no corte da parte fracionária.

Como surgem os erros?

Para que um erro se torne um erro de tempo de execução, ele deve permanecer sem ser detectado pelo compilador. Ajude o compilador definindo o nível de aviso o mais alto possível. Avisos do compilador podem ser desagradáveis, mas ainda mais desagradáveis ​​são erros sutis de tempo de execução. Você só deve ignorar os avisos se tiver um motivo muito convincente para fazê-lo.

Abaixo você encontrará quatro exemplos de erros típicos de C++ que podem não ser reconhecidos pelo compilador. É melhor experimentar esses exemplos em seu ambiente de desenvolvimento para poder ver se o seu compilador o avisaria sobre um ou outro erro.

Variável não inicializada

Em C++, as variáveis ​​não são inicializadas automaticamente quando são criadas. Se você trabalhar com uma variável não inicializada, o comportamento do programa será indefinido. No exemplo a seguir, a variável counter pode ter qualquer valor que provavelmente seja maior que 10. Provavelmente é por isso que o loop while nem sequer é inserido. Em qualquer caso, o programa não se comportará como originalmente pretendido.

Variável não inicializada
int counter;

while(counter < 10) { cout << counter; ++counter; }

O exemplo abaixo mostra o código corrigido. O número inteiro é inicializado explicitamente como 0 e os números de 0 a 9 são exibidos no console.

Variável inicializada

int counter = 0;

while(counter < 10) { cout << counter; ++counter; }

Em C++, as variáveis ​​não são inicializadas automaticamente, então você mesmo deve atribuir um valor inicial a cada variável.

Confusão entre operador de atribuição e operador de comparação (=/==)

O operador de atribuição é usado para atribuir um valor específico a uma variável ou objeto, geralmente retornando uma referência ao objeto que foi atribuído. O operador de comparação é usado para comparar duas variáveis ​​ou objetos entre si, o resultado é um booleano que diz se os objetos comparados são iguais. Uma confusão pode ter consequências graves, como ilustra o exemplo a seguir.

Em vez de verificar se o valor da variável contador é 5, é atribuído à variável o valor 5. A condição é verdadeira porque o valor de retorno da atribuição é 5 e um número inteiro diferente de 0 é avaliado como verdadeiro. Como isso acontece em cada loop executado, a condição de término (contador <10) nunca é atingida e o programa é executado em um loop infinito que gera ciclicamente “5” para o console. int counter = 0;

while(counter < 10) { // do some stuff here... // ... // here is a quick check if(counter = 5) { cout << counter; } ++counter; }

Em contraste, no exemplo correto a seguir, “5” é emitido apenas uma vez, conforme desejado pelo programador.

Comparação correta

int counter = 0;

while(counter < 10) { // do some stuff here... // ... // here is a quick check if(counter == 5) { cout << counter; } ++counter; }

Portanto, sempre certifique-se de usar dois “=”, ou seja, o operador de comparação, ao fazer comparações.

Sem interrupção na instrução switch

A instrução switch é usada para diferenciar claramente os casos com base em valores inteiros. Um erro típico de programação que acontece frequentemente aqui é esquecer o intervalo. Se uma constante case corresponder ao valor consultado, todas as instruções a seguir serão executadas até que ocorra uma quebra. O exemplo a seguir mostra como isso não se destina:

Faltam pausas

// get random number between 1 and 10
int myNumber = rand % 10 + 1;

// check if this is an important number to me
switch(myNumber)
{
case 1: cout << "Meine liebste Zahl wurde gezogen!"; case 3: cout << "Meine zweitliebste Zahl wurde gezogen!"; default: cout << "Eine für mich unbedeutende Zahl wurde gezogen."; }

Se o gerador aleatório selecionar 1 aqui, todas as três sentenças serão geradas porque as seções de caso não têm uma quebra final. Se você estiver ciente disso, também poderá usar isso para criar uma conexão OR, que pode, no entanto, ser considerada uma técnica avançada.

Bloqueio de interruptor correto

// get random number between 1 and 10
int myNumber = rand % 10 + 1;

// check if this is an important number to me
switch(myNumber)
{
case 1:
cout << "Meine liebste Zahl wurde gezogen!"; break; case 3: cout << "Meine zweitliebste Zahl wurde gezogen!"; break; default: cout << "Eine für mich unbedeutende Zahl wurde gezogen."; break; }

Aqui as quebras foram definidas corretamente e o código faz o que deveria. Para evitar erros como os acima, você pode adquirir o hábito de quebrar imediatamente cada caso e padrão antes de escrever o código real. Com a seguinte regra para iniciantes, esse erro não pode acontecer com você.

Dentro de uma instrução switch, defina imediatamente um break para cada caso e o padrão. Remova-o apenas se tiver certeza do que acontecerá.

Divisão inteira

Um problema numérico clássico pode surgir quando você faz divisão com valores inteiros. Se tanto o dividendo quanto o divisor forem números inteiros, o resultado também será um número inteiro e isso significa que a parte decimal será cortada. Mesmo se você atribuir o resultado a uma variável de ponto flutuante, isso não muda nada:

Resultado inesperado em uma divisão

int dividend = 6;
int divisor = 4;

double result = dividend / divisor;
cout << result; // result is 1.0!

Ao contrário do esperado, a variável de resultado aqui contém 1,0, pois o resultado da divisão já é um número inteiro que é convertido silenciosamente (“convertido”) em duplo. Existem várias maneiras de contornar esse problema. Uma delas é usar double ou float para dividendo e divisor:

Alternativa correta I

double dividend = 6;
double divisor = 4;

double result = dividend / divisor;
cout << result; // result is 1.5

Se você tiver apenas o dividendo e o divisor disponíveis como números inteiros, não será necessário criar uma variável intermediária. Aqui basta simplesmente converter um dos dois valores para double ou float:

Alternativa correta II

int dividend = 6;
int divisor = 4;

double result = static_cast(dividend) / divisor;
cout << result; // result is 1.5

Neste exemplo, o resultado da divisão já é duplo e portanto nenhuma casa decimal é perdida na atribuição ao resultado.

Conclusão

Agora você aprendeu sobre 4 erros típicos de programação em C++. Mesmo em um ambiente profissional, a probabilidade de encontrar um desses erros é relativamente alta, especialmente com bases de código maiores. Como você viu, esses erros são muito fáceis de evitar.

O artigo foi útil para você? Se sim, ajude-nos e compartilhe!

Programação

Conteúdo Relacionado

Voltar para o blog

Deixe um comentário

Os comentários precisam ser aprovados antes da publicação.