C e Pensamento Computacional - Week 01 CS50
Um pouco sobre o CS50
O CS50 é um curso introdutório de Ciência da Computação da Universidade de Harvard. Ele é dividido em semanas, começando pela semana 0 com o Scratch, e vai até a semana 10, que aborda conceitos de Inteligência Artificial.
O curso é ministrado por David J. Malan, professor formado e doutor em Ciência da Computação pela própria Harvard. Embora o conteúdo seja atualizado anualmente, o objetivo principal do CS50 não é apresentar as tecnologias mais populares do momento, mas sim ensinar os fundamentos essenciais para quem deseja trabalhar com desenvolvimento de software.
Ao longo do curso, passamos por:
-
Scratch, uma forma visual e intuitiva de aprender lógica computacional;
-
C, para aprender os fundamentos da programação de baixo nível, como arrays, algoritmos, memória e estruturas de dados;
-
Python, SQL, HTML/CSS/JavaScript e Flask — um framework web em Python
C
Embora exista debate sobre o C ser uma linguagem de alto ou baixo nível, essa discussão foge tanto da minha competência quanto do foco do curso. O que realmente importa é que aprender C nos obriga a lidar com aspectos fundamentais da computação, o que proporciona uma compreensão mais profunda da programação, pois estamos lidando diretamente com a memória da máquina. A forma como declaramos as variáveis também importa, se não o código nem compila.
Ao iniciarmos a aula da semana 1, somos introduzidos a alguns conceitos importantes da linguagem C, vamos listar eles aqui.
Estrutura de um programa em C
- Todo programa começa pela função main()
- Exemplo básico:
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
- Compilação
- O código em C é compilado em etapas:
- Preprocessamento, Compilação, Assembly, Linkagem. Ao final, o código-fonte é transformado em um executável. Vou dar um breve resumo de cada uma das etapas:
- Pré-processamento
- Responsável por interpretar diretivas como #include, #define, #ifdef
- Inclui bibliotecas, substitui macros, e remove comentários
- Compilação
- Traduz o código pré-processado para Assembly(código de máquina simbólico)
- Verifica sintaxe, tipos, declarações e gera instruções para a CPU
- Montagem
- Converte o código Assembly em código de máquina binário (formato objeto)
- Cada .c vira um .o (object file)
- Linkagem
- Junta vários arquivos objeto e bibliotecas para formar o programa final executável
- Resolve símbolos (como a posição do printf), lida com endereços de memória e liga funções externas
Por isso é necessário adicionar um compilador a sua máquina quando se programa em C, C++. Atualmente eu tenho preferência pelo GCC, entretando existem outros disponíveis para experimentar. O compilador também serve como uma maneira de comunicar falhas no seu código, indicando linhas em que estão estes erros, podendo ser de sintaxe, léxico, etc(provavelmente um ";").
Os exercícios propostos para a semana 01
Ao final de cada aula, são disponibilizados exercícios para praticar os conceitos apresentados. Acredito que para alguém com mais experiência na área e uma lógica forte, não terá dificuldades em resolver as questões(existem algumas cabreiras, mas ainda não chegamos lá). É preciso lembrar também que são questões feitas para alunos de Havard, então talvez não sejam o "simples" que se espera de um curso da Udemy, ou até mesmo em algumas faculdades do país.
Mario (less)
Pessoalmente, eu sempre opto por resolver o exercício mais simples, e manter o mais dificil como uma revisão que utilizarei eventualmente. Dito isso, vamos ao exercício: é proposto que desenhemos com "#" as pirâmides do jogo Super Mario Bros., aquele amontoado de quadrados, sabe? Minha solução ficou dessa forma:
#include <cs50.h>
#include <stdio.h>
void print_row(int spaces, int bricks);
int main(void)
{
// The user defines the number of bricks
int n;
do
{
n = get_int("Height: ");
}
while(n < 1 || n > 8);
for (int i = 0; i < n; i++)
{
int spaces = n - i - 1;
int bricks = i + 1;
print_row(spaces, bricks);
}
}
void print_row(int spaces, int bricks)
{
// Create Spaces
for (int i = 0; i < spaces; i++)
{
printf(" ");
}
// Create bricks '#'
for (int i = 0; i < bricks; i++)
{
printf("#");
}
printf("\n");
}
Por padrão ao curso, eu opto por manter meus comentários em inglês.
- Cabeçalhos:
#include <cs50.h> //Biblioteca padrão do curso, ele abstrai alguns comandos, principalmente de entrada, como o get_int();
#include <stdio.h> //Biblioteca padrão de C
- main()
// Solicita ao usuário uma altura entre 1 e 8, repetindo enquanto for inválida.
int n;
do
{
n = get_int("Height: ");
}
while(n < 1 || n > 8);
- Loop de construção da pirâmide
// i representa o andar atual da pirâmide
for (int i = 0; i < n; i++)
{
int spaces = n - i - 1;
int bricks = i + 1;
// spaces: número de espaços antes dos blocos. Diminui a cada linha.
// bricks: número de blocos #, que aumenta a cada linha.
// Chama a função print_row(spaces, bricks) para imprimir a linha correta.
print_row(spaces, bricks);
}
- Funçao print_row(int spaces, int bricks)
// Imprime os espaços em branco no início da linha.
for (int i = 0; i < spaces; i++)
{
printf(" ");
}
// Imprime os blocos # após os espaços.
for (int i = 0; i < bricks; i++)
{
printf("#");
}
// Finaliza a linha.
printf("\n");
Cash
A proposta é simples: dado um valor em centavos, calcular quantas moedas de 25¢, 10¢, 5¢ e 1¢ são necessárias para dar o troco com o menor número de moedas possível. Sinceramente o que mais aprendi aqui foi sobre o nomeclatura das moedas que eles usam (CS50 também é cultura). A lógica por trás é de um algoritmo ganancioso: Sempre usamos a maior moeda possível em cada etapa.
Vamos ao código.
#include <cs50.h>
#include <stdio.h>
int calculate_quarters(int cents);
int calculate_dimes(int cents);
int calculate_nickels(int cents);
int calculate_pennies(int cents);
int sum_cents(int cents);
int main(void)
{
// Prompt to ask how many change i need to give;
int cents;
do
{
cents = get_int("Change owed: ");
}
while (cents < 0);
// Sum and exibes the necessary coins
int total_coins = sum_cents(cents);
printf("Total coins used: %d\n", total_coins);
}
int calculate_quarters(int cents)
{
// Calculate how many quarters you should give the costumer
int quarters = 0;
while (cents >= 25)
{
quarters++;
cents = cents - 25;
}
return quarters;
}
int calculate_dimes(int cents)
{
// Calculate how many dimes you should give the costumer
int dimes = 0;
while (cents >= 10)
{
dimes++;
cents = cents - 10;
}
return dimes;
}
int calculate_nickels(int cents)
{
// Calculate how many nickels you should give the costumer
int nickels = 0;
while (cents >= 5)
{
nickels++;
cents = cents - 5;
}
return nickels;
}
int calculate_pennies(int cents)
{
// Calculate how many pennies you should give the costumer
int pennies = 0;
while (cents >= 1)
{
pennies++;
cents = cents - 1;
}
return pennies;
}
int sum_cents(int cents)
{
// Declares the values
int quarters = calculate_quarters(cents);
cents -= quarters * 25;
int dimes = calculate_dimes(cents);
cents -= dimes * 10;
int nickels = calculate_nickels(cents);
cents -= nickels * 5;
int pennies = calculate_pennies(cents);
// Sum the numbers of quarters, dimes, nickels, and pennies used
int total_coins = quarters + dimes + nickels + pennies;
return total_coins;
}
Sei que não é a maneira mais otimizada de solucionar este problema. Eu poderia ter usado divisão inteira e %, no entanto decidi priorizar a lógica e a estrutura do código, quase uma descrição lógica do passo a passo.
Considerações Finais
Gosto da didática do David, e como os exercícios são feitos para utilizar tudo aquilo que lhe foi ensinado durante a aula. Sei que poderia ter usado a biblioteca <math.h>, no entanto optei por resolver tudo na unha para me acostumar ao estilo do curso. Volto semana que vem com minhas considerações sobre a Week 2 - Arrays.
Sobre o SICP
Na minha postagem anterior, eu mencionei estudar o SICP também. Ainda o farei, no entanto a vida acontece e a vida pessoal tem exigido muito da minha atenção, então estarei optando para acompanhar este material após terminar o CS50.
Agradeço a atenção de cada um que parou para ler um pouco do que escrevi, entendo que minha didática não possa estar tão clara, e alguns conceitos podem ter sido explicados de forma incorreta, para isso estou aberto a críticas e direções. Até semana que vem.