A nossa missão nesse post é criar um programa em C que permita registrar cada carta com informações detalhadas sobre as cidades, utilizando variáveis, operadores e funções de entrada e saída.
Cada carta conterá dados essenciais como: estado, código, nome da cidade, população, PIB, área e número de pontos turísticos.
Além disso, você também calculará e adicionará propriedades derivadas, como densidade populacional e PIB per capita, enriquecendo as informações estratégicas de cada carta.
Conceitos de solução estruturada
O computador não tem discernimento para julgar se algo é certo ou errado.
No entanto, ele pode ser instruído a tomar decisões lógicas, baseadas em critérios objetivos, e seguir instruções ordenadas. Isso é o que chamamos de solução estruturada.
Programar é parecido com seguir uma receita.
Dividimos um problema grande em partes menores e mais gerenciáveis, o que torna a resolução mais fácil e organizada.
Voltando ao exemplo do bolo, na cozinha, isso é o que chamamos de mise em place.
Se os ingredientes e as etapas não forem organizados, o resultado pode ser um bolo malfeito.
Importância da organização e clareza no código
Imagine que você tenha encontrado a receita de um bolo, mas ela esteja toda desorganizada.
Um ingrediente está listado no meio das instruções, e a temperatura do forno está no final do texto. Difícil de seguir, não é? O mesmo acontece com o código de um programa.
Um código bem organizado facilita a leitura e a manutenção não só para você, mas também para outras pessoas que possam trabalhar no seu projeto.
Para manter o código organizado e claro, podemos usar algumas práticas!
Indentação
Espaço extra adicionado no início de uma linha de código para indicar que ela está dentro de um bloco de código.
Isso ajuda a visualizar blocos de código e entender a hierarquia das instruções.
A indentação facilita a leitura e a compreensão do código, pois é possível perceber visualmente quais linhas pertencem a que bloco de código.
Comentários
São uma ferramenta essencial na programação, especialmente na linguagem C, pois ajudam a documentar o código, tornando-o mais legível e compreensível para outros programadores e para o próprio autor do código no futuro.
Eles são ignorados pelo compilador, o que significa que não afetam a execução do programa, mas fornecem informações valiosas sobre a lógica e a estrutura do código.
Nomes significativos
Use nomes de variáveis e funções que façam sentido. Por exemplo, em vez de x e y, use soma ou resultado. Você irá compreender melhor mais à frente.
Raciocínio lógico e pensamento computacional
O raciocínio lógico é a capacidade de pensar de maneira clara e ordenada.
Na programação, usamos o raciocínio lógico para resolver problemas de forma sistemática.
Já o pensamento computacional é um conjunto de habilidades que nos permite abordar problemas de maneira que um computador possa entender.
Para desenvolver essas habilidades, podemos seguir alguns passos. Acompanhe.
- Decomposição — Consiste em dividir o problema inicial em partes menores, permitindo que cada parte menor seja mais facilmente resolvida.
- Reconhecimento de padrões — Ao decompor um problema em partes menores, fica mais fácil focar os detalhes e perceber que algumas dessas partes já são conhecidas ou têm soluções conhecidas.
- Abstração — Consiste na filtragem e classificação dos dados, concentrando a atenção no que realmente é importante. Por exemplo, ao calcular a média, não importa o nome do aluno, apenas as notas.
- Algoritmos — São procedimentos para resolver um problema, detalhando as ações a serem executadas e a ordem em que devem ocorrer.
São procedimentos para resolver um problema, detalhando as ações a serem executadas e a ordem em que devem ocorrer.
Processo de programação e linguagem C
Programar é como dar instruções para um computador fazer o que você quer, como se estivesse ensinando alguém a seguir uma receita. Isso envolve várias etapas.
- Entendimento do problema — Primeiramente, você precisa entender o que deve ser resolvido.
- Planejamento — Aqui, você decide como resolver o problema.
- Codificação — Agora, escrevemos o código.
- Compilação — Essa é a etapa que traduz o código que você escreveu na linguagem C para uma linguagem que o computador entende.
- Teste — Esse é o momento em que verificamos se tudo funciona.
- Depuração — Se algo deu errado, corrigimos os erros.
- Manutenção — Depois de tudo pronto, pode ser necessário fazer ajustes ou melhorias.
O que é uma linguagem de programação?
Uma linguagem de programação é um conjunto de instruções que você pode usar para comunicar-se com um computador.
Uma linguagem de programação é um conjunto de instruções que você pode usar para comunicar-se com um computador.
As linguagens de programação foram desenvolvidas para facilitar a escrita de programas de computador, fornecendo uma maneira padronizada para que os programadores escrevam instruções que podem ser traduzidas em ações que um computador pode executar.
Conheça agora as características das linguagens de programação.
- Sintaxe e semântica — Cada linguagem tem sua própria sintaxe (regras sobre como escrever o código) e semântica (significado das instruções).
- Nível de abstração — As linguagens podem ser de alto nível (mais próximas da linguagem humana) ou de baixo nível (mais próximas da linguagem de máquina).
- Paradigmas de programação — Diferentes linguagens suportam diferentes estilos de programação, como programação orientada a objetos, programação funcional, programação procedural etc.
Processo de tradução
Quando escrevemos código em C, estamos usando uma linguagem que é mais fácil para nós, humanos, entendermos.
Mas o computador não fala C diretamente. Precisamos traduzir esse código para que o computador possa executar.
Aqui estão, de forma resumida, os passos desse processo. Confira!
- Escrita do código-fonte — Escrevemos nosso programa em um arquivo de texto com uma linguagem de programação, como C.
- Compilação — Escrevemos nosso programa em um arquivo de texto com uma linguagem de programação, como C.
- Linking (Ligação) — Muitas vezes, nosso código precisa de outras bibliotecas ou recursos. O linker combina nosso código compilado com essas bibliotecas para criar o arquivo executável final.
- Execução — Executamos o arquivo binário no computador, e ele fará o que programamos.
Meu primeiro programa em C
Agora que você já conhece os conceitos fundamentais de programação, vamos colocar a mão na massa e criar seu primeiro programa em C.
Vamos criar um programa simples que exibe a mensagem "Olá, Mundo!" na tela.
Esse é o programa tradicional de introdução em muitas linguagens de programação.
Escrevendo o código
#include <stdio.h>
int main() {
printf("Olá, Mundo!\n");
return 0;
}
Esse código é bem simples. Ele tem apenas três partes principais:
- Inclusão da biblioteca ****—
#include
inclui a biblioteca padrão de entrada e saída, necessária para usar a função printf. - Função principal ****—
int main()
é onde o programa começa a execução. Toda aplicação em C começa pela função main. - Saída de dados — A linha
printf("Olá, Mundo!\n");
imprime a mensagem "Olá, Mundo!" na tela. O \n adiciona uma nova linha ao final da mensagem. - Fim do programa —
return 0;
indica que o programa terminou com sucesso.
Compilação e execução do programa
Para que o computador entenda e execute o código, precisamos compilá-lo. Você precisará de uma IDE e um compilador instalados no seu computador.
Algumas opções populares incluem Code::Blocks, Dev-C++, e Visual Studio Code com extensões adequadas.
Variáveis e tipos de dados
Vamos falar sobre variáveis e tipos de dados, dois conceitos fundamentais na programação.
O que são variáveis?
Pense nas variáveis como caixas onde você pode armazenar informações.
Cada caixa tem um nome, e você pode usar esse nome para colocar algo dentro dela ou pegar o que está lá.
Em programação, essas caixas são usadas para guardar valores que podem mudar enquanto o programa está rodando.
Declaração de variáveis
Declarar uma variável é como criar uma caixa e dar um nome a ela.
Em C, a declaração de variáveis segue um formato específico, definindo primeiro o tipo de variável e depois o nome, isso é o que chamamos de sintaxe da declaração de variáveis.
Tipo_variável nome_variável
Vamos ver exemplos de declaração de variáveis:
-
int idade
— Declara uma variável inteira chamada "idade" -
float altura
— Declara uma variável de ponto flutuante chamada "altura" -
double salario
— Declara uma variável de ponto flutuante de dupla precisão chamada "salario" -
char opcao
— Declara uma variável de caractere chamada "opcao"
Regras para criação de nomes de variáveis em C
Criar nomes de variáveis claros e significativos é uma prática essencial na programação. Aqui estão algumas regras e dicas para nomear variáveis em C:
- Comece com uma letra ou sublinhado (_)
- Em seguida, use apenas letras, números e sublinhados.
- Case-sensitive
- Não use palavras reservadas
Inicialização de variáveis
Inicializar uma variável significa colocar um valor inicial dentro da caixa. Isso pode ser feito na mesma linha em que você declara a variável ou depois, no meio do seu código.
-
int idade = 25
— Declara "idade" e atribui o valor 25 -
float altura
— Declara "altura" sem inicializar -
altura = 1.75
— Atribui o valor 1.75 a "altura" posteriormente -
double salario = 3000.50
— Declara "salario" e atribui o valor 3000.50 -
char opcao = 'S'
— Declara "opcao" e atribui o caractere ‘S’
Aqui, estamos criando as variáveis e colocando valores iniciais nelas ao mesmo tempo.
Inicializar variáveis é importante porque, se você tentar usar uma variável que não foi inicializada, ela pode conter lixo (valores aleatórios) que podem causar erros no seu programa.
Tipos de dados primitivos
São como etiquetas que você coloca nas suas caixas (variáveis) para indicar que tipo de valor elas podem armazenar.
Diferentes tipos de dados são usados para diferentes propósitos. A Linguagem C tem 5 diferentes tipos básicos: char, int, float, void, double.
- int — Os inteiros são números sem casas decimais.
- float e double — Os números de ponto flutuante são usados para representar números com casas decimais.
- void — Void é um tipo de dado especial que representa a ausência de um tipo.
- caractere (char) — O tipo char armazena caracteres como números inteiros que representam sua posição na tabela ASCII.
Uso de strings
Além de armazenar caracteres individuais, podemos também trabalhar com sequências de caracteres, conhecidas como strings que são sequências de caracteres armazenadas como arrays (conjuntos) de char, terminadas por um caractere especial chamado caractere nulo (\0).
char nome[20] = "Alice"; // Declara um array de 20 caracteres e inicializa com "Alice"
No exemplo acima, nome pode armazenar até 19 caracteres mais o caractere nulo. A manipulação de strings requer cuidado para evitar buffer overflows (escrever além dos limites do array).
Saída de dados com printf
A função printf é usada para exibir informações na tela.
Pense em printf como uma maneira de pegar informações das suas "caixas" (variáveis) e mostrá-las ao mundo exterior.
printf("texto com formatação", variavel1, variavel2, ...);
Nesse exemplo, printf("Olá, Mundo!\n");
imprime a mensagem "Olá, Mundo!" na tela. O \n no final adiciona uma nova linha, movendo o cursor para a linha seguinte.
Exemplo de uso com variáveis: ao utilizar o printf para imprimir variáveis, é necessário colocar o nome da variável e o especificador de formato. Veja a sintaxe a seguir.
printf(“%formato1 %formato2”, variável1, variável2);
Aqui, "%formato1 %formato2" são os especificadores de formato correspondentes aos tipos das variáveis que você deseja exibir.
Esses especificadores são elementos essenciais para controlar a formatação dos dados nas funções de entrada e saída da linguagem C, como printf e scanf.
Cada especificador de formato é precedido por um caractere % e indica o tipo de dado da variável que será exibida.
Para cada variável que você deseja imprimir, é necessário acrescentar um especificador de formato correspondente.
- %d — Imprime um inteiro no formato decimal.
- %i — Equivalente a %d.
- %f — Imprime um número de ponto flutuante no formato padrão.
- %e — Imprime um número de ponto flutuante na notação científica.
- %c — Imprime um único caractere.
- %s — Imprime uma cadeia (string) de caracteres.
#include <stdio.h>
int main() {
int idade = 25;
float altura = 1.75;
double saldoBancario = 12345.67;
char inicial = 'A';
char nome[20] = "Bruno";
printf("Idade: %d anos\n", idade);
printf("Altura: %.2f metros\n", altura);
printf("Saldo Bancário: %.2f reais\n", saldoBancario);
printf("Inicial do Nome: %c\n", inicial);
printf("Nome: %s\n", nome);
return 0;
}
Entrada de dados com o scanf
Essa é uma das formas mais comuns e úteis de ler dados do usuário em programas escritos em C.
scanf("formato", &variavel);
Aqui, "formato" especifica o tipo de dado que você espera que o usuário insira, e &variavel é o endereço da variável onde o dado será armazenado.
Vamos analisar um exemplo no qual solicitamos ao usuário que insira sua idade.
Lemos essa entrada e, em seguida, exibimos a idade inserida na tela. Este exemplo utiliza as funções printf e scanf.
#include <stdio.h>
int main() {
int idade;
printf("Digite sua idade: \n");
scanf("%d", &idade);
printf("Sua idade é: %d\n", idade);
return 0;
}
Entrada de dados com scanf (lendo strings)
A função scanf também pode ser usada para ler strings do usuário, mas com uma importante ressalva: por padrão, ela lê apenas até o primeiro espaço em branco.
Isso significa que se o usuário digitar um nome completo (com espaços), apenas a primeira parte do nome (até o primeiro espaço) será lida.
char nome[50];
printf("Digite seu nome: ");
scanf("%s", nome);
printf("Nome digitado: %s\n", nome);
Se o usuário digitar "João da Silva", apenas "João" será armazenado em nome. "da Silva" será deixado no buffer de entrada e poderá causar problemas em leituras subsequentes.
Lendo strings com espaços: fgets
Para ler strings com espaços em branco, a função fgets é a melhor opção.
Ela lê uma linha inteira da entrada, incluindo espaços, até encontrar um caractere de nova linha (\n) ou atingir o tamanho máximo especificado.
char nome[50];
printf("Digite seu nome completo: ");
fgets(nome, 50, stdin); // Lê no máximo 49 caracteres da entrada padrão (stdin)
// fgets inclui o '\n' na string, então podemos removê-lo se necessário
nome[strcspn(nome, "\n")] = 0;
printf("Nome completo digitado: %s\n", nome);
fgets
recebe três argumentos:
- O array onde a string será armazenada.
- O tamanho máximo da string (incluindo o \n e o \0).
- O fluxo de entrada (geralmente stdin para a entrada padrão do teclado).
A linha nome[strcspn(nome, "\n")] = 0;
remove o caractere de nova linha (\n) que fgets pode incluir na string.
strcspn
retorna o índice da primeira ocorrência de \n na string nome.
Continuamos a utilizar a solução estruturada, essencial para escrever programas claros e organizados.
Baseada nos conceitos de modularidade, abstração e um fluxo lógico consistente, a solução estruturada nos ajuda a resolver problemas complexos de maneira eficiente e organizada.
Modularidade
Dividir um problema grande em subproblemas menores é uma técnica fundamental para a solução estruturada.
Isso não só torna o problema mais manejável, mas também facilita a identificação e a correção de erros.
Imagine que você esteja desenvolvendo um sistema para calcular a média de temperaturas de uma semana.
O problema pode ser dividido nas seguintes etapas. Observe!
- Entrada de dados — Coletar as temperaturas diárias
- Saída de dados — Exibir a média das temperaturas
- Processamento de dados — Calcular a média das temperaturas
Ela envolve escrever funções ou módulos que realizam tarefas específicas, tornando o código mais reutilizável e fácil de entender.
Cada módulo deve ter uma única responsabilidade.
Embora o conceito de função não seja o foco deste desafio, utilizaremos funções genéricas para ilustrar a modularidade.
Vamos usar o exemplo de cálculo da média de temperaturas para ilustrar a modularidade.
#include <stdio.h>
// Função genérica para entrada de dados
void entradaDados() {
// código para a função entradaDados
}
// Função genérica para cálculo da média
float calcularMedia() {
// código para a função calcularMedia
}
Nesse exemplo, temos três funções distintas para entrada, processamento e saída de dados, cada uma com uma responsabilidade clara.
Abstração
Permite focar os aspectos mais importantes de um problema, ignorando os detalhes irrelevantes.
Isso é importante para lidar com a complexidade.
Usando o exemplo do cálculo da média das temperaturas, em vez de se preocupar com os detalhes de como a entrada de dados é feita, você pode criar uma função entradaDados
que abstrai esse processo.
Assim, se precisar modificar a maneira como os dados são coletados, basta alterar essa função, mantendo o restante do código inalterado.
Ferramentas de planejamentos de soluções
Para resolver problemas complexos de maneira eficiente, é essencial planejar a solução antes de começar a programar.
Duas ferramentas eficazes para esse planejamento são o pseudocódigo ****e os fluxogramas.
Pseudocódigo
É uma forma de descrever a lógica do algoritmo em linguagem natural, de maneira estruturada e fácil de entender. Ele permite que você organize suas ideias e planeje a estrutura do programa.
Início
Solicitar ao usuário um número
Receber o número fornecido
Se o número for divisível por 2 então
Exibir "O número é par"
Senão
Exibir "O número é ímpar"
Fim
Benefícios do pseudocódigo:
- Simplicidade
- Clareza
- Foco na lógica
Fluxogramas
São representações gráficas de um algoritmo, usando símbolos padronizados para ilustrar os passos e o fluxo do processo.
Benefícios dos fluxogramas:
- Visualização clara
- Identificação de problemas
- Facilidade de compreensão
Operadores matemáticos
Em C nós temos alguns operadores que vão se repetir em várias outras linguagens, os matemáticos são:
- Soma (+), subtração (-), multiplicação (*), divisão (/);
Os de atribuição são:
- Atribuição simples (=), atribuição com soma (+=), atribuição com subtração (-=), atribuição com multiplicação (*=), atribuição com divisão (/=);
Os de incremento e decremento são:
- Incremento (++) — quando colocado na frente é pré-incremento que incrementa a variável antes do uso.
int a = 5;
int b = ++a; // a será 6, b será 6
Se posto depois ele incrementa o valor da variável em um, assim:
int i =1;
i++; // i terá o valor 2
O mesmo acontece para o decremento, (—), mas é claro, agora é subtração. Uma boa prática é essa aqui:
#include <stdio.h>
int main() {
int a = 10;
int b = 5;
// Operadores aritméticos
int soma = a + b;
int subtracao = a - b;
int multiplicacao = a * b;
int divisao = a / b;
// Operadores de atribuição
a += 2; // a será 12
b *= 3; // b será 15
// Operadores de incremento e decremento
a++; // a será 13
b--; // b será 14
// Exibição dos resultados
printf("Soma: %d\n", soma);
printf("Subtração: %d\n", subtracao);
printf("Multiplicação: %d\n", multiplicacao);
printf("Divisão: %d\n", divisao);
printf("Novo valor de a (após += 2 e ++): %d\n", a);
printf("Novo valor de b (após *= 3 e --): %d\n", b);
return 0;
}
Manipulação de variáveis inteiras
São usadas para armazenar números inteiros, ou seja, números sem parte decimal. Em C, o tipo de dado inteiro mais comum é int
.
Para ilustrar a manipulação de variáveis inteiras, consideramos um programa simples no qual declaramos e inicializamos duas variáveis inteiras, a e b.
#include <stdio.h>
int main() {
int a = 10;
int b = 3;
int soma = a + b;
int diferenca = a - b;
int produto = a * b;
int quociente = a / b; // Note que a divisão de inteiros resulta em um número inteiro
printf("Soma: %d\n", soma);
printf("Diferença: %d\n", diferenca);
printf("Produto: %d\n", produto);
printf("Quociente: %d\n", quociente);
return 0;
}
A saída do programa mostra que a divisão inteira de 7 por 2 resulta em 3, pois a parte decimal é descartada.
Esse exemplo ilustra como a divisão de inteiros em C sempre retorna um valor inteiro.
Variáveis de ponto flutuante
Em C, os tipos de dados de ponto flutuante mais comuns são float e double.
Para demonstrar a manipulação de variáveis de ponto flutuante, consideramos um programa no qual realizamos operações aritméticas básicas com variáveis float e exibimos os resultados com duas casas decimais.
#include <stdio.h>
int main() {
float x = 5.5;
float y = 2.2;
float soma = x + y;
float diferenca = x - y;
float produto = x * y;
float quociente = x / y; // Divisão de ponto flutuante
printf("Soma: %.2f\n", soma);
printf("Diferença: %.2f\n", diferenca);
printf("Produto: %.2f\n", produto);
printf("Quociente: %.2f\n", quociente);
return 0;
}
A soma de 5.5 e 2.2 resulta em 7.70, a diferença é 3.30, o produto é 12.10 e a divisão de 5.5 por 2.2 resulta em 2.50.
Os resultados são exibidos com duas casas decimais, demonstrando a precisão das operações com ponto flutuante.
Conversão implíctia entre tipos de dados
Ocorre automaticamente quando você mistura diferentes tipos de dados em uma expressão.
Para ilustrar a conversão implícita, consideramos um programa no qual uma variável inteira é somada a uma variável float, resultando em uma conversão automática para float.
#include <stdio.h>
int main() {
int a = 10;
float b = 3.5;
float resultado = a + b; // 'a' é convertido implicitamente para float
printf("Resultado: %.2f\n", resultado); // 13.50
return 0;
}
💡
A conversão implícita pode ser útil, mas também apresenta riscos.
Pode ocorrer perda de dados ou precisão quando tipos de dados de precisões diferentes são convertidos.
Por exemplo, ao converter float para int, a parte decimal será perdida.
Conversão explícita (casting)
A conversão explícita é feita usando operadores de casting para forçar a conversão de um tipo de dado para outro.
Veja a seguir um exemplo de conversão explícita:
#include <stdio.h>
int main() {
int a = 10;
int b = 3;
float quociente = (float) a / b; // 'a' é explicitamente convertido para float
printf("Quociente: %.2f\n", quociente); // 3.33
return 0;
}
Para garantir que suas operações aritméticas sejam realizadas corretamente e evitar problemas de precisão e perda de dados, aqui estão algumas práticas recomendadas que você deve seguir.
- Verifique os tipos
- Use casting quando necessário
- Cuidado com a precisão
Modificadores de tipos de dados
São usados para alterar as propriedades dos tipos de dados primitivos, permitindo uma manipulação mais precisa e eficiente das variáveis.
Modificador unsigned
É usado para declarar variáveis que podem armazenar apenas valores positivos (incluindo zero).
Ele pode ser aplicado aos tipos de dados int e char, dobrando a faixa positiva de valores que podem ser armazenados.
A lista a seguir apresenta um resumo:
- int — -2,147,483,648 a 2,147,483,647
- unsigned int — 0 a 4,294,967,295
- char — -128 a 127
- unsigned char — 0 a 255
Modificador long
É usado para aumentar a capacidade de armazenamento dos tipos de dados primitivos. Ele pode ser aplicado a int e double, permitindo armazenar valores maiores e com maior precisão.
- int — -2,147,483,648 a 2,147,483,647
- long int — -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807
- double — ±1.7E-308 a ±1.7E+308
- long char — ±3.4E-4932 a ±1.1E+4932
Prática recomendada
- Escolha o tipo de dado apropriado
- Verifique a compatibilidade de tipos
- Use especificadores de formato corretos
Operadores relacionais
Enfim, chegamos ao fim, agora vamos falar sobre os operadores relacionais.
Eles são fundamentais na programação, pois permitem a comparação entre variáveis.
Os operadores relacionais disponíveis na linguagem C são:
- > (maior que)
- < (menor que)
- >= (maior ou igual a)
- <= (menor ou igual a)
- == (igual a)
- != (diferente de)
E eles podem ser usados assim:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
printf("a > b: %d\n", a > b);
printf("a < b: %d\n", a < b);
printf("a == b: %d\n", a == b);
printf("a != b: %d\n", a != b);
return 0;
}
Top comments (0)