Lógica de
Programação
Um guia completo e didático para quem quer entender como o computador pensa — e como você pode pensar como um programador.
O que é Lógica de Programação?
Antes de escrever qualquer linha de código, é preciso entender o que você está fazendo: dar instruções precisas a uma máquina que não tem intuição.
Um computador é incrivelmente rápido, mas literalmente burro. Ele executa exatamente o que você mandar, nem mais, nem menos. Isso significa que a clareza do seu raciocínio é mais importante do que qualquer linguagem de programação.
A lógica de programação é a base que sustenta tudo. Ela não pertence a nenhuma linguagem específica. Aprenda-a bem e você será capaz de aprender qualquer linguagem com facilidade.
Os exemplos neste guia serão escritos em pseudocódigo e em Python, por ser uma linguagem limpa e próxima do português natural.
Variáveis e Constantes
Uma variável é um nome que aponta para um espaço na memória do computador onde você guarda um valor. Pense nela como uma caixinha com um rótulo.
idade = 25
nome = "Maria"
altura = 1.68
esta_chovendo = TrueO valor de uma variável pode mudar ao longo do programa — daí o nome variável:
pontuacao = 0
pontuacao = pontuacao + 10 # agora vale 10
pontuacao = pontuacao + 5 # agora vale 15Uma constante é um valor que não deve mudar durante a execução. Em Python, a convenção é escrever em maiúsculas para sinalizar essa intenção:
PI = 3.14159
VELOCIDADE_DA_LUZ = 299_792_458 # m/s
TAXA_DE_JUROS = 0.05Boas práticas ao nomear variáveis
| ❌ Evite | ✅ Prefira |
|---|---|
| x | velocidade_inicial |
| d | data_nascimento |
| temp2 | temperatura_media |
| varAuxiliar3 | total_desconto |
Tipos de Dados
Todo valor tem um tipo, que determina o que você pode fazer com ele. Somar dois números é diferente de juntar duas palavras.
Tipos Primitivos
| Tipo | Descrição | Exemplo |
|---|---|---|
| int | Número inteiro | 42, -7, 0 |
| float | Número decimal | 3.14, -0.5, 2.0 |
| str | Texto (string) | "olá", "Python" |
| bool | Verdadeiro ou Falso | True, False |
# Inteiros e floats
filhos = 3
preco = 19.99
# Strings: texto entre aspas
cidade = "São Paulo"
mensagem = 'Olá, mundo!'
# Booleans: apenas dois valores possíveis
logado = True
admin = FalseTipagem Dinâmica vs. Estática
Python é dinamicamente tipado: o tipo é inferido pelo valor. Já linguagens como Java são estaticamente tipadas: o tipo deve ser declarado explicitamente.
# Python (dinâmico)
x = 10 # x é int
x = "dez" # agora x é str — válido!// Java (estático)
int x = 10;
x = "dez"; // ERRO de compilação!Conversão de Tipos (Type Casting)
# Usuário digita um texto, mas você precisa do número
entrada = input("Qual sua idade? ") # entrada é str
idade = int(entrada) # converte para int
# Converter número para texto
codigo = 42
mensagem = "Seu código é: " + str(codigo)
# Cuidado com conversões inválidas!
valor = int("abc") # Erro! "abc" não é um númeroOperadores
Operadores são os verbos da lógica: eles realizam ações sobre os dados.
Aritméticos
a = 10
b = 3
print(a + b) # 13 → adição
print(a - b) # 7 → subtração
print(a * b) # 30 → multiplicação
print(a / b) # 3.33 → divisão real
print(a // b) # 3 → divisão inteira (quociente)
print(a % b) # 1 → módulo (resto da divisão)
print(a ** b) # 1000 → potenciação% é muito útil! Ele responde: "qual o resto quando divido a por b?" Use-o para saber se um número é par (n % 2 == 0), para criar ciclos ou para embrulhar índices.Comparação
10 > 5 # True
10 < 5 # False
10 == 10 # True (igual)
10 != 7 # True (diferente)
10 >= 10 # True (maior ou igual)
5 <= 3 # False (menor ou igual)Lógicos
# AND: ambas precisam ser True
pode_dirigir = (idade >= 18) and tem_carteira # True
# OR: pelo menos uma precisa ser True
pode_pagar = tem_dinheiro or tem_cartao # True
# NOT: inverte o valor
esta_aberto = not esta_fechado # TrueEstruturas de Controle
Por padrão, um programa executa linha por linha, de cima para baixo. As estruturas de controle permitem desviar esse fluxo: tomar decisões e repetir ações.
Condicionais — if, elif, else
A estrutura condicional básica: "se isso, faça aquilo; senão, faça outra coisa".
temperatura = 38.5
if temperatura > 39:
print("Febre alta! Vá ao médico.")
elif temperatura > 37.5:
print("Febre moderada. Descanse e tome água.")
elif temperatura > 36:
print("Temperatura normal.")
else:
print("Temperatura abaixo do normal. Agasalhe-se.")Como o computador lê isso:
- Testa a primeira condição. Se for verdadeira, executa o bloco e pula todo o resto.
- Se for falsa, testa a próxima condição (
elif). - Se nenhuma for verdadeira, executa o
else.
# Condicionais aninhadas
nota = 7.5
frequencia = 80
if frequencia >= 75:
if nota >= 7:
print("Aprovado!")
elif nota >= 5:
print("Recuperação.")
else:
print("Reprovado por nota.")
else:
print("Reprovado por falta.")Laços de Repetição
while — repete enquanto uma condição for verdadeira
contador = 1
while contador <= 5:
print(f"Contagem: {contador}")
contador += 1
# Use while quando não sabe de antemão quantas repetições serão necessárias:
while True:
senha = input("Digite sua senha: ")
if senha == senha_correta:
print("Acesso liberado!")
break
print("Senha incorreta. Tente novamente.")for — repete para cada item de uma sequência
frutas = ["maçã", "banana", "laranja", "uva"]
for fruta in frutas:
print(f"Eu gosto de {fruta}.")
# range(início, fim, passo)
for i in range(1, 11, 2):
print(i) # 1, 3, 5, 7, 9break e continue
# break: interrompe o laço imediatamente
numeros = [7, 3, 11, 4, 9, 2]
for n in numeros:
if n % 2 == 0:
print(f"Primeiro par encontrado: {n}")
break
# continue: pula para a próxima iteração
for n in range(10):
if n % 2 == 0:
continue # pula os pares
print(n) # 1, 3, 5, 7, 9Funções
Uma função é um bloco de código nomeado que realiza uma tarefa específica e pode ser reutilizado.
Reutilização: escreva uma vez, use várias vezes.
Organização: divida o problema em partes menores.
Legibilidade: código com funções bem nomeadas se lê quase como texto.
Manutenção: para corrigir um bug, basta alterar em um único lugar.
Anatomia de uma Função
def calcular_media(nota1, nota2, nota3):
"""Calcula a média aritmética de três notas."""
soma = nota1 + nota2 + nota3
media = soma / 3
return media
resultado = calcular_media(8.0, 7.5, 9.0)
print(f"Média: {resultado:.2f}") # Média: 8.17Parâmetros e Valor Padrão
def saudar(nome, saudacao="Olá"): # valor padrão
return f"{saudacao}, {nome}!"
print(saudar("Ana")) # Olá, Ana!
print(saudar("Carlos", "Oi")) # Oi, Carlos!Escopo de Variáveis
Variáveis criadas dentro de uma função não existem fora dela. Funções são caixas pretas que recebem entradas e produzem saídas, sem interferir no resto do programa.
def calcular():
resultado = 42 # variável LOCAL
return resultado
calcular()
print(resultado) # Erro! 'resultado' não existe aqui foraExemplo prático: validador de senha
def validar_senha(senha):
if len(senha) < 8:
return False, "Senha muito curta (mínimo 8 caracteres)"
tem_numero = any(c.isdigit() for c in senha)
if not tem_numero:
return False, "Senha deve conter pelo menos um número"
tem_maiuscula = any(c.isupper() for c in senha)
if not tem_maiuscula:
return False, "Senha deve conter pelo menos uma letra maiúscula"
return True, "Senha válida! ✓"
for s in ["abc", "minhasenha", "MinhaSenha1"]:
valida, msg = validar_senha(s)
print(f"{'✓' if valida else '✗'} '{s}': {msg}")Recursão
Recursão é quando uma função chama a si mesma para resolver um problema. É uma técnica elegante para problemas com estrutura repetitiva ou autossimilar.
Toda função recursiva tem dois componentes obrigatórios:
- Caso base: a condição de parada (sem ela, recursão infinita = travamento).
- Caso recursivo: a função chamando a si mesma com uma entrada menor.
Fatorial
def fatorial(n):
if n == 0: # caso base
return 1
return n * fatorial(n - 1) # caso recursivo
print(fatorial(5)) # 120fatorial(5)
= 5 × fatorial(4)
= 4 × fatorial(3)
= 3 × fatorial(2)
= 2 × fatorial(1)
= 1 × fatorial(0) = 1 ← caso base!
→ 5 × 4 × 3 × 2 × 1 = 120Fibonacci
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
for i in range(10):
print(fibonacci(i), end=" ")
# 0 1 1 2 3 5 8 13 21 34Recursão vs. Iteração
| Iteração | Recursão | |
|---|---|---|
| Velocidade | Geralmente mais rápida | Pode ser mais lenta |
| Memória | Usa menos memória | Cada chamada usa a pilha |
| Legibilidade | Mais verbosa às vezes | Mais elegante para certos problemas |
| Risco | Laço infinito | Stack overflow |
Estruturas de Dados Básicas
Estruturas de dados são formas de organizar e armazenar informações para que possam ser acessadas e modificadas eficientemente.
Arrays (Vetores)
Uma coleção ordenada de elementos acessada por índice, começando em 0.
alunos = ["Ana", "Bia", "Carlos", "Davi", "Eva"]
# [0] [1] [2] [3] [4]
print(alunos[0]) # "Ana" — primeiro elemento
print(alunos[-1]) # "Eva" — último elemento
print(alunos[1:3]) # ["Bia", "Carlos"] — fatiamento
alunos.append("Felipe") # adicionar ao final
alunos.remove("Bia") # remover por valor
print(len(alunos)) # 5Pilhas e Filas
Pilha (Stack) — LIFO: Last In, First Out
O último a entrar é o primeiro a sair. Pense em uma pilha de pratos: você só retira o do topo.
pilha = []
pilha.append("A") # push
pilha.append("B")
pilha.append("C")
print(pilha) # ['A', 'B', 'C']
topo = pilha.pop() # pop → remove do topo
print(topo) # 'C'
# Caso de uso: validar parênteses balanceados
def parenteses_balanceados(expr):
pilha = []
pares = {')': '(', ']': '[', '}': '{'}
for c in expr:
if c in '([{': pilha.append(c)
elif c in ')]}':
if not pilha or pilha[-1] != pares[c]: return False
pilha.pop()
return len(pilha) == 0Fila (Queue) — FIFO: First In, First Out
O primeiro a entrar é o primeiro a sair. Pense em uma fila de banco.
from collections import deque
fila = deque()
fila.append("João") # enqueue
fila.append("Maria")
fila.append("Pedro")
proximo = fila.popleft() # dequeue
print(proximo) # 'João' — primeiro que entrouDicionários (Mapas)
Armazena pares de chave → valor. O acesso é feito pelo nome (chave), não pela posição.
aluno = {
"nome": "Lucas",
"idade": 20,
"notas": [8.5, 9.0, 7.5],
"aprovado": True
}
print(aluno["nome"]) # "Lucas"
aluno["idade"] = 21 # modificar
aluno["email"] = "l@mail" # nova chave
# Frequência de palavras — uso clássico de dicionários
def contar_palavras(texto):
freq = {}
for palavra in texto.lower().split():
freq[palavra] = freq.get(palavra, 0) + 1
return freqNoções de Complexidade
Quando você escreve um algoritmo, duas perguntas são fundamentais: quão rápido ele é? (complexidade de tempo) e quanta memória usa? (complexidade de espaço).
A notação Big O descreve como o desempenho cresce à medida que a entrada cresce, focando no pior caso.
| Notação | Nome | Exemplo prático |
|---|---|---|
| O(1) | Constante | Acessar lista[i] |
| O(log n) | Logarítmica | Busca binária |
| O(n) | Linear | Percorrer uma lista |
| O(n log n) | Linearítmica | Merge Sort |
| O(n²) | Quadrática | Bubble Sort, laços aninhados |
| O(2ⁿ) | Exponencial | Fibonacci recursivo ingênuo |
O(log n) — Busca Binária
Cada passo divide o problema pela metade. 1.000.000 de elementos → apenas ~20 comparações.
def busca_binaria(lista_ordenada, alvo):
"""Funciona apenas em listas ORDENADAS."""
esq, dir = 0, len(lista_ordenada) - 1
while esq <= dir:
meio = (esq + dir) // 2
if lista_ordenada[meio] == alvo: return meio
elif lista_ordenada[meio] < alvo: esq = meio + 1
else: dir = meio - 1
return -1O(n²) — Bubble Sort
def bubble_sort(lista):
n = len(lista)
for i in range(n): # O(n)
for j in range(n - 1): # O(n) → total: O(n²)
if lista[j] > lista[j + 1]:
lista[j], lista[j + 1] = lista[j + 1], lista[j]
return lista
# 1.000 elementos → ~1.000.000 operações
# 10.000 elementos → ~100.000.000 operações !Memoização — de O(2ⁿ) para O(n)
def fibonacci_memo(n, memo={}):
if n in memo: return memo[n] # O(1) — já calculado
if n <= 1: return n
memo[n] = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo)
return memo[n]
print(fibonacci_memo(50)) # Instantâneo!
# Sem memoização: fibonacci(50) = trilhões de operaçõesConclusão
| Conceito | O que faz |
|---|---|
| Variáveis e Tipos | Armazenam e classificam dados |
| Operadores | Manipulam e comparam dados |
| Condicionais | Tomam decisões |
| Laços | Repetem ações |
| Funções | Organizam e reutilizam código |
| Recursão | Resolvem problemas autossimilares |
| Estruturas de Dados | Organizam coleções de dados |
| Complexidade | Medem a eficiência de algoritmos |
Esses conceitos formam a gramática universal da programação. Toda linguagem — Python, JavaScript, Java, C++, Rust — os implementa de formas ligeiramente diferentes, mas a essência é sempre a mesma.
Próximos Passos
- Orientação a Objetos — modelar o mundo em classes e objetos
- Estruturas de Dados Avançadas — árvores, grafos, heaps
- Algoritmos Clássicos — ordenação, busca, grafos
- Paradigmas — funcional, reativo, concorrente
- Sistemas — memória, processos, redes
"Todo expert foi um dia um iniciante. A diferença é que o expert não desistiu quando ficou difícil."
Linguagens de
Programação
Um guia aprofundado sobre seis linguagens que definem paradigmas, moldaram a indústria e continuam relevantes — cada uma a seu modo.
Java é uma linguagem orientada a objetos, fortemente tipada, compilada para bytecode e executada sobre a JVM (Java Virtual Machine). Com o princípio central de "Write Once, Run Anywhere", o mesmo código compilado roda em qualquer plataforma que tenha uma JVM instalada.
Seu modelo de OO é considerado clássico: encapsulamento, herança, polimorfismo e abstração são cidadãos de primeira classe na linguagem.
- Back-end CorporativoSistemas bancários, ERPs e e-commerce de grande porte. Spring Boot tornou microsserviços e APIs REST extremamente produtivos.
- Aplicações AndroidPor anos a linguagem oficial do Android. Bilhões de dispositivos rodam código Java diariamente.
- Big Data & DistribuídoApache Hadoop, Kafka e Spark são escritos em Java/Scala. A JVM provou-se confiável para workloads massivos.
- Alta DisponibilidadeLinkedIn e Netflix (partes do back-end) confiam em Java por sua estabilidade e vasto ecossistema de monitoramento.
Haskell é uma linguagem puramente funcional, com tipagem estática forte e avaliação lazy (preguiçosa) por padrão. Criada por um comitê de pesquisadores para consolidar os avanços em linguagens funcionais da época.
Haskell abraça a pureza funcional de forma radical: funções não têm efeitos colaterais, dados são imutáveis por padrão e o sistema de tipos elimina muitos bugs em tempo de compilação — antes mesmo de o programa rodar.
- Compiladores e FerramentasO GHC é um dos compiladores mais avançados do mundo. O Pandoc (conversor universal de documentos) é escrito em Haskell.
- Sistemas Financeiros CríticosStandard Chartered, Barclays e Facebook (equipe anti-spam) usam Haskell onde bugs custam muito caro.
- BlockchainA blockchain Cardano tem seu núcleo e linguagem de smart contracts (Plutus) desenvolvidos em Haskell.
- Pesquisa Acadêmica (PLT)Haskell é a linguagem franca de pesquisadores em teoria de linguagens de programação. Novas ideias são prototipadas em Haskell antes de migrarem para outras linguagens.
Python é uma linguagem interpretada, dinamicamente tipada e multiparadigma, com sintaxe minimalista projetada para ser legível como pseudocódigo. Adota o princípio das "baterias inclusas" (batteries included): biblioteca padrão vastíssima e um ecossistema de pacotes (PyPI) com mais de 500 mil projetos.
- Ciência de Dados & MLNumPy, Pandas, Scikit-learn, TensorFlow, PyTorch e Jupyter Notebooks são ferramentas universais de data scientists ao redor do mundo.
- Automação & ScriptingDevOps e sysadmins usam Python para automatizar tarefas: deploy, web scraping (BeautifulSoup, Scrapy), integração de sistemas.
- Desenvolvimento WebDjango (Instagram, Pinterest) e FastAPI tornam Python uma escolha sólida para back-end web.
- Computação CientíficaSubstituiu MATLAB em muitos laboratórios. A imagem do buraco negro M87 foi processada com código Python.
:=).C é uma linguagem imperativa, procedural e de baixo nível, criada originalmente para escrever o sistema operacional Unix. É considerada a "mãe" das linguagens modernas — C++, Java, C#, Go, Rust e Python são herdeiros diretos ou indiretos de sua filosofia.
C opera muito próximo ao hardware: o programador controla manualmente a alocação e liberação de memória, pode manipular ponteiros diretamente e tem controle fino sobre como os dados são representados.
- Sistemas OperacionaisO kernel do Linux, o Windows NT e o macOS (XNU) são escritos predominantemente em C. O próprio Unix foi reescrito em C — um evento revolucionário.
- Embarcados & FirmwareMicrocontroladores em automóveis, marca-passos e aviação rodam firmware em C. Quando recursos são contados em kilobytes, C é a escolha natural.
- Compiladores e RuntimesCPython (Python), o runtime do PHP, o interpretador do Ruby — todos escritos em C. A linguagem que roda outras linguagens.
- Bancos de DadosPostgreSQL, SQLite e MySQL são escritos em C. Bancos precisam de desempenho máximo e controle preciso de memória.
printf("Hello, World!\n") foi popularizado pelo livro "The C Programming Language" (Kernighan & Ritchie, 1978) e tornou-se o ritual de iniciação universal de qualquer programador.TypeScript é um superset tipado de JavaScript, desenvolvido pela Microsoft para resolver o maior problema do JS em escala: a ausência de tipos estáticos. Todo código JavaScript válido é também TypeScript válido.
TypeScript adiciona interfaces, enums, generics e um sistema de tipos estrutural extremamente poderoso. O compilador (tsc) transpila TypeScript para JavaScript puro, que roda em qualquer ambiente.
- Web de Grande EscalaAngular, React (com TS) e Vue 3 têm suporte de primeira classe. Slack, Airbnb e Asana migraram suas bases de código para TypeScript.
- Back-end Node.jsNestJS e Deno (que usa TS nativamente) tornaram o desenvolvimento back-end com TypeScript uma realidade madura e produtiva.
- Aplicativos MobileReact Native com TypeScript é uma das principais stacks para mobile multiplataforma. O app Discord para mobile é construído com essa combinação.
- Monorepos Full-StackA capacidade de compartilhar tipos entre front-end e back-end no mesmo repositório é uma vantagem enorme em times grandes.
Zig é uma linguagem de sistemas imperativa, compilada e de baixo nível, criada com o objetivo de ser um substituto moderno para C: sem macros, sem pré-processador, sem exceções, sem runtime oculto — apenas código simples, previsível e extremamente eficiente.
Zig não é apenas uma linguagem — é também um toolchain: seu compilador consegue compilar código C e C++ e serve como um cross-compiler de alta qualidade.
- Sistemas & EmbarcadosCompete diretamente com C em firmware, kernels e sistemas de baixo nível. Sem GC, sem runtime, sem surpresas — o programador vê exatamente o que acontece.
- Substituição de CZig pode importar headers C diretamente com
@cImportsem bindings manuais, permitindo reescrever projetos C incrementalmente. - Cross-CompilationO Bun (runtime JavaScript ultrarrápido) usa Zig como toolchain para compilar para múltiplas plataformas simultaneamente.
- Game DevelopmentA leveza e o controle de Zig atraem desenvolvedores de engines que precisam de desempenho máximo sem o overhead de C++.
!T) — funções que podem falhar retornam um tipo que obriga o chamador a tratar o erro explicitamente. Mais honesto que C e mais simples que Rust.Comparativo Rápido
| Linguagem | Paradigma | Tipagem | GC | Nível | Ponto Forte |
|---|---|---|---|---|---|
| Java | OO | Estática forte | Sim | Alto | Ecossistema corporativo |
| Haskell | Funcional pura | Estática forte | Sim | Alto | Correção formal |
| Python | Multiparadigma | Dinâmica | Sim | Alto | Versatilidade e velocidade |
| C | Procedural | Estática fraca | Não | Baixo | Desempenho e controle |
| TypeScript | Multiparadigma | Estática gradual | Sim (JS) | Alto | Web em escala |
| Zig | Imperativa | Estática forte | Não | Baixo | Substituto moderno do C |
Conclusão
Não existe linguagem perfeita — existe a linguagem certa para o problema certo.
Java garante que sistemas bancários rodem há décadas sem surpresas. Haskell garante que código compilado seja matematicamente correto. Python garante que uma ideia saia do papel em minutos. C garante que o firmware do seu carro responda em microssegundos. TypeScript garante que uma equipe de 200 engenheiros não quebre a produção ao refatorar. E Zig garante que a próxima geração de ferramentas de sistema seja tão rápida quanto C, mas sem seus fantasmas históricos.
Conhecer os paradigmas por trás de cada linguagem é mais valioso do que decorar sua sintaxe — pois os paradigmas migram, se influenciam e reaparecem em novas formas ao longo de toda a história da computação.