CS50x em Português - Aula 1 - C
CS50
Da semana 0 para a linguagem C 0:44
A aula retoma o que foi visto na semana 0 com o Scratch, aquela linguagem gráfica de arrastar e soltar blocos, e explica que as mesmas ideias fundamentais, como funções, variáveis, laços e condicionais, vão continuar valendo agora em C. A sintaxe vai parecer mais assustadora e difícil de memorizar no início, mas a prática traz a memória muscular necessária. A comparação com o hack do MIT, que ligou um bebedouro a um hidrante com a placa dizendo que estudar lá é como beber de uma mangueira de incêndio, serve para descrever a sensação de sobrecarga que aprender programação pode causar no começo.
Código-fonte, código de máquina e compilador 3:30
O texto que o programador escreve, chamado código-fonte, é compreensível para humanos com treino, mas os computadores só entendem código de máquina, feito de zeros e uns. Para converter um no outro existe um software chamado compilador, que recebe código-fonte como entrada e produz código de máquina como saída. Esse processo é comparado ao modelo de caixa preta apresentado na semana anterior, em que uma entrada passa por um processo e gera uma saída.
Conhecendo o VS Code 5:01
A ferramenta usada agora é o Visual Studio Code, ou VS Code, muito popular entre programadores profissionais e disponível gratuidamente para instalação em Mac ou PC. No início do curso é usada uma versão baseada em nuvem, acessível por navegador, para evitar problemas técnicos, mas ao final do período o aluno pode migrar para a versão instalada em sua própria máquina. A interface tem uma área para escrever código com abas, um explorador de arquivos e pastas à esquerda, e uma janela de terminal no canto inferior direito, onde os comandos são digitados. Essa combinação é chamada de interface gráfica do usuário, ou GUI, enquanto a parte de comandos digitados é a interface de linha de comando, ou CLI.
Criando e executando o primeiro programa 9:00
O primeiro programa é escrito no arquivo hello.c, seguindo a convenção de nomes em minúsculas e sem espaços. O código usa a linha include stdio.h, depois int main void, e dentro das chaves a instrução printf com o texto hello, world entre aspas, barra invertida n e ponto e vírgula no final. Para transformar esse código-fonte em um programa executável, usa-se o comando make hello, que aciona o compilador e cria um arquivo chamado hello, sem gerar nenhuma saída visível quando tudo está correto. Depois, o comando ./hello executa o programa, imprimindo hello world na tela, e é preciso recompilar sempre que o código-fonte for alterado para que as mudanças tenham efeito.
Comparando com o Scratch e a sintaxe do C 14:33
O bloco amarelo do Scratch que iniciava o programa corresponde ao código de configuração inicial em C, enquanto o bloco roxo de dizer corresponde à função printf, cujo F significa formatar a saída impressa. Os parênteses da função em C se parecem com o formato oval usado no Scratch para representar entradas. Em C é preciso colocar o texto entre aspas duplas para deixar claro o que deve ser impresso, e terminar cada instrução com ponto e vírgula, assim como uma frase termina com ponto final.
Sequências de escape e erros comuns 19:30
A barra invertida seguida de n, chamada sequência de escape, faz o cursor pular para uma nova linha, evitando que o próximo comando apareça colado ao resultado do programa. Outras sequências de escape incluem barra invertida r, que remete ao retorno de carro das máquinas de escrever antigas, e barra invertida aspas duplas, usada para imprimir uma aspa dupla real sem que o computador a confunda com o fim do texto. A aula também mostra o que acontece ao esquecer o ponto e vírgula, gerando uma mensagem de erro que aponta o arquivo, a linha e o caractere exatos do problema, e adianta que esquecer a linha include stdio.h no topo do código provoca um tipo diferente de erro, que será explicado na semana seguinte.
Erro de compilação e arquivos de cabeçalho 24:32
O programa hello.c apresenta um novo erro: a função printf não é reconhecida, mesmo com o ponto e vírgula e o barra n corretos. A explicação é que o C depende de arquivos de cabeçalho, arquivos terminados em .h que contêm código escrito por outras pessoas e que podem ser reaproveitados. Nesse caso, é preciso incluir o arquivo stdio.h, que define a função printf, algo que só se aprende consultando referências, aulas ou documentação, já que não é intuitivo por si só.
Documentação e manual do CS50 27:01
Para consultar essas informações existe uma tradição de páginas de manual oficiais da linguagem C, mas muitas são antigas e difíceis para iniciantes. Por isso o CS50 criou o site manual.cs50.io, que reescreve essa documentação de forma mais simples, mostrando por exemplo as funções da biblioteca stdio.h e explicando em qual arquivo cada função está definida, sua sintaxe e um exemplo de uso. Além dessa documentação oficial, o próprio CS50 criou funções auxiliares, como as da biblioteca cs50.h, entre elas getString e getInt, pensadas para facilitar tarefas que no C puro seriam mais trabalhosas para iniciantes, como obter uma entrada de texto do usuário.
Traduzindo o Scratch para C 31:01
Retomando o programa interativo feito em Scratch na aula anterior, que perguntava o nome do usuário com o bloco ask, o mesmo efeito é reproduzido em C com a função getString do CS50. A frase a ser exibida entra entre parênteses e aspas, e o valor digitado pelo usuário é guardado numa variável chamada answer, criada com a palavra string antes do nome, indicando o tipo de dado. Assim como no Scratch, a lógica é a mesma, mas o C exige mais detalhes de sintaxe, como declarar o tipo da variável e fechar cada instrução com ponto e vírgula.
Exibindo o nome com printf e %s 37:00
Ao tentar imprimir hello seguido da variável answer diretamente dentro das aspas, o programa apenas mostra a palavra answer literalmente, porque o computador executa exatamente o que foi escrito. A solução é usar o símbolo %s como um espaço reservado dentro do texto entre aspas, que será substituído pelo valor da variável informada como segundo argumento de printf, separado por vírgula. Assim, escrevendo printf de hello, %s seguido da variável answer, o programa passa a exibir corretamente hello seguido do nome digitado pelo usuário, como hello David.
Perguntas sobre entradas e cabeçalhos 41:05
Em resposta a perguntas da turma, fica explicado que os arquivos de cabeçalho como cs50.h e stdio.h já vêm pré-instalados no servidor usado no ambiente de programação do curso, por isso o compilador sabe onde encontrá-los. Também se esclarece que tanto o texto fixo entre aspas quanto a variável fornecida a printf são consideradas entradas da função, mesmo vindo de origens diferentes: uma é decidida antecipadamente pelo programador, a outra só é conhecida quando o usuário responde à pergunta feita pelo programa.
Sistemas operacionais e linha de comando 44:00
O ambiente usado no curso roda sobre Linux, um sistema operacional descendente do Unix, muito usado em servidores por ser rápido e não depender necessariamente de interface gráfica. A partir dele são apresentados comandos básicos de linha de comando: ls para listar arquivos, mkdir para criar uma pasta, rm para remover arquivos ou diretórios, mv para mover ou renomear, cp para copiar e cd para entrar em uma pasta. Como demonstração, o arquivo compilado hello é apagado com rm e, em seguida, é criada uma nova pasta chamada hello com mkdir, para organizar os programas que serão feitos ao longo do curso.
Movendo e organizando arquivos no terminal 49:02
Continuando com a linha de comando, o professor usa mv para mover hello.c para dentro da pasta hello, mostrando que o comando espera primeiro a origem e depois o destino. Ele explica que uma barra final no destino deixa claro que se trata de uma pasta, e que o Linux já reconhece isso automaticamente. Depois usa ls para listar o conteúdo, cd para entrar na pasta hello, e mostra como o prompt passa a indicar em qual pasta o usuário está, uma convenção comum a vários sistemas para não perder a noção da localização.
Comandos cd, rm, cp e a pasta pai 53:00
Dentro da pasta hello, o professor recompila com make hello, remove arquivos com rm confirmando com y, e usa mv também para renomear arquivos, como transformar hello.c em old.c e depois voltar ao nome original. Ele cria uma cópia de segurança com cp para backup.c, apenas como demonstração, e depois remove tudo. Explica que dois pontos representam a pasta pai, permitindo mover um arquivo para fora da pasta atual, e que digitar apenas cd sem nada leva direto à pasta padrão do usuário. Uma pergunta da turma esclarece que é possível ter um arquivo e uma pasta com o mesmo nome em locais diferentes sem conflito, desde que não estejam na mesma pasta.
Condicionais em C comparadas ao Scratch 56:01
O professor traduz as estruturas condicionais do Scratch para C, mostrando que o bloco laranja de decisão corresponde ao if em C, escrito com parênteses contendo uma expressão booleana e chaves envolvendo o código a ser executado. Ele explica que as chaves em C funcionam como o encaixe visual das peças do Scratch, e que a indentação de quatro espaços é uma convenção de estilo adotada para manter o código legível entre programadores. Mostra também como implementar if-else e uma cadeia de else if para comparar duas variáveis x e y, verificando se uma é menor, maior ou igual à outra.
Igualdade, atribuição e eficiência do código 1:00:01
Uma distinção importante é feita entre o sinal de igual único, usado para atribuição de valores a variáveis, e o sinal duplo, usado para testar igualdade em condicionais, algo que não existe no Scratch por ser voltado a crianças. O professor aponta que perguntar três condições quando apenas duas são necessárias é um exemplo de mau design, pois desperdiça tempo do computador e do usuário; melhor é usar um bloco else padrão para o terceiro caso. Ele lista outros operadores de C, como maior ou igual, menor ou igual, e diferente de, representado por ponto de exclamação e igual.
Tipos de dados e funções de entrada do cs50.h 1:03:00
Além de strings, C oferece bools, chars, floats, doubles, ints e longs, cada um com um número fixo de bits e, portanto, uma capacidade limitada de representar valores, mesmo sendo o mundo real infinito em possibilidades numéricas. O arquivo cs50.h fornece funções como get_int, get_char, get_float e get_double para obter esses tipos do usuário, e o printf usa marcadores específicos como %c, %f, %i e %li para exibir cada tipo corretamente.
Construindo o programa compare.c 1:09:03
O professor cria um novo programa chamado compare, que pede dois valores inteiros ao usuário, x e y, usando get_int, e compara os dois com uma sequência de if e else if para determinar se x é menor, maior ou igual a y. Ele demonstra a compilação com make compare e a execução com ./compare, ajustando o código a cada teste até cobrir todos os três cenários possíveis. Ao final, discute com a turma por que perguntar três condições separadas, uma por linha, é ineficiente, já que o programa sempre verificaria todas elas mesmo quando a resposta já fosse conhecida, reforçando a importância de estruturas mutuamente exclusivas bem organizadas.
Fluxogramas para representar condicionais 1:14:00
Para quem aprende de forma mais visual, o professor mostra como desenhar um fluxograma equivalente a um trecho de código com condicionais. Um losango representa a expressão booleana, como x é menor que y, e a partir dela saem caminhos de verdadeiro e falso que levam a diferentes instruções de impressão. Ele compara três versões do mesmo programa: uma sem else, que simplesmente não faz nada quando a condição é falsa; uma com else, que cobre o caso contrário; e uma terceira, mais longa, que fazia três perguntas repetidas de forma desnecessária. Ao reorganizar o código usando else if, o fluxograma fica mais curto, porque cada pergunta só é feita se as anteriores forem falsas, evitando perguntas óbvias e otimizando o programa.
Programa agree.c e comparação de caracteres 1:17:00
O professor cria um novo programa chamado agree.c, que pede ao usuário para concordar ou não com termos, usando a função getchar para capturar um único caractere em vez de uma string inteira. Ele compara esse caractere com valores conhecidos usando aspas simples, como c igual a y ou c igual a n, explicando que aspas simples servem para comparar caracteres únicos, enquanto aspas duplas servem para strings de texto. Ele nota que getchar já rejeita entradas com mais de um caractere e pede novamente até o usuário cooperar, o que evita algumas verificações de erro manuais.
Operadores lógicos para evitar repetição 1:20:32
Ao testar o programa, aparece um problema: digitar Y maiúsculo não funciona, só y minúsculo. A solução ingênua seria duplicar o bloco de código para tratar também o Y maiúsculo, mas isso repete uma linha quase idêntica, o que é considerado má prática porque qualquer mudança futura teria que ser feita duas vezes. A solução elegante é usar o operador lógico ou, representado por duas barras verticais, combinando duas expressões booleanas menores em uma só condição, de modo que tanto y quanto Y maiúsculo sejam aceitos. O professor explica também por que usar e comercial duplo para representar e lógico não faria sentido nesse caso, já que uma variável não pode ser minúscula e maiúscula ao mesmo tempo.
Loops while e for em C 1:26:03
O professor mostra como repetir uma ação em C usando loops, já que não existe uma palavra-chave equivalente a repeat do Scratch. Com um loop while, é possível fazer um gato miar três vezes, seja contando de 3 até 0 com decremento, seja de 0 até 3 com incremento, sendo essa segunda forma a convenção mais comum em programação. Ele também apresenta o loop for como uma alternativa mais compacta, que reúne a inicialização da variável, a condição e o incremento em uma única linha, produzindo o mesmo resultado com menos código. Em seguida ele cria de fato o programa cat.c, primeiro copiando e colando a instrução de miado três vezes, depois substituindo essa repetição por um loop while e por um loop for.
Loop infinito e o perigo do while true 1:29:00
O professor mostra que é possível criar um loop que roda para sempre usando while true, já que essa expressão booleana nunca deixa de ser verdadeira. Ao rodar esse código no gato, o terminal começa a imprimir miado sem parar, e a interface do ambiente chega a alertar sobre alto uso de CPU, obrigando a interromper o processo com Ctrl+C. Depois desse incidente, ele reformula o programa para perguntar ao usuário quantas vezes o gato deve miar, usando get_int para capturar esse número em uma variável chamada n, e usando essa variável como limite dentro do loop for, no lugar do valor fixo três.
Validando entradas negativas com continue e break 1:34:30
O professor percebe que o programa aceita valores negativos para n, o que não faz sentido para um número de miados, e tenta impedir isso pedindo novamente o valor quando n é menor que zero. Mas repetir a chamada de get_int manualmente várias vezes é uma solução ruim, porque duplica código e não garante quantas tentativas serão suficientes. A alternativa mais elegante é usar um loop while true combinado com as palavras-chave continue e break, onde continue volta ao início do loop para pedir o valor de novo, e break sai do loop quando o valor for válido. Ao tentar compilar essa versão, porém, aparece um erro dizendo que a variável n não está declarada na linha 19, apesar de ter sido criada dentro do loop, algo que o professor deixa para explicar a seguir.
O problema do escopo da variável 1:39:02
O professor mostra um erro comum: declarar a variável n dentro das chaves de um loop faz com que ela só exista naquele espaço, chamado escopo. Fora daquelas chaves, o programa não reconhece mais n, e o compilador reclama. A solução é declarar n antes do loop, logo abaixo da abertura da função main, para que ela fique disponível em todo o bloco de código.
Simplificando a saída do loop 1:41:02
Depois de corrigir o escopo, o programa volta a funcionar: o usuário pode digitar números negativos repetidamente e o gato só mia quando recebe um valor válido. O professor simplifica a lógica trocando o uso combinado de continue e break por uma única condição direta, saindo do loop quando n for maior ou igual a zero, tornando o código mais limpo e fácil de ler.
O loop do-while 1:42:31
Além do while comum, existe o loop do-while, que executa o bloco de código primeiro e só depois verifica a condição, no final em vez do início. Isso é útil quando se quer fazer algo pelo menos uma vez, como perguntar um valor ao usuário. O professor ilustra a diferença com uma piada visual baseada nos desenhos do Papa-Léguas e Coiote: um verifica a condição antes de agir, o outro só depois, quando já é tarde.
Criando funções próprias em C 1:45:01
Retomando a ideia do Scratch, o professor mostra como criar uma função chamada meow em C, que não recebe entrada nem retorna valor, apenas produz o efeito de imprimir miau na tela. Depois, essa função é aprimorada para aceitar um número como entrada, chamado times, permitindo repetir o miado a quantidade desejada de vezes, exatamente como se fazia com blocos personalizados no Scratch.
Protótipos e organização do código 1:49:00
Quando a função meow é movida para o fim do arquivo, o compilador C não a reconhece mais, porque ele lê o código de cima para baixo sem verificar o que vem depois. A solução é escrever um protótipo, uma linha no topo do arquivo que apenas anuncia ao compilador que aquela função existirá mais adiante. Isso permite manter main no topo do arquivo, como é convencional, enquanto as funções auxiliares ficam organizadas abaixo.
Correção, design e estilo do código 1:56:00
O professor apresenta três eixos para avaliar a qualidade de um programa: correção, ou seja, se ele faz o que deveria; design, que é o quão bem ele resolve o problema, sem desperdiçar tempo do computador ou do humano; e estilo, que trata da estética do código, como indentação e nomes claros de variáveis. Para isso, o CS50 oferece ferramentas como Check50, para testar a correção, Design50, que dá conselhos sobre a qualidade do código, e Style50, que compara visualmente o código escrito com o padrão esperado.
Abstraindo a leitura de números válidos 2:00:33
Como aprimoramento final, o professor cria uma nova função chamada get_n, que passa a ser responsável por perguntar ao usuário um número e garantir que ele seja zero ou positivo, repetindo a pergunta enquanto o valor for negativo. Diferente das funções anteriores, esta retorna um valor inteiro em vez de apenas ter um efeito colateral, e esse valor é então passado diretamente para a função meow, deixando o código principal mais limpo e modular.
Introdução ao projeto Mario 2:03:01
Para encerrar, o professor apresenta a ideia de recriar, em C, elementos simples do jogo Super Mario Brothers, começando pela representação de blocos com pontos de interrogação que escondem moedas. Sem usar gráficos, apenas texto, ele propõe começar criando um arquivo chamado mario.c e escrever o código mais simples possível para imprimir uma sequência de quatro pontos de interrogação na tela.
Construindo o céu do Mario com loops 2:04:01
Você volta ao exemplo do Mario para gerar quatro pontos de interrogação no céu usando um loop, em vez de escrever cada símbolo manualmente. A primeira tentativa erra ao colocar a quebra de linha dentro do loop, o que imprime os símbolos em coluna em vez de em linha; a correção é mover o barra n para fora do loop, depois que todos os pontos de interrogação já foram impressos. Em seguida você aplica a mesma lógica para desenhar uma coluna de três tijolos, trocando os pontos de interrogação por cerquilhas para parecer mais com um bloco quadrado.
Uma grade de tijolos em duas dimensões 2:06:30
O desafio seguinte é desenhar uma grade três por três de tijolos, o que exige combinar linhas e colunas pela primeira vez. A solução usa um loop externo para as linhas e um loop interno para as colunas, com variáveis chamadas i e j para evitar conflito de nomes; depois você as renomeia para linha e coluna, deixando o código mais claro sem mudar seu funcionamento. A quebra de linha é colocada depois do loop interno, para pular de linha só quando uma fileira inteira de tijolos foi impressa. Por fim, você percebe que o número três está duplicado em dois lugares do código e resolve isso criando uma constante chamada n com a palavra-chave const, que impede que o valor seja alterado por engano mais adiante.
Montando uma calculadora simples 2:13:00
Você cria um programa de calculadora que pede dois números ao usuário e imprime a soma, usando getInt e o marcador %i. Depois discute que criar uma variável extra apenas para usá-la uma vez pode ser desnecessário, e que somar diretamente dentro do printf também é uma escolha razoável, já que legibilidade importa mais do que regras rígidas. Você também mostra atalhos de terminal, como usar Tab para autocompletar nomes de arquivo e as setas para cima e para baixo para reaproveitar comandos digitados antes.
O meme de dobrar apostas e o estouro de inteiro 2:16:30
Você recria o meme de apostar dólares e dobrar o valor a cada rodada, usando um loop que multiplica dollars por dois enquanto o usuário responder y. Depois de muitas repetições o valor vira negativo e depois zera, revelando o estouro de inteiro: como cada inteiro usa um número finito de bits, geralmente 32, o valor máximo positivo gira em torno de dois bilhões, e passar desse limite faz o número dar a volta. Trocar o tipo para long, com 64 bits, adia o problema mas não o elimina, já que mesmo esse limite maior acaba sendo alcançado.
Exemplos reais de estouro e imprecisão 2:22:33
Você conta o caso real de aviões Boeing 787 que perdiam energia elétrica depois de 248 dias ligados continuamente, por causa de um contador de software que estourava; a solução temporária era simplesmente reiniciar o avião. Cita também o bug histórico do Pac-Man, que embaralha a tela no nível 256 pelo mesmo tipo de problema. Em seguida você mostra o truncamento, quando dividir inteiros descarta a parte decimal, resolvido usando float, e a imprecisão de ponto flutuante, em que um terço aparece com dígitos estranhos no final por causa da quantidade finita de bits. Fecha citando o problema do ano 2000, causado por anos representados com dois dígitos, e o problema semelhante previsto para 2038, ligado à contagem de segundos em inteiros de 32 bits desde primeiro de janeiro de 1970.
O problema do ano 2038 2:29:01
Assim como o bug do ano 2000, os computadores que usam contadores de 32 bits para contar segundos desde 1º de janeiro de 1970 vão ultrapassar esse limite em 19 de janeiro de 2038, podendo confundir a data com 13 de dezembro de 1901.
Encerramento da aula 2:29:32
O professor lembra que CS50 existe para dar ferramentas para resolver problemas como esse, sugere escanear um código para salvar a data no calendário e conclui a semana 1, avisando que a lista de problemas 1 chegará em breve.
AI-generated summary. It can be wrong or incomplete - check anything that matters against the original.

