Prévia do material em texto
LÓGICA DE PROGRAMAÇÃO
Aula 1 - Conceitos introdutórios
Aula 2 - Definições de lógica
Aula 3 - Elementos fundamentais de programação
Aula 4 - Algoritmos
Referências
Aula 1
CONCEITOS INTRODUTÓRIOS
Nesta aula iniciamos os estudos sobre programação de computadores em que você terá
contato com os primeiros conceitos de algoritmos, variáveis, tipos de dados e os
operadores básicos.
INTRODUÇÃO
Olá, estudante.
Nesta aula iniciamos os estudos sobre programação de computadores em que você terá
contato com os primeiros conceitos de algoritmos, variáveis, tipos de dados e os
operadores básicos. A compreensão dos fundamentos da programação é importante para
que o restante do aprendizado adiante não seja comprometido, assim como compreender
a base sobre a qual a grande área de Tecnologia da Informação é construída. Desse
modo, aproveite esta etapa para estudar com calma, lendo e relendo os conceitos e
exemplos apresentados, realizando os exercícios, assistindo aos vídeos das aulas para
que o conteúdo seja entendido de modo adequado e sua jornada seja tranquila.
Bons estudos!
PRIMEIROS CONCEITOS
Vamos começar abordando os primeiros conceitos da lógica de programação e a
definição de algoritmo, que é o núcleo da sua aprendizagem nesta disciplina.
A programação de computadores é um termo abrangente e que pode ser compreendido
de diversas formas. “Programar”, no nosso contexto, refere-se a aplicar técnicas e
sequências de instruções a um dado artefato tecnológico com o objetivo de que suas
tarefas sejam executadas automaticamente. Pense no exemplo dos robôs de limpeza
utilizados para limpar o chão de casas de modo autônomo. Para que este artefato
tecnológico consiga realizar suas tarefas sem danificar objetos da residência, muitas
instruções estão gravadas em seu sistema para controlar sua operação. A partir do
momento que ele é ligado, deve mapear o ambiente, verificar a existência de móveis,
calcular a rota e assim por diante. Todas essas operações já estão programadas. Por
exemplo, caso encontre um objeto à frente, gire 90º para a direita e siga em frente. Para
que uma instrução como essa seja salva no sistema do robô, é necessário que linguagens
específicas sejam utilizadas, afinal, o objetivo é instruir uma máquina formada por
dezenas e milhares de transistores, resistores e circuitos. Assim, uma instrução na
linguagem humana deve ser traduzida para linguagens compreendidas pela máquina por
meio do que chamaremos de comandos. Portanto, uma operação que pode parecer
simples do nosso ponto de vista muitas vezes será dividida em dezenas, centenas ou
milhares de comandos para a máquina.
Desse modo, é possível inferir que o estudo da programação deve ser composto de
outras áreas do conhecimento, como a lógica, pois é necessário que as sequências de
comandos estejam organizadas logicamente de modo a fazer funcionar a máquina em
toda sua complexidade. Além disso, elementos da matemática e até mesmo da linguística
também são utilizados, pois para escrever um programa com instruções e comandos é
fundamental que sigam as sintaxes e padrões estabelecidos.
O que é algoritmo
É comum hoje nos depararmos com a palavra algoritmo em notícias, vídeos, reportagens,
pois ela é utilizada em contextos diferentes como: eleições, propagandas, recomendação
de filmes e séries, etc. O motivo para a difusão desta palavra é simples: o algoritmo é a
base da programação. Mais especificamente, um programa de computador é a
implementação de um ou mais algoritmos como solução para resolver um problema.
Do modo sucinto, pois abordaremos os detalhes em outro momento, um algoritmo é uma
sequência de instruções e comandos para resolver um problema.
Reflita
Quais algoritmos você já utilizou em sua vida? Podemos pensar no ensino fundamental,
quando aprendemos o algoritmo da divisão. Ou então os passos para resolver uma
fórmula de Bhaskara; os passos para descobrir se um número é primo, entre outros.
Em resumo, um algoritmo é como uma receita, isto é, a descrição dos passos necessários
para se chegar a um resultado esperado.
Variáveis, tipos e operadores
Para que um programa implemente um algoritmo é preciso, além da lógica do algoritmo
em si, um ferramental para manipular os dados e organizar as instruções. De modo geral,
a maioria das linguagens de programação apresentam variáveis para armazenar dados,
que possuem tipos específicos e podem ser relacionadas por meio de operadores.
Ao retomarmos o exemplo do robô aspirador, podemos imaginar de que modo vamos
guardar a direção que o robô se encontra, sua velocidade, sua energia, se há ou não
objetos próximos e assim por diante. Todas as informações devem ser armazenadas em
variáveis. E, caso necessário, seus valores podem ser alterados, como ao alterar a
direção. Por essa capacidade de modificar os dados armazenados chamamos a estrutura
de variáveis, em oposição a constantes, que são dados armazenados imutáveis. Por
exemplo: o peso do robô será uma constante, pois não deve sofrer variações de acordo
com sua execução. Por último, para que as variáveis sejam alteradas é necessário
manipulá-las, o que é feito com os operadores.
UM PROGRAMA E SEUS ELEMENTOS
Agora, vamos aprofundar o estudo inicial de programas de computador e uso e tipos de
variáveis. Para iniciar, temos uma receita de bolo abaixo:
Receita de bolo
• 2 xícaras de açúcar
• 3 xícaras de farinha
• 4 colheres de manteiga
• 3 ovos
• 1 colher de fermento
Modo de preparo:
• Bata as claras em neve;
• Misture as gemas, o açúcar e a manteiga;
• Acrescente o leite e a farinha de trigo aos poucos;
• Adicione as claras em neve e o fermento;
• Despeje a massa em uma forma grande de furo central;
• Asse em forno médio a 180 °C, preaquecido, por aproximadamente 40 minutos.
Observe que uma receita tem duas partes principais: os ingredientes utilizados e o modo
de preparo (no nosso caso, o algoritmo), que é o passo a passo da manipulação dos
ingredientes para obter o bolo conforme esperado. Assim, a sequência correta da
execução das instruções é essencial para o resultado correto. Caso a última instrução
fosse executada antes da hora, provavelmente o bolo não seria saboroso. Da mesma
forma, as instruções de um programa de computador devem seguir uma sequência lógica
de passos.
Ademais, não basta seguir a sequência correta se os recipientes e ingredientes não
estiverem de acordo com a receita. Observe que na receita há um número certo de
xícaras de farinha. Na nossa analogia da receita com um programa, os ingredientes
seriam as variáveis, que podem ter suas quantidades alteradas de acordo com o tamanho
do bolo desejado e manipulados de acordo com cada operador, como adicionar as claras
em neve e o fermento.
Tomemos agora um exemplo de um programa em que se deseja calcular a média de três
números inteiros. Poderíamos escrever as instruções desse programa da seguinte
maneira:
• Some os três números.
• Divida a soma dos três números pelo número 3.
• Imprima na tela o resultado.
Para os números 3, 4 e 9, por exemplo, poderíamos escrever o seguinte programa:
1. 3 + 4 + 9
2. (3 + 4 + 9) / 3 → Observe que os parênteses são utilizados da mesma forma que na
notação da matemática
3. imprimir((3+4+9)/3))
Porém, caso quiséssemos utilizar o programa para calcular a média de 6, 7 e 10, teríamos
que reescrever todo o programa para tal.
1. 6 + 7 + 10
2. (6 + 7 + 10) / 3
3. imprimir((6 + 7 + 10)/3))
E assim por diante, isto é, para cada três novos valores seria necessário reescrever todo
o programa.
Para resolver esta situação, introduzimos o uso das variáveis e assim nosso código pode
ser reutilizado. Utilizaremos as variáveis x, y e z para representar os números, mas
observe que você pode dar o nome que quiser, desde que o primeiro caractere seja uma
letra. Por exemplo: numero1, numero2 e numero3, ou a, b e c, etc. E as variáveis soma e
média representarão outras variáveis auxiliares.
Desse modo, o programa ficaria da seguinte maneira:
1. soma ← x + y + z
2. media ← (soma)/33. imprimir(media)
E, com isso, pode ser reaproveitado para quaisquer números, bastando modificar os
valores de x, y e z. Assim temos um programa mais completo e eficiente. Contudo, ainda
é preciso estar atento aos tipos das variáveis, afinal, a divisão de números inteiros nem
sempre é inteira. Desse modo, é preciso especificar qual o tipo numérico de cada variável:
1. x: inteiro;
2. y: inteiro;
3. z: inteiro;
4. soma: inteiro;
5. media: decimal;
Desse modo, nosso primeiro programa está praticamente completo, com as variáveis e
tipos definidos e o algoritmo de cálculo da média implementado: a primeira parte refere-se
ao que chamamos de declaração das variáveis e a segunda parte às instruções
propriamente ditas do algoritmo:
// Declaração das variáveis
1. x: inteiro;
2. y: inteiro;
3. z: inteiro;
4. soma: inteiro;
5. media: decimal;
// Instruções do programa
6. soma ← x + y + z
7. media ← (soma)/3
8. imprimir(media)
Apesar de completo, este exemplo tem fins apenas didáticos, pois não está em uma
linguagem reconhecida por nenhum compilador ou tradutor de linguagem de máquina. É o
que chamamos de pseudocódigo, pois simula o código de um programa em linguagem e
símbolos mais fáceis de serem compreendidos por nós, o que é a forma ideal de iniciar na
programação.
O USO DE VARIÁVEIS E OPERADORES
Agora, veremos alguns exemplos de criação de programas básicos e sua implementação
utilizando pseudocódigo para representar as variáveis e as operações.
Tome o exemplo a seguir:
1. x: inteiro;
2. y: inteiro;
3. x ← 2
4. y ← x
5. imprimir(y)
Qual o valor de y após a execução das duas linhas?
Neste caso, a variável y recebe o valor que estava armazenado em x, no caso, o valor 2.
Agora observe o caso a seguir:
1. x: inteiro;
2. y: inteiro;
3. x ← 2
4. imprimir(x)
5. y ← x + 1
6. x ← x + y
7. imprimir(x)
O programa possui dois comandos de impressão na tela. Quais os valores de x serão
impressos?
Pare responder a essa pergunta precisamos executar o código passo a passo. Quando o
programa executar o primeiro comando “imprimir(x)” (linha 4), o valor de x será 2, pois até
aquele momento foi a última atualização da variável x.
Contudo, no momento da execução do segundo comando “imprimir(x)” (linha 7), o valor
impresso será 5, você sabe explicar o porquê?
Após a primeira impressão, a variável y recebe o valor armazenado na variável x (que é
igual a 2) mais o número 1, portanto, y está valendo 3. No próximo comando, a variável x
recebe a soma dos valores armazenados em x (igual a 2) mais o valor armazenado na
variável y (igual a 3). Portanto, a variável x é atualizada para o valor 5. Ou seja, deixa de
armazenar o valor 2 para armazenar o valor 5.
Façamos agora um outro exemplo para fixar o conteúdo visto até o momento.
O objetivo do programa será implementar um algoritmo que leia o nome de duas pessoas
junto com suas respectivas idades e imprima na tela uma mensagem de texto informando
a soma da idade das duas pessoas. Por exemplo: se o usuário digitar o nome João e a
idade 24 e o nome Maria com a idade 25, deve imprimir na tela a mensagem: “A soma da
idade de João e Maria é 49”.
Para tanto, passamos a precisar de variáveis que representem texto e variáveis que
representam números inteiros. Além disso, é preciso ler os nomes e idades, calcular a
soma das idades e imprimir a mensagem solicitada, conforme o programa abaixo.
1. nome1: texto;
2. nome2: texto;
3. idade1: inteiro;
4. idade2: inteiro;
5. Ler(nome1); //neste momento é lido o primeiro nome
6. Ler(idade1); //neste momento é lida a primeira idade
7. Ler(nome2); //neste momento é lido o segundo nome
8. Ler(idade2); //neste momento é lida a segunda idade
9. soma ← idade1 + idade2;
10. Imprimir(“A soma da idade de “ nome1 “ e “ nome2 “ é “ soma);
Observação
As duas barras // indicam um comentário. Isso significa que o texto após as barras não faz
parte do código, como nas linhas 5, 6, 7 e 8.
Como último exercício de fixação, execute mentalmente (ou em um papel) o programa
acima com diferentes nomes e idades e observe quais mensagens serão impressas ao
final. Este é um bom exercício para compreender que um programa deve poder ser
utilizado para diferentes tipos de valores, o que chamamos de entradas de dados.
Nesta aula, você aprendeu de maneira introdutória os principais conceitos de algoritmo,
programa, variáveis, tipos de dados e alguns operadores. Bons estudos!
VÍDEO RESUMO
Olá, estudante, no vídeo desta aula abordaremos os primeiros conceitos da lógica de
programação de modo a complementar este material escrito. Abordaremos e ilustraremos
a definição e os exemplos do uso de variáveis com os principais operadores de maneira a
consolidar essa etapa introdutória e essencial ao seu aprendizado.
Saiba mais
O estudo da lógica de programação e dos primeiros passos para pensar e construir
algoritmos pode ser uma novidade interessante e desafiadora para muitas pessoas. Por
isso, há diversas ferramentas disponíveis para auxiliar os estudantes nesta etapa. Uma
das mais utilizadas para o nível introdutório é a linguagem Scratch, criada em 2007 pelo
MIT e que utiliza elementos ilustrativos e blocos para ensinar o pensamento algoritmo de
maneira lúdica e didática.
O Scratch, sua documentação e instruções para download estão disponíveis em seu site.
Aula 2
DEFINIÇÕES DE LÓGICA
https://scratch.mit.edu/
Nesta aula, você conhecerá uma temática fundamental para a compreensão do
pensamento algorítmico: a lógica proposicional, o ramo da lógica que auxilia a
compreender e organizar as variáveis, os métodos e as funções de maneira estruturada.
INTRODUÇÃO
Olá, estudante.
Nesta aula, você conhecerá uma temática fundamental para a compreensão do
pensamento algorítmico: a lógica proposicional, o ramo da lógica que auxilia a
compreender e organizar as variáveis, os métodos e as funções de maneira estruturada.
Assim, por meio de definições e conceitos iniciais, você aprenderá o básico da lógica, os
principais conectivos como conjunção, disjunção e condicional, bem como sua
representação utilizando a tabela verdade.
Portanto, é importante que você acompanhe este material com atenção para que o
conteúdo abordado sirva como base para o seu desenvolvimento futuro no mundo da
programação.
Bons estudos!
INTRODUÇÃO À LÓGICA
A lógica é um campo fundamental da ciência e da filosofia que estuda a representação do
conhecimento, em que a preocupação principal é a validação da argumentação. Assim, a
lógica, como veremos nesta aula, não busca verificar se uma ou mais afirmações são
verdadeiras, mas se o modo como as afirmações são organizadas é válido.
No programação, um dos maiores desafios é como representar as informações do mundo
real que são necessárias para a operação correta de um sistema. Assim, o estudo da
lógica nos servirá para compreender a linguagem de representação de informações do
mundo real assim como validar e organizar as instruções nos algoritmos.
A lógica é um extenso campo subdividido em diversos ramos. Entre eles, podemos
destacar a lógica clássica (também chamada de lógica aristotélica em referência a
Aristóteles), que é composta em alguns princípios elementares que definem suas regras:
• O princípio da identidade: este princípio, um tanto óbvio, afirma que algo é sempre
algo. Isto é, a = a e b = b;
• O princípio da não contradição: estabelece que se uma afirmação é falsa, sua
contraditória deve ser verdadeira. Ou seja, se uma afirmação A é verdadeira e outra
afirmação B é o contrário de A, então B deve, obrigatoriamente, ser falsa;
• O princípio do terceiro excluído: estabelece que uma afirmação não pode ser falsa e
verdadeira ao mesmo tempo.
Assim, uma vez definidos os princípios, é preciso definir o que é uma proposição. Uma
proposição lógica é uma afirmação, uma declaração de algo. Mas, atenção, pois nem toda
sentença é uma proposição lógica. Por exemplo: "Feliz ano novo" é uma sentença
exclamativa e não declarativa e, portanto, não é uma proposição. Para identificar uma
proposiçãoé preciso sempre pensar que deve ser possível atribuir um valor lógico, isto
é, uma proposição será sempre verdadeira ou falsa. Por exemplo: "5 é menor que 3".
Neste caso há uma declaração e a proposição em questão tem valor lógico falso, pois 5
não é menor que 3. Um outro exemplo de proposição é: "O Brasil é o maior país da
América do Sul e o Amazonas é o maior estado do Brasil".
Neste caso, temos duas proposições que formam uma proposição composta. Como
podemos verificar, as duas proposições simples são verdadeiras e, portanto, a proposição
composta também é verdadeira.
Por fim, podemos observar um último elemento importante que abordaremos em maior
profundidade a seguir que são os conectores. A proposição composta anterior foi
formada por meio do conector e, que uniu as duas proposições menores. Os conectores
que estudaremos são conjunção, disjunção, negação e condicional. A conjunção é
também representada pelo e, a disjunção pelo ou, a negação pelo não e a condicional
pelo se.
ELEMENTOS DA LÓGICA PROPOSICIONAL
A lógica proposicional é baseada no estudo dos valores lógicos, sentenças e afirmações
que se representam por meio de proposições, como você observou no bloco anterior.
Assim, você verá como essas sentenças declarativas podem ser relacionadas, formando
proposições compostas em que o valor lógico depende dos valores de cada variável.
Neste sentido, vamos aprofundar o conhecimento de cada uma delas para, no último
bloco, analisar a aplicação desses conceitos por meio da tabela verdade.
Negação
A primeira das relações a ser estudada é a mais simples, a negação. Nesta operação, se
uma variável p tem certo valor lógico, sua negação (representada por ~p) terá o valor
oposto.
Por exemplo, dada a proposição:
p: o céu é amarelo
Sua negação será:
~p: o céu não é amarelo
A negação pode ser aplicada a uma variável isolada ou em proposições com mais
variáveis.
Conjunção
A próxima operação analisada é a conjunção, que necessita de duas variáveis para sua
aplicação. A conjunção nada mais é do que o conectivo que representa a intersecção, ou
então, na língua portuguesa o E, isto é, uma coisa e outra. Por exemplo, tomando duas
proposições p e q:
p: Brasília é a capital do Brasil
q: Buenos Aires é a capital da Argentina
Neste caso, a conjunção é representada da seguinte forma
p^q: Brasília é a capital do Brasil e Buenos Aires é a capital da Argentina
E, como ambas as proposições são verdadeiras a proposição resultante também é.
Disjunção
Outro conectivo muito importante é a disjunção, que representa a união da matemática,
ou, em língua portuguesa, o OU. Mas atenção: a disjunção será verdadeira quando uma
das variáveis for verdadeira ou ambas forem verdadeiras. Como exemplo temos as duas
proposições p e q:
p: a água é transparente
q: o mar é vermelho
Deste modo, a disjunção é representada da seguinte forma:
p V q: a água é transparente ou o mar é vermelho
Condicional e bicondicional
Outros dois conectivos fundamentais para o estudo da lógica são o condicional e
o bicondicional. Como o nome indica, a operação condicional representa uma condição
e pode ser lida como se p então q (indicado pela seta à). Por exemplo,
p: choveu hoje
q: o asfalto está molhado
Assim, a condicional é representada por:
p à q: se choveu hoje então o asfalto está molhado
De modo análogo, temos a bicondicional, que é a condicional aplicada a ambas as
direções e lida como p se e somente se q(representada por <->). Como exemplo temos:
p: a é primo
q: a é divisível por 2
Neste caso, a bicondicional é representada por:
p <-> q: a é primo se e somente se a é divisível por 2
Que, observando os valores lógicos de p e q, é falso.
Desse modo, você conheceu os principais conectivos lógicos da lógica proposicional que
conformam o arcabouço que auxilia na compreensão e no desenvolvimento do
pensamento algorítmico necessário para a programação.
A TABELA VERDADE E ALGUNS EXEMPLOS
Agora, veremos a aplicação dos conceitos da lógica por meio de exemplos e do uso da
tabela verdade para a validação das proposições.
Tabela verdade
A representação mais interessante no início dos estudos da lógica proposicional é a
tabela verdade, pois permite avaliar os valores lógicos resultantes das operações entre as
proposições de maneira mais direta.
A tabela é formada por colunas, sendo uma para cada variável proposicional e uma ou
mais colunas para a proposição composta resultante, a depender do seu tamanho. No
nosso caso, utilizaremos apenas a tabela com três colunas, conforme o exemplo a seguir,
que representa a operação E indicada pelo operador ^. Observe que temos duas
variáveis, p e q e, para cada uma, há 4 linhas com os possíveis valores lógicos. A terceira
coluna corresponde à proposição composta p ^ q e possui os valores de todas as
combinações possíveis entre os valores lógicos de cada variável.
Tabela 1 | Tabela verdade da conjunção
p q p ^ q
F F F
F V F
V F F
V V V
Observe que a primeira linha interna da tabela tem a variável p com valor falso (F), a
variável q também com F e, na terceira coluna, o resultado da operação p ^ q com ambas
as variáveis F, que resulta em F. Na segunda linha, quando p é verdadeiro (V), q é F, o
resultado de p ^ q é F, afinal, para a conjunção ser verdadeira, é necessário que ambas
as proposições sejam verdadeiras, o que ocorre apenas na última linha da tabela.
A seguir temos a tabela da disjunção, isto é, dados p e q, a operação p V q. É importante
lembrar que a disjunção é a operação também conhecida como OU, ou seja, o resultado
será verdadeiro quando uma das duas proposições forem verdadeiras (ou ambas) – como
observamos nas três primeiras linhas – e falso quando nenhuma das duas forem
verdadeiras, conforme observamos na primeira linha da tabela.
Tabela 2 | Tabela verdade da disjunção
p q p v q
F F F
F V V
V F V
V V V
É importante observar que a aplicação da tabela verdade é útil em muitos casos, mas
pode se tornar inviável a depender do número de variáveis que compõem a proposição.
Suponha que tenhamos 10 proposições simples formando uma proposição composta por
meio de operadores lógicos. Qual seria o número de linhas da tabela verdade?
Para responder a essa questão é preciso observar que o número de linhas de uma tabela
com uma única variável será 2, pois há apenas duas combinações possíveis. A tabela as
seguir ilustra a tabela verdade com apenas a variável p formando a proposição ~p, que é
a negação de p.
Tabela 3 | Tabela verdade da negação
p ~p
F V
V F
Assim, retornando ao questionamento, uma tabela com uma variável possui 2 linhas, uma
tabela com duas variáveis possui 4 linhas, uma tabela com 3 variáveis terá 8 linhas.
Forma-se um padrão que é representado pela expressão , portanto uma proposição
composta por 10 variáveis terá 2¹⁰ linhas, ou 1024 linhas, o que torna difícil sua
representação para muitas variáveis.
VÍDEO RESUMO
Olá, estudante, no vídeo desta aula abordaremos alguns conceitos da lógica, sua
definição e elementos práticos de como manipular e validar argumentos por meio de
exemplos e da construção da tabela verdade.
Saiba mais
O estudo da lógica proposicional pode ser complementado por estudos paralelos e pela
prática em forma de exercícios. Desse modo, seguem alguns links com jogos educativos
para praticar seu conhecimento em relação aos conceitos apresentados:
Lógica Proposicional Clássica - Quiz com exercícios sobre lógica.
Raciocínio Lógico - Conceitos Básicos – I - Quiz com perguntas.
Aula 3
ELEMENTOS FUNDAMENTAIS DE PROGRAMAÇÃO
Nesta aula você terá contato com os primeiros elementos necessários para iniciar o
desenvolvimento de programas de computador, o que será essencial para a evolução na
sua aprendizagem.
https://www.quiz.com.br/quiz/716/raciocinio-logico-conceitos-basicos-i/
https://quizizz.com/admin/quiz/5e184173be7d73001c424bf7/logica-proposicional-classica
INTRODUÇÃO
Olá, estudante.
Nesta aula você terácontato com os primeiros elementos necessários para iniciar o
desenvolvimento de programas de computador, o que será essencial para a evolução na
sua aprendizagem. Veremos como os algoritmos formam a base da computação e são
fundamentais para que um sistema possa ser executado de maneira eficiente e
adequada. Veremos também elementos estruturantes para a produção de códigos como
os principais operadores aritméticos, lógicos e relacionais, e a noção e manipulação de
variáveis e constantes. Esperamos que este material contribua para que seus estudos na
introdução à programação sejam completos e auxiliem em sua vida acadêmica e
profissional.
Bons estudos!
OS ALGORITMOS NA PROGRAMAÇÃO
A computação tem como objetivo central a resolução de problemas pelo uso de máquinas
potentes que são capazes de realizar bilhões de operações por segundo. E para que
essas máquinas e esses equipamentos possam realizar seus cálculos e operações
corretamente é necessário que as instruções sejam estruturadas de maneira lógica. Para
isso, cabe aos programadores a tarefa de escrever as instruções a serem executadas.
Assim, programar não é uma tarefa simples, pois exige conhecimentos sobre os
equipamentos, linguagens de programação e, principalmente, sobre as melhores
maneiras de resolver os problemas.
Neste sentido, antes de escrever as dezenas, centenas ou milhares de linhas de código
para um sistema computacional, é fundamental o estudo e planejamento da solução e de
sua lógica, para só então transformá-la em programas de computador. E é aqui que são
desenvolvidos os algoritmos, que são as instruções de um programa em sequência e
ordem determinadas, as quais garantem que uma entrada de dados será processada e
resultará em uma saída que deve resolver o problema. É análogo a uma receita de bolo,
em que o algoritmo deve instruir o cozinheiro ou cozinheira como processar os
ingredientes e transformá-los em um bolo perfeito.
Desse modo, faz-se essencial estudar como desenvolver um bom algoritmo e conhecer
as ferramentas utilizadas para construí-los e transformá-los em código. Para tanto, nesta
aula abordaremos alguns dos elementos para darmos início à construção de códigos,
como os operadores aritméticos, operadores relacionais, operadores lógicos, variáveis e
constantes.
Em linhas gerais, os operadores possibilitam manipular e relacionar dados. Estes dados
podem ser de vários, tipos: numéricos, textuais, lógicos, entre outros. E, na programação,
a lógica de manipulação segue a lógica matemática que você conhece do ensino médio.
Assim, como os dados podem sofrer alterações durante o algoritmo, há estruturas
conhecidas como variáveis que servem para armazenar temporariamente um dado valor
de dado tipo, de acordo com o que o programador definir. Essas variáveis, como o nome
indica, podem sofrer variações em seus valores durante a execução do programa,
diferente das constantes, que são dados imutáveis.
Ressaltamos a importância deste momento do aprendizado, pois a manipulação correta
de variáveis, por exemplo, é a base para a execução eficiente de um programa de
computador. Imagine, por exemplo, um programa de computador para orientar o
lançamento de foguetes espaciais. São inúmeros cenários e fatores que podem decidir o
sucesso ou fracasso do lançamento que devem ser todos considerados para o
desenvolvimento do sistema. Como são milhares ou milhões os fatores que podem ser
transformados em dados e analisados pelos programas, é dever do programador criar
algoritmos corretos e eficientes utilizando corretamente as variáveis e as operações pois
um programa com excesso de variáveis pode levar a estourar a capacidade de memória,
e um algoritmo com operações em excesso pode sobrecarregar a capacidade de
processamento. São detalhes como este que fazem diferença tanto no mercado de
trabalho quanto na vida acadêmica de computação e que iniciaremos o estudo nesta aula.
O USO DE OPERADORES E VARIÁVEIS
Vamos aprofundar os conhecimentos sobre os operadores, variáveis e constantes,
definindo cada um deles.
Operadores aritméticos
Os operadores aritméticos são aqueles utilizados para realizar cálculos aritméticos, da
mesma maneira que você aprendeu na matemática. Neste bloco veremos os 4 principais:
adição, subtração, divisão e multiplicação:
1. Adição
O operador de adição é o símbolo +. Para utilizá-lo, basta relacionar dois elementos
sejam eles variáveis, constantes ou números. Por exemplo: a expressão 3 + 2 é uma
adição válida, assim como 3 + num, desde que a variável num seja do tipo numérico. É
possível também associar duas variáveis como num1 + num2, ou então variáveis e
constantes, como em num2 + NUM3, em que num2 é uma variável e NUM3 uma
constante. A ordem neste caso não faz diferença.
2. Subtração
O operador da subtração é o símbolo -. Analogamente à adição, é possível relacionar
números, variáveis e constantes, como 3 - 4, ou então num1 - num2, ou então NUM3 - 4.
3. Divisão
O operador da divisão utilizado na maioria das linguagens de programação e em
pseudocódigo é o /. Com ele é possível realizar divisões entre valores numéricos
(números, variáveis e constantes). Assim como na matemática, também pode ser
necessário o uso de parênteses para o correto resultado. Por exemplo, a divisão 3 + 4/2 é
diferente de (3+4)/2. Uma observação importante é que a divisão de números inteiros
geralmente resultará um um resultado inteiro, portanto, é preciso estar atento ao tipo das
variáveis e números utilizados.
4. Multiplicação
O último operador aritmético analisado é o de multiplicação, com o símbolo *. Neste caso,
assim como na divisão, é preciso estar atento ao uso de parenteses. Por exemplo, 5 * 2 -
3 é igual a 7, já 5 * (2 - 3) é igual a 5.
Uma característica importante, assim como na matemática, é a precedência dos
operadores, pois a divisão e a multiplicação são realizadas antes da soma e da subtração.
Com base no que vimos, um exercício interessante é descobrir qual o valor da seguinte
expressão: 4 - (5 * 2) / 5 ?
Operadores relacionais
Os operadores relacionais servem para testar os valores lógicos de uma dada expressão,
isto é, se a expressão é verdadeira ou falsa.
1. Igualdade
Para testar a igualdade, utilizaremos o símbolo ==, como no exemplo: 5 == 7. Neste caso,
o resultado da expressão é falso, pois 5 não é igual a 7.
2. Diferença
Para testar a diferença, utilizamos o operador !=, como no exemplo 5 != 7. Neste caso, o
resultado da expressão é verdadeiro, pois 5 é diferente de 7.
3. Maior e menor
Já para testar se um valor é maior ou menor que outro, utilizamos os mesmos operadores
que a matemática, > para testar se um valor é maior que outro e < para testar se um dado
valor é menor que outro. Por exemplo, 5 < 2 possui valor lógico falso, pois não é verdade
que 5 é menor que 2, enquanto 5 > 2 retorna verdadeiro, pois de fato 5 é maior que 2.
Ainda é importante salientar que é possível utilizar o símbolo >= e <= para testar se
valores são maiores ou iguais e menores ou iguais a outros, respectivamente.
Operadores lógicos
Os operadores lógicos são utilizados, no nosso caso, para concatenar expressões, isto é,
se uma expressão composta é verdadeira ou falsa. Por exemplo: se quisermos avaliar as
expressões 4 > 5 e a expressão 5 > 6 pela conjunção, escrevemos da seguinte maneira:
4 > 5 && 5 > 6. Neste caso, o resultado será falso, já que ambas as expressões são
falsas.
No caso da disjunção utilizaremos o símbolo ||. Por exemplo: 5 > 3 || 6 >= 7. Neste caso,
a expressão 5>3 é verdadeira e a expressão 6>=7 é falsa. Porém, a expressão completa
5 > 3 || 6 >= 7 é verdadeira, pois trata-se de uma disjunção.
Variáveis e constantes
Por fim, vamos conhecer um pouco mais sobre variáveis e constantes.
Uma variável é um espaço na memória reservado para armazenar um valor de tipo pré-
determinado. Por exemplo: se quisermos armazenar um número inteiro, devemos
declarar uma variável com um nome que o programador escolhe e o tipo destavariável.
Para declarar uma variável inteira e uma real, é possível indicar:
num1: inteiro; num2: real;
A partir de então é possível armazenar valores nestas variáveis, utilizá-las em expressões
e até mesmo substituir seus valores.
Já as constantes são valores fixos. Uma vez atribuídos valores para as constantes (que
também recebem nomes e tipos), estes valores não podem mais ser modificados.
Convenciona-se escrever as constantes em letra maiúscula, como no exemplo a seguir:
NUM1: inteiro; NUM1 <- 5; A partir deste momento a constante NUM1 sempre conterá o
valor 5.
EXEMPLOS DE ALGORITMOS COMPLETOS
Agora, você irá consolidar o conhecimento adquirido anteriormente por meio da aplicação
da lógica de desenvolvimento de um algoritmo, a noção de operadores e a manipulação
de variáveis na solução de problemas.
A primeira etapa, conforme abordamos, é compreender o problema proposto. Vamos
iniciar com um problema simples: imprimir a soma de dois números inteiros.
Para isso, temos como entrada dois números, que precisamos salvar em duas variáveis,
como no código a seguir:
1. num1: inteiro;
2. num2: inteiro;
3. soma: inteiro;
4. ler(num1, num2);
Observe que nas três primeiras são declaradas as variáveis inteiras que utilizaremos. A
seguir, é necessário utilizar o operador aritmético de adição para realizar a soma das
variáveis e operador de atribuição para salvar o resultado na variável soma:
1. num1: inteiro;
2. num2: inteiro;
3. soma: inteiro;
4. ler(num1, num2);
5. soma <- num1 + num2;
6. imprime(soma);
Na linha 5 realizamos a operação de soma e, na linha 6, imprimimos na tela o
resultado calculado.
Agora passemos a um exemplo mais completo: ler 5 números inteiros e imprimir na
tela quantos números positivos e negativos.
Para isso, é preciso inicialmente fazer a leitura de cada número. Quando um número é
lido, é necessário salvar em uma variável, que neste caso será do tipo inteiro. Em
seguida, é necessário utilizar o operador relacional para comparar se o número é maior
ou menor que zero e então incrementar a variável correspondente, conforme o
pseudocódigo a seguir:
1. contador: inteiro;
2. num: inteiro;
3. qtdePositivos: inteiro;
4. qtdeNegativos: inteiro;
5. contador <- 0, qtdePositivos <- 0, qtdeNegativos <- 0;
6. enquanto contador < 5 faça:
7. ler(num)
8. se num > 0 então:
9. qtdePositivos <- qtdePositivos + 1;
10. se num < 0 então:
11. qtdeNegativos <- qtdeNegativos + 1;
12.
13. imprima(qtdePositivos, qtdeNegativos);
Agora vamos compreender o código acima. Nas linhas 1 a 4 são declaradas as variáveis
que serão utilizadas, bem como o tipo de cada uma, que no caso são inteiras. A variável
contador servirá para contar a quantidade de números lidos; as variáveis qtdePositivos e
qtdeNegativos servem para contar a quantidade de números positivos e negativos,
respectivamente; a variável num armazena cada número lido por vez. Na linha 5, há a
inicialização dos valores de cada variável utilizando o operador de atribuição. A linha 6
declara um laço de repetição, assunto que será abordado em aulas futuras. Entre a linha
7 e a linha 11, o algoritmo em si, conforme explicado anteriormente, é executado com sua
lógica de comparação e incremento das variáveis. E, por fim, na linha 13 há a impressão
do resultado.
Observe que no decorrer do código utilizamos os operadores aritméticos de adição, os
operadores relacionais de maior e menor e operador de atribuição. Um exercício
interessante para fixar ainda mais o conteúdo é reler o código e marcar todas as
ocorrências de cada operador indicando seu tipo.
Desse modo você aprendeu a manipular variáveis e operadores para construir algoritmos
básicos utilizando pseudocódigo.
VÍDEO RESUMO
Olá, estudante, no vídeo desta aula abordaremos a importância de pensar em algoritmos,
como desenvolver um algoritmo eficiente, assim como os principais elementos que o
constituem como variáveis, constantes e os principais operadores.
Saiba mais
O pensamento algorítmico é fundamental para um bom programador. Nesse sentido, uma
das maneiras de entrar no mundo dos códigos é por meio dos jogos.
CodeCombat - Jogo online para aprender a programar.
CodinGame - Jogo que envolve programação em várias linguagens.
Aula 4
ALGORITMOS
Nesta aula você terá um contato mais aprofundado com a construção e o
desenvolvimento dos algoritmos. Serão introduzidos conceitos importantes de
representação de algoritmos antes do momento da implementação utilizando linguagens
de programação.
INTRODUÇÃO
Olá, estudante.
Nesta aula você terá um contato mais aprofundado com a construção e o
desenvolvimento dos algoritmos. Serão introduzidos conceitos importantes de
representação de algoritmos antes do momento da implementação utilizando linguagens
de programação. Afinal, você deve se perguntar se um algoritmo só pode ser
implementado utilizando uma linguagem específica como a C, Java ou outras. E, para
isso, mostraremos as técnicas de descrição narrativa e pseudocódigo, além de abordar a
https://www.codingame.com/start
https://codecombat.com/
declaração de variáveis e entrada e saída de dados por meio delas.
Bons estudos!
CONSTRUÇÃO DE ALGORITMOS
Estudante, neta aula, você aprenderá mais algumas características dos algoritmos que
são importantes neste momento do início da sua jornada pelo mundo da programação.
Você já aprendeu que para desenvolver uma solução para qualquer problema
computacional é preciso compreender o problema, esboçar uma solução e aí então iniciar
a escrita. Neste momento, introduziremos duas maneiras de escrever o projeto de
algoritmos: a descrição narrativa e o pseudocódigo.
Vale ressaltar que ambas as técnicas não são programas em linguagem de máquina, isto
é, que podem ser compilados e executados, mas, sim, instruções redigidas em ordem e
estrutura definidas para que a lógica da programação esteja clara para futuros
desenvolvimentos.
Neste sentido, podemos afirmar que essas técnicas assemelham-se a um esboço do
código final, apresentando os principais passos para resolver um problema em um nível
de abstração mais alto, em que detalhes da implementação por vezes não estão
presentes. Por isso, esse tipo de representação pode ser chamado de também de alto
nível, pois o nível de abstração é maior, em oposição às linguagens de baixo nível, que
são linguagens mais próximas à linguagem utilizada para a manipulação direta das
estruturas físicas do computador.
Assim, a definição da descrição narrativa pode ser ampliada para a representação passo
a passo em linguagem natural das instruções do algoritmo e o pseudocódigo, de modo
muito similar, da descrição dos passos em maiores detalhes e com maior capacidade de
representação de estruturas. Por exemplo: com o pseudocódigo é possível explicitar a
declaração de variáveis, isto é, deixar claro o nome da variável e seu tipo, como no
exemplo a seguir:
num1: inteiro;
Neste caso foi declarada a variável chamada num1 do tipo numérico inteiro. Note que, na
descrição narrativa, não há a preocupação em declarar as variáveis, mas apenas informar
passos mais gerais. Outro elemento que a técnica de pseudocódigo permite aprofundar é
a entrada e saída de dados, que são as operações de leitura e impressão, por exemplo.
São estas operações que realizam a comunicação com cenários externos ao programa,
pois recebem os dados que serão utilizados para a execução de um programa e, após
seu processamento, devolvem o resultado em forma de saída. Uma maneira de
representar a leitura de um número no pseudocódigo seria:
ler(num1);
Assim, informa-se ao leitor que será realizada a operação (função ou método) de leitura
de algum valor e que este valor será armazenado na variável chamada num1.
Analogamente, a saída de dados também é representada da seguinte forma:
imprime(num1);
Neste caso está representada uma chamada a uma operação de impressão da variável
num1. Esta impressão poderia ser realizada em um terminal de saída, por exemplo, ou
atémesmo gravada em arquivos.
ETAPAS DE DESENVOLVIMENTO DE ALGORITMOS
Você já estudou sobre a importância de um bom algoritmo para resolver um problema
computacional, conheceu os principais operadores, as variáveis e constantes, porém
pode se questionar qual o próximo passo. Afinal, o projeto de algoritmos mentalmente é
importante, porém não suficiente, já que é preciso documentar e escrever os passos
utilizados.
Contudo, como estamos introduzindo o ensino da programação, antes de iniciar os
códigos diretamente utilizando uma linguagem de programação como o C, Java ou
Python, você aprenderá duas técnicas úteis para representar o algoritmo de modo inicial,
de modo a auxiliar no planejamento e visualização de uma solução para algum problema
proposto.
Descrição narrativa
A técnica da descrição narrativa tem como função a descrição em linguagem natural (no
nosso caso o português) dos passos necessários para resolver o problema proposto. Ou
seja, trata-se da descrição do algoritmo em uma linguagem mais próxima da resolução
mental proposta e, por isso, é a primeira forma de documentar e planejar um programa.
Podemos pensar em uma receita que buscamos na internet como uma descrição
narrativa, pois ali estão descritos os passos para realizar um prato em língua portuguesa,
ou seja, é altamente compreensível para o ser humano mas não é capaz de executar um
programa de computador. Para escrever uma descrição narrativa, basta inserir cada
passo da solução por linha. Por exemplo, para calcular o menor número dentre dois
números dados, o algoritmo em descrição narrativa seria o seguinte:
1. Ler os dois números
2. Comparar os números
3. Imprimir o menor
Dessa maneira, nota-se que a descrição narrativa é mais enxuta e objetiva.
Um elemento que aparece neste caso é a entrada e saída de dados. A entrada está
representada na linha 1, em que a instrução de leitura de dois números é informada. Esta
leitura pode ser do teclado ou de um arquivo. E a saída pode ser a impressão na tela, ou
a gravação em algum arquivo
Pseudocódigo
O uso do pseudocódigo pretende utilizar a linguagem natural com maiores detalhes
técnicos, indicando quais variáveis serão utilizadas e como as expressões serão
formadas. Para resolver o mesmo problema anterior, o pseudocódigo seria o seguinte:
1. num1: inteiro;
2. num2: inteiro;
3. ler(num1, num2);
4.
5. se num1>num2:
6. imprime(num2);
7. se num2 > num1:
8. imprime(num1);
Observe que neste caso deixamos claro quais as variáveis, seu tipo, como serão lidas e
alguns elementos mais claros de sintaxe, como o uso de ponto e vírgula ao fim de cada
linha. Apesar de possuir mais regras de sintaxe que a descrição narrativa, o pseudocódigo
também não serve para ser executado como um programa de computador, mas sim para
elucidar e auxiliar no planejamento de algoritmos.
ALGORITMOS NA PRÁTICA
Agora, veremos alguns exemplos práticos na construção de algoritmos utilizando a
descrição narrativa e a técnica de pseudocódigo apresentadas anteriormente.
Tomemos como base para a construção dos códigos o seguinte problema: você deve
desenvolver um programa de computador para uma agência de monitoramento climático
e foi solicitado que, com os dados de temperatura de sete dias da semana, você escreva
um programa que calcule a média das temperaturas.
Para iniciar o desenvolvimento do código, é preciso, inicialmente, estudar o problema e
analisar as entradas do programa. Neste caso, o problema principal é calcular a média de
7 temperaturas e a solução é aplicar a fórmula da média, sendo dividir a soma dos valores
pela quantidade de valores, no caso o número de dias da semana. Para analisar as
entradas, observamos que o programa irá receber 7 valores de temperatura, que serão
valores reais. Portanto, até o momento, já sabemos a fórmula que devemos implementar
e os tipos dos valores utilizados que serão transformados em variáveis.
Por fim, é preciso analisar qual será a saída do programa, isto é, qual o resultado. No
nosso caso, o resultado será a impressão da média calculada.
Desse modo, temos as condições necessárias para desenvolver o código. Iniciaremos
mostrando o código em descrição narrativa:
1. Ler os 7 valores de temperatura
2. Somar os 7 valores
3. Dividir a soma dos valores por 7
4. Armazenar o resultado na média
5. Imprimir a média calculada
Assim, é possível notar que o programa em descrição narrativa é simples e direto,
evidenciado em linhas gerais os passos que serão efetuados, porém sem apresentar
detalhes maiores, como as variáveis utilizadas.
Em seguida, apresentamos o código em pseudocódigo:
1. temp1: real;
2. temp2: real;
3. temp3: real;
4. temp4: real;
5. temp5: real;
6. temp6: real;
7. temp7: real;
8. soma: real;
9. media: real;
10.
11. ler(temp1, temp2, temp3, temp4, temp5, temp6, temp7);
12. soma <- temp1 + temp2 + temp3 + temp4 + temp5 + temp6 + temp7;
media <- soma/7;
13. media <- soma/7;
14. imprime(media);
Em relação ao exemplo em pseudocódigo, é possível observar que o código tem mais
detalhes que a descrição narrativa e é mais próximo a uma implementação real em
linguagem de programação. Neste caso, são descritas quais as variáveis e quais seus
tipos, como descrito das linhas 1 a 9, como se dá a entrada de dados, na linha 11, as
operações em si, linhas 12 e 13 e a saída de dados na linha 14.
Assim, você aprendeu duas técnicas para representar algoritmos que auxiliam no
planejamento e projeto, etapas importantes para a futura implementação nas linguagens
de programação.
VÍDEO RESUMO
Neste vídeo você verá maiores detalhes sobre as técnicas de descrição narrativa e
pseudocódigo por meio de mais um exemplo de cada, de modo a fixar este importante
conteúdo. Também abordaremos as estratégias de construção de algoritmos utilizando
variáveis e entrada e saída de dados.
Saiba mais
O uso de pseudocódigo é muito importante para visualizar a estratégia de resolução de
problemas antes da implementação em si. Existem diversas ferramentas que auxiliam no
aprendizado como a linguagem em pseudocódigo Portugol.
REFERÊNCIAS
Aula 1
DASGUPTA, S.; PAPADIMITRIOU, C.; VAZIRANI, U. Algoritmos. Porto Alegre: AMGH
Editora, 2009.
ZIVIANI, N. et al. Projeto de algoritmos: com implementações em Pascal e C. Luton:
Thomson, 2004.
Aula 2
LABRA, J. E.; FERNÁNDEZ, A. I. Lógica proposicional para informática. Cuaderno
Didáctico, n. 12, 1998.
MORTARI, C. A. Introdução à lógica. Unesp, 2001.
Aula 3
DASGUPTA, S.; PAPADIMITRIOU, C.; VAZIRANI, U. Algoritmos. Porto Alegre: AMGH
Editora, 2009.
ZIVIANI, N. et al. Projeto de algoritmos: com implementações em Pascal e C. Luton:
Thomson, 2004.
https://portugol-webstudio.cubos.io/
Aula 4
DASGUPTA, S.; PAPADIMITRIOU, C.; VAZIRANI, U. Algoritmos. Porto Alegre: AMGH
Editora, 2009.
ZIVIANI, N. et al. Projeto de algoritmos: com implementações em Pascal e C. Luton:
Thomson, 2004.
UNIDADE 2
ELEMENTOS DE ALGORITMOS
•Aula 1 - Representações de algoritmos
•Aula 2 - Execução sequencial e estruturas de decisão
•Aula 3 - Estruturas de repetição
•Aula 4 - Variáveis indexadas
•Referências
Aula 1
REPRESENTAÇÕES DE ALGORITMOS
Nesta aula você aprenderá a definição de algoritmos, sua aplicabilidade e conceito como
peça fundamental para desenvolvimento de um programa de computador.
INTRODUÇÃO
Olá, estudante!
Nesta aula você aprenderá a definição de algoritmos, sua aplicabilidade e conceito como
peça fundamental para desenvolvimento de um programa de computador. Também irá
estudar quais as principais propriedades de um algoritmo e como fluxogramas podem ser
criados para representar algoritmos.
Todo este conhecimento é a base fundamental para a construção de softwares, já que
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U2/index.html#referencias
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U2/index.html#aula4
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U2/index.html#aula3https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U2/index.html#aula2
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U2/index.html#aula1
você exercitará a criação da lógica necessária para o processo de desenvolvimento de
novas aplicações ou manutenção em aplicações já existentes.
Lembre-se que o seu aprendizado só dependerá de você, então, não se limite apenas ao
estudado em aula, mas busque, de forma proativa, ampliar seus conhecimentos.
Bons estudos!
O QUE SÃO ALGORITMOS E QUAIS SUAS APLICABILIDADES
Em seu cotidiano, todas as ações que você executa têm uma sequência lógica de passos
para sua conclusão. Mesmo que, de forma inconsciente, você não precise ficar
raciocinando sobre a ordem de execução de cada passo, em algum momento, alguém te
ensinou a sequência que você reproduz. A esta sequência lógica de passos para executar
uma ação denominamos algoritmo.
Os passos necessários para obter um resultado de uma ação, como, por exemplo,
preparar uma receita culinária, devem seguir uma sequência lógica com o objetivo de
estabelecer uma ordem no pensamento das etapas que deverão ser seguidas para que a
refeição, ao final do processo, esteja pronta.
Segundo o que apresenta Forbellone (1993), a sequência finita e ordenada de passos
necessária para se atingir um objetivo (como trocar um pneu, preparar uma receita
culinária ou sair de casa para ir ao trabalho) é o que se conhece como um algoritmo.
Um programa de computador (software) é a representação, por meio de uma linguagem
de programação, de uma lógica que irá resultar em um comportamento esperado para o
programa, como, por exemplo, o cadastro de dados de uma pessoa em uma clínica
médica, marcação de consultas a partir de uma agenda disponível de um médico, dentre
outros exemplos do nosso cotidiano.
Então, antes da construção de qualquer programa de computador, é necessário entender
o processo de raciocínio lógico e a definição dos passos necessários para a construção
de um algoritmo.
Como exemplo de um algoritmo simples para, por exemplo, abrir uma porta trancada,
você pode listar os seguintes passos:
1. selecionar a chave correta para a fechadura que se deseja abrir;
2. inserir a chave na fechadura;
3. se a chave encaixou corretamente, então:
3.1 gire a chave no sentido anti-horário uma volta;
3.2 tente abrir a porta. Se a porta abriu, então:
3.2.1 porta aberta com sucesso.
3.3 Se a porta não abriu, então:
3.3.1 Volte ao passo 3.1
Quando os passos, em sua respectiva sequência lógica, são listados, é possível perceber,
por exemplo, que cada tarefa tem um certo nível de complexidade e um determinado
padrão de comportamento (uma porta que possua chaves mecânicas sempre seguirá a
mesma lógica para sua abertura).
É importante mencionar que, em muitos casos, será necessário que o usuário forneça
algumas informações de entrada ao algoritmo (como nome, endereço e RG de uma
pessoa que será cadastrada como aluna em uma instituição de ensino, por exemplo), que
passará por um processamento (como uma validação, por exemplo), gerando um
resultado (efetuar o cadastro do aluno com sucesso).
Para que a lógica de um algoritmo possa ser representada de modo que fique claro para
outras pessoas que conheçam lógica de programação e algoritmos, você poderá utilizar
um fluxograma, ou seja, a representação gráfica de um fluxo de passos sequenciais, por
meio do uso de símbolos com significados específicos.
Conforme nos apresenta Pressman (1995), a construção de um fluxograma é um método
bastante utilizado para representação da lógica de um algoritmo por ser simples, fazendo
uso de losangos para representação de uma condição de controle e setas para mostrar
qual o fluxo a seguir, conforme cada alternativa possível que parta do fluxo de condição.
Uma sequência de passos pode ser representada por meio de retângulos. Detalharemos
a representação utilizando fluxogramas em um momento posterior neste texto.
PRINCIPAIS CARACTERÍSTICAS DE UM ALGORITMO
Toda lógica que se pretende transferir a um programa de computador poderá ter
diferenças na forma como as etapas são ordenadas para se atingir o objetivo desejado, a
depender da maneira pela qual quem está construindo o algoritmo ordene seu
pensamento lógico.
Porém, existem alguns pontos fundamentais para garantir que um algoritmo seja
compreendido facilmente e, caso necessário, sofra alterações evolutivas (quando se
deseja acrescentar novas funcionalidades a uma aplicação), adaptativas (quando se
deseja ajustar funcionalidades já existentes para o que o usuário considera mais
adequado para resolver seus problemas) ou corretivas (quando é feita correção de erros
detectados durante a utilização do programa). A estes pontos damos o nome
de propriedades de um algoritmo.
Quando a construção de um algoritmo se preocupa em garantir que as principais
propriedades serão respeitadas, o processo de representação deste algoritmo em
fluxograma será facilitado, garantindo maior probabilidade de sucesso ao longo do
processo de codificação (implementação) de sua lógica.
Uma das propriedades dos algoritmos é a sequenciação, já que, para que se atinja um
objetivo específico (como cadastrar os dados um usuário, extrair um relatório, etc.), é
preciso que os passos necessários para a concretização da funcionalidade sejam
definidos em uma ordem sequencialmente lógica. Por exemplo: caso o seu algoritmo seja
de cadastro de dados de um paciente, é preciso que uma tela contendo os campos que
serão informados pelo usuário possa aparecer, seguindo-se do preenchimento destes
campos e do envio para que possam ser validados (conforme as regras de negócio) e
cadastrados. Caso o envio aconteça antes da etapa de informação dos dados, a
sequência lógica será quebrada, não sendo possível alcançar o propósito final
(cadastramento dos dados).
A complexidade é outra propriedade importante para um algoritmo. Quanto mais simples
os passos e a sequência lógica destes passos aconteçam, mais simples será seu
algoritmo, sendo mais fácil de ser construído e mantido posteriormente.
Um fator que aumenta a complexidade, de forma considerável, conforme apresenta
Forbellone (1993), é a relação entre o que deve ser feito e o como deve ser feito, que
pode levar a respostas tão complexas que não cheguem a nenhuma solução.
Quando você perguntar “O quê?”, terá uma resposta direta e objetiva. Por exemplo: na
pergunta “O que é um relógio?”, uma resposta objetiva seria similar a “instrumento que
apresenta a passagem do tempo, ao longo de um dia”. Já a pergunta “Como é um
relógio?”, por outro lado, poderá ter diferentes e irrelevantes respostas, como “objeto
esférico com ou sem ponteiros, com tamanhos variados, que pode ser de parede,
bancada ou de pulso”.
A legibilidade é uma propriedade importante para garantir que outras pessoas irão
conseguir ler o seu algoritmo e ter um mesmo entendimento a respeito de seu objetivo.
Quanto maior for a legibilidade de um algoritmo, mais facilmente ele será entendido e
menor será sua complexidade.
Outra propriedade importante de um algoritmo é a portabilidade. Construir um algoritmo
que possa ser executado em diferentes sistemas operacionais e diferentes arquiteturas de
máquina (hardware) é uma questão importante para englobar os mais diferentes perfis e
tipos de usuários de uma aplicação. Um algoritmo, por ser apenas a representação de
uma sequência lógica de passos que irão resolver um problema do mundo real do
usuário, poderá ser escrito (implementado) utilizando diferentes linguagens de
programação e para os mais diferentes ambientes de execução.
Todas estas propriedades são importantes para garantir que, após a definição de quais
passos serão necessários para se atingir um objetivo com um algoritmo, a sua
representação em fluxogramas seja feita de forma fácil, contendo apenas os passos
estritamente necessários, sem maiores complexidades e de fácil manutenibilidade(facilidade de manutenção futura).
UTILIZANDO FLUXOGRAMAS PARA A REPRESENTAÇÃO DE ALGORITMOS
Algoritmos podem ser representados por meio de fluxogramas, como já mencionado, já
que esta ferramenta possui os elementos gráficos necessários para representação de
uma sequência de passos, com representação para tomada de decisões e fluxo de
repetição de passos.
Todo fluxograma tem um início e um fim, sendo o início representado pela primeira ação
(ou passo) a ser executada para se atingir o objetivo da lógica estruturada. É importante
que você defina um “gatilho” para que a sua lógica seja iniciada, ou seja, uma ação que
deverá ser feita pelo usuário (como o clique em um botão de menu, a abertura de uma
tela contendo um formulário, dentre outras), para que a sequência de passos possa,
então, seguir a partir desta ação inicial.
Tabela 1 | Principais símbolos de um fluxograma
Elemento Significado
Elemento que indica início do fluxo a ser
construído.
Elemento que indica um passo a ser executado,
em forma sequencial.
Elemento que indica uma condição (pergunta)
que irá alterar o fluxo da execução, conforme a
Elemento Significado
resposta (Sim ou Não).
Elemento que indica sequência do fluxo.
Elemento que indica término do fluxo.
Fonte: elaborada pela autora.
A Tabela 1 apresenta um resumo dos principais elementos que são utilizados para
construção de um fluxograma. É possível, por exemplo, criar fluxos contendo apenas
elementos sequenciais ou, em fluxos mais elaborados, contendo fluxos alternativos, que
irão partir de tomada de decisões.
A Figura 1 apresenta um exemplo de um fluxograma básico, sem estrutura de controle,
apenas com um sequenciamento de passos do início ao fim.
O início de todo fluxograma deve ser representado com um conector, que irá exibir qual
será o primeiro passo para ser executado em busca do resultado esperado.
Figura 1 | Representação de um fluxograma simples
Fonte: elaborada pela autora.
A Figura 1 apresenta uma sequência de passos simples para o envio de um e-mail a um
ou mais destinatários. O primeiro elemento do fluxo apresenta um conector, indicando que
o processo será iniciado. Cada caixa retangular irá indicar um passo a ser executado,
sendo ligadas por setas, que indicam a sequência que deverá ser seguida. Ao final do
processo, um elemento que representa a conclusão do fluxo, sendo representado por um
elemento ovalado, apresenta o objetivo concluído (que é o e-mail enviado).
Para fluxos mais complexos, que incluem situações de tomadas de decisão ou fluxo de
repetição de passos, elementos que representam os caminhos alternativos a serem
seguidos podem ser inseridos no fluxo, conforme apresentado na Figura 2.
Figura 2 | Fluxograma com tomada de decisão
Fonte: elaborada pela autora.
A Figura 2 apresenta uma sequência de passos para a abertura de uma porta, conforme
exemplo apresentado em momento anterior neste texto. Após o conector que representa o
início do processo ter sido inserido, então o fluxo se inicia com uma pergunta condicional
sobre a chave, se é compatível com a fechadura da porta a ser aberta ou não. Caso seja
compatível, o fluxo será alternado para o ramo da esquerda, seguindo pelas etapas de
girar a chave, verificar se a porta se abriu e, caso a porta não abra, então, o fluxo
retornará para a etapa de girar chave no sentido anti-horário, repetindo os passos abaixo
deste. Caso a porta se abra, então o fluxo será finalizado.
Uma pessoa que não tenha elaborado este fluxograma, ao realizar a leitura deste, deverá
ter o mesmo entendimento dos passos e fluxos condicionais, o que caracteriza a
propriedade de legibilidade do algoritmo.
A partir de um fluxograma, deverá ser possível implementar sua lógica em qualquer
linguagem de programação desejada.
VÍDEO RESUMO
Olá, estudante! Neste vídeo você aprenderá os principais conceitos e aplicações de um
algoritmo, a importância da sequência lógica de passos para construção de um algoritmo,
suas principais propriedades e a importância de cada propriedade.
Você também irá aprender a importância de um fluxograma para a construção de um
algoritmo e como a construção destes fluxogramas poderá ser utilizada para representar
um algoritmo.
Saiba mais
Com a ferramenta gratuita diagrams.net (draw.io), é possível criar fluxogramas de uma
forma simples, sem a necessidade de criar contas ou realizar login.
A ferramenta gratuita Portugol Webstudio é voltada para o teste da lógica de
programação, em linguagem natural, para iniciantes no aprendizado de algoritmos. Você
poderá ver um exemplo clicando no link “Abrir Exemplo” e, ao clicar em “Novo Arquivo”,
poderá criar a sua própria lógica. Inicie a partir do exemplo Entrada e Saída à Olá, mundo.
É o mais simples e o que você poderá reproduzir de forma mais fácil. A partir daí, vá
seguindo com os demais exemplos, sempre tentando aglutinar os exemplos aprendidos
em um mesmo arquivo.
Aula 2
EXECUÇÃO SEQUENCIAL E ESTRUTURAS DE DECISÃO
Nesta aula, você aprenderá a estrutura básica necessária para elaboração de um
programa de computador.
INTRODUÇÃO
Olá, estudante!
Nesta aula, você aprenderá a estrutura básica necessária para elaboração de
um programa de computador, quais são as estruturas sequenciais que podem
ser utilizadas e quais elementos podem ser utilizados como formas de decisão
https://dgadelha.github.io/Portugol-Webstudio/
https://dgadelha.github.io/Portugol-Webstudio/
https://app.diagrams.net/
no seu código, que irão permitir que o fluxo principal seja alternado para outro
fluxo, conforme o teste de uma condição específica (que poderá dar verdadeiro
ou falso como resultado).
Ao final desta aula, você será capaz de criar um código simples, contendo
estruturas sequenciais e de decisão.
Lembre-se que você é responsável pelo seu aprendizado, então, não se limite
apenas ao visto em aula, mas busque enriquecer seus conhecimentos por meio
de outras fontes confiáveis.
Bons estudos!
ESTRUTURAS SEQUENCIAIS E CONDICIONAIS DE UM
ALGORITMO
Um algoritmo, para que possa ser legível e interpretado por um computador ou
outra pessoa, precisa seguir uma estrutura básica, mantendo sua organização
lógica e seguindo um fluxo principal, que irá culminar no resultado (objetivo
final) desejado.
Então, é preciso que as estruturas sequenciais, como a declaração
de variáveis (endereços de memória que irão receber valores que variam ao
longo do tempo) e declaração de constantes (informações que são definidas
uma única vez na lógica, não sofrendo alterações ao longo do tempo) precisam
estar organizadas logo no início do seu algoritmo. É possível definir valores
para as variáveis declaradas, por meio do processo de atribuição, que pode ser
proveniente da execução de uma operação matemática ou um número já
definido.
Uma característica de uma variável é a sua tipificação, ou seja, ela irá
armazenar valores de um mesmo tipo de dados, que pode ser inteiro, real
(ponto flutuante), caractere (que armazena texto, podendo ser um ou mais
caracteres) e lógico (também conhecido como booleano, por armazenar os
valores verdadeiro ou falso). Então, se uma variável é declarada como inteiro,
ela não poderá armazenar números com pontos flutuantes ou informações
textuais, pois irá contra a sua tipificação.
Figura 1 | Fluxo para declaração de variáveis
Fonte: adaptada de Forbellone (1995).
A Figura 1 apresenta a forma como uma variável deve ser declarada. Primeiro,
você deverá definir qual será o tipo de dado (ou tipo primitivo) que ela irá
armazenar, seguindo-se do caractere “:” e do nome (identificador) que irá
representar a sua variável. Para finalizar a sua declaração, você deverá utilizar
o caractere “;”, indicando a finalização do comando.
Um exemplo simples de declaração de variáveis.
caractere : nomePaciente;
inteiro : idade;
real : valorConsulta;
logico : ehPrimeiraConsulta;
O exemplo mostra algumas variáveis sendo declaradas com seus respectivos
tipos primários associados. Então, temos uma variávelque irá armazenar texto,
com identificador nomePaciente, uma variável que irá armazenar números
inteiros, com identificador idade, uma variável que irá armazenar números com
ponto flutuante, com identificador valorConsulta e uma variável que irá
armazenar um valor lógico (verdadeiro ou falso), com
identificador ehPrimeiraConsulta.
Com estas variáveis declaradas, você poderá solicitar informações (entrada de
dados) ao usuário que executará sua aplicação ou armazenar resultado de
operações matemáticas (cálculos utilizando números simples ou outras
variáveis). Estas operações irão seguir uma sequência lógica, que irá
representar os passos do seu algoritmo. A seguir veja um exemplo de um
algoritmo contendo uma estrutura sequencial simples para ler e escrever um
número informado pelo usuário.
1 inteiro : numero;
2 leia (numero);
3 escreva "o número digitado foi: " + numero;
Observe que, as operações acontecem de forma sequencial, ou seja, primeiro
(linha 1) é declarada a variável que irá armazenar o valor informado pelo
usuário, que será numérico. Em seguida, na linha 2, você irá solicitar ao usuário
que digite um valor e, na linha 3, o valor digitado será concatenado (símbolo de
+) ao texto entre aspas duplas, apresentando qual foi o valor digitado.
É possível, além de realizar operações simples de atribuição, também
acrescentar comandos condicionais, que irão realizar uma avaliação lógica de
uma condição e, a depender do resultado verdadeiro ou falso, alterar o fluxo
principal para alternativos. O comando condicional mais simples para
testar uma condição é o se, que pode ser estruturado conforme exemplo a
seguir.
Se <condição_a_ser_testada> Então
Lógica, caso verdadeira a condição
Senão
Lógica, caso falsa a condição
O fluxograma que representa uma condicional simples se deve ser elaborado
conforme apresentado na Figura 2.
Figura 2 | Fluxograma para uma estrutura de decisão simples
Fonte: elaborada pela autora.
A Figura 2 apresenta o fluxo para uma condicional simples se. A partir do teste
de uma condição, caso a resposta seja verdadeira, então uma sequência
específica de comandos deverá ser executada. Caso o resultado lógico do teste
seja falso, então um outro conjunto de comandos poderá ser executado. Após
o término de execução da estrutura condicional, o algoritmo irá retomar seu
fluxo principal de passos até a sua conclusão. Iremos apresentar um exemplo
prático em momento posterior nesta aula.
Também é possível fazermos uma condição mais complexa, que envolva
diferentes opções de resultado, conhecida como escolha. Um comando do
tipo escolha irá avaliar o valor de uma variável simples declarada conforme
uma lista de diferentes opções. A lógica do seu algoritmo, então, poderá ser
alterada para a opção que o valor for igual ao valor contido na variável. A seguir
veja a estrutura condicional complexa escolha.
Escolha <variável>:
caso <valor_variável1>:
<sua lógica>
caso <valor_variável2>:
<sua lógica>
caso <valor_variável3>:
<sua lógica>
caso contrário:
<sua lógica>
Com a estrutura condicional complexa escolha, cujo formato de declaração
está apresentado, você poderá testar o valor de uma variável dentre um
conjunto de valores, construindo uma lógica diferente para cada possibilidade
de valor. Caso nenhuma das possibilidades listadas seja atendida, o fluxo irá
seguir a lógica do caso contrário.
O fluxograma que representa uma condicional complexa escolha segue o
modelo apresentado na Figura 3.
Figura 3 | Fluxograma para a estrutura condicional complexa escolha
Fonte: elaborada pela autora.
A Figura 3 apresenta como deverá ficar um diagrama de fluxo para uma
condicional do tipo escolha. A escolha se dará a partir do valor que uma
variável poderá assumir, sendo executado o bloco de instruções que irá
corresponder ao valor já conhecido e que a variável esteja assumindo no
momento do teste. Caso nenhum dos valores possíveis seja igual ao valor atual
da variável testada, então a cláusula caso contrário terá suas instruções
executadas (comportamento padrão).
COMO E QUANDO UTILIZAR CADA TIPO DE ESTRUTURA EM
UM ALGORITMO
Vamos iniciar com um exemplo de algoritmo simples, para que você possa
entender em qual momento poderá utilizar cada tipo de estrutura apresentada
anteriormente.
Caso você precise construir uma lógica para testar se a idade informada pelo
usuário é menor ou maior que 60 anos, você irá utilizar uma estrutura
condicional simples da seguinte forma:
• Caso a idade informada seja menor que 60 anos, então você deverá
apresentar a mensagem “Idade menor que 60”;
• Caso a idade informada seja maior ou igual a 60, a mensagem apresentada
deverá ser “Idade igual ou superior a 60”.
Para transcrever a lógica acima apresentada para um algoritmo, você deverá
utilizar uma estrutura condicional se – senão simples, como mostrado a
seguir.
1 se (idade < 60) então
2 escreva "Idade menor que 60.";
3 senão
4 escreva "Idade maior ou igual a 60";
Porém, no exemplo apresentado, não é possível saber se a idade informada é
igual a 60 ou maior, caso entre na condição senão. Então, vamos alterar a
lógica para apresentar uma mensagem personalizada para cada faixa etária, da
seguinte forma:
• Caso a idade do usuário esteja entre 16 e 18 anos, você irá apresentar a
mensagem “Olá, adolescente!”;
• Caso a idade do usuário esteja entre 19 e 59 anos, você irá apresentar a
mensagem “Olá, adulto!”;
• Caso a idade do usuário esteja acima de 60 anos, você irá apresentar a
mensagem “Olá, idoso!”;
• Caso a idade não do usuário for abaixo de 16 anos, a mensagem deverá ser
“Não permitido uso por pessoas com idade inferior a 16 anos.”.
Existem formas diferentes de construir esta lógica. Caso você tenha listado os
passos do algoritmo utilizando o operador condicional simples se, você deverá
realizar um teste para cada condição, ou seja, um para cada faixa etária que se
deseja verificar a idade que o usuário informou. Isso irá encadear vários
comandos condicionais se, para a resolução do algoritmo proposto.
1 se (idade >= 16 e idade <=19) então
2 escreva “Olá, adolescente!”;
3 senão se (idade >=20 e idade <=59) então
4 escreva “Olá, adulto!”;
5 senão se (idade >= 60) então
6 escreva “Olá, idoso!”;
7 senão
8 escreva “Não permitido uso por pessoas com idade inferior
a 16 anos.”;
Perceba, conforme o apresentado, que o teste de cada se irá retornar um valor
lógico verdadeiro ou falso. Além disso, a idade informada pelo usuário,
antes que os testes sejam feitos, deverá ser lida pela sua lógica, caracterizando
então a necessidade de armazenamento temporário desta informação em
uma variável do tipo inteiro.
Porém, estamos considerando que o usuário já irá informar a idade dele, não a
data de nascimento para que o cálculo da idade seja feito, a partir do ano atual.
Então, seguindo esta linha de raciocínio, você deverá listar os passos iniciais do
seu algoritmo como:
1. Solicitar ao usuário que informe sua idade;
2. Armazenar a idade informada em uma variável para testes;
3. Testar a idade informada para cada faixa etária desejada.
O comando condicional complexo escolha serve para que você possa
simplificar a sua lógica, em caso de muitas condicionais simples se aninhadas.
Trocando o tipo de estrutura por uma escolha, você poderá testar, em uma
única condição, todas as opções que desejar como possiblidades,
possibilitando, ainda, a definição de uma mensagem padrão, caso nenhuma das
opções sejam atendidas.
Uma diferença, porém, entre os comandos condicionais simples se e
complexo escolha, é o tipo de teste que deve ser feito para que o fluxo
principal possa ser alternado. Enquanto o se poderá ter mais de uma condição
em seu teste, como o exemplo se (idade > 18) e (nome = ‘João’ ou nome =
‘Maria’) então, o condicional escolha irá selecionar, dentre uma lista de
valores, os que podem ser assumidos por uma determinada variável, sem,
efetivamente, testar uma ou mais condições.
Um exemplo de usoda estrutura condicional escolha pode ser visto a partir da
alteração do algoritmo apresentado a seguir.
1 escreva "Digite sua faixa etária: 1 - Adolescente; 2 - Adulto;
3 - Idoso";
2 leia (faixa_etaria);
3
4 escolha(faixa_etaria)
5 caso 1
6 escreva “Olá, adolescente!”;
7 caso 2
8 escreva “Olá, adulto!”;
9 caso 3
10 escreva “Olá, idoso!”;
11 caso contrario:
12 escreva “Não é uma opção válida.”;
No exemplo, fizemos um pequeno ajuste solicitando que o usuário informe
números em uma faixa já esperada (1, 2 ou 3), indicando sua faixa etária.
Qualquer outro número informado será considerado opção inválida.
UTILIZANDO ESTRUTURAS SEQUENCIAIS NA CRIAÇÃO DE UM
ALGORITMO
Para que você ponha em prática todo o conteúdo estudado nesta aula, iremos
iniciar com um exemplo de um algoritmo básico, contendo uma estrutura
condicional simples se.
O exemplo inicial consiste na criação de um algoritmo para o cálculo de um
desconto de 10% em cima de um valor inteiro positivo informado pelo usuário,
apresentando, como resultado, o valor descontando (que irá representar os
10%). Se o valor descontado for igual ou superior a 20, então apresente a
mensagem “Valor inicial acima de 200”. Caso o valor descontado seja inferior a
20, então apresente a mensagem “Valor inicial entre 0 e 199”.
1 Ler valor
2 Calcular desconto de 10% em cima do valor lido
3 Escrever valor do desconto de 10% calculado
4 Se valor do desconto for igual ou superior a 20
5 Apresentar mensagem “Valor inicial acima de 200”
6 Se valor do desconto for inferior a 20
7 Apresentar mensagem “Valor inicial entre 0 e 199”
Conforme os passos apresentados para o algoritmo proposto, teremos, como
primeira ação, que solicitar um valor de entrada ao usuário. Este valor, no
entanto, deverá ser armazenado de forma temporária, até que uma nova
solicitação seja feita. Também deverá armazenar o resultado do valor do
desconto de 10% calculado, para que possa ser apresentada a mensagem
coerente com o resultado, após a execução do teste condicional.
1 inteiro : valor;
2 inteiro : resultadoDesconto;
3
4 leia(valor);
5 resultadoDesconto = valor * 0,10;
6
7 se (resultadoDesconto >= 20) então
8 escreva(“Valor inicial acima de 200”);
9
10 se (resultadoDesconto < 20) então
11 escreva(“Valor inicial entre 0 e 199”);
Vimos um algoritmo em pseudocódigo. Note que, nas linhas 1 e 2, as variáveis
que serão utilizadas no código estão sendo declaradas, sendo elas a
variável valor, que será informada pelo usuário, e a
variável resultadoDesconto, que armazenará o valor do desconto de 10%
sobre o valor informado. A linha 5 realiza uma operação de atribuição do
cálculo dos 10% sobre a variável valor à variável resultadoDesconto. As
linhas 7 e 10 apresentam o operador condicional simples se sendo utilizado
para testar o valor do resultado obtido com o cálculo dos 10%. O teste deverá
sempre retornar um verdadeiro ou falso, sendo que, no exemplo
apresentado, apenas o resultado verdadeiro irá apresentar a mensagem
contida na ação escreva em cada teste.
Note que, neste exemplo, podemos aperfeiçoar nossa lógica fazendo uma
pequena modificação nas linhas 7 e 10. Você poderá utilizar a
condição senão para o condicional se da linha 7, não sendo necessário fazer
um novo teste se, como apresentado na linha 10. Então, veja o exemplo de
alteração da lógica para uso do condicional senão.
1 inteiro : valor;
2 inteiro : resultadoDesconto;
3
4 leia(valor);
5 resultadoDesconto = valor * 0,10;
6
7 se (resultadoDesconto >= 20) então
8 escreva(“Valor inicial acima de 200”);
9 senão
10 escreva(“Valor inicial entre 0 e 199”);
A troca do condicional se, apresentado pelo condicional senão, apresentado
na linha 9 só é possível pois não existem outras opções, para o algoritmo
apresentado, de valores que a variável resultadoDesconto poderá assumir.
Para cada condicional se, você poderá utilizar um senão, que irá ser
executado caso o teste no se dê negativo.
Quando se utiliza o senão, qualquer outro valor que a
variável resultadoDesconto assuma, inclusive menor que zero, irá
apresentar a mensagem “Valor inicial entre 0 e 199”, o que não está de acordo
com o nosso requisito inicial. Então, é possível que um teste, ao dar negativo,
possa efetuar um novo teste, em sua cláusula senão, conforme o exemplo de
alteração do algoritmo para inclusão de se aninhado.
7 se (resultadoDesconto >= 20) então
8 escreva(“Valor inicial acima de 200”);
9 senão se (resultadoDesconto > 0) então
10 escreva(“Valor inicial entre 0 e 199”);
11 senão
12 escreva(“Valor inicial menor que 0”);
Na linha 9 do novo exemplo, em comparação com a linha 9 do exemplo anterior,
foi alterada para realizar um novo teste condicional se, em cima da
variável resultadoDesconto, para saber se seu valor é maior que zero
(atendendo, portanto, ao requisito de número inteiro positivo). Caso não seja um
inteiro positivo, o fluxo alternará para a linha 11, apresentando a mensagem de
“Valor inicial menor que 0”.
VÍDEO RESUMO
Olá, estudante! Neste vídeo, você irá aprender como um algoritmo deve ser
estruturado, sendo composto por elementos sequenciais e condicionais. Irá
aprender, também, um exemplo prático da estrutura condicional
complexa escolha. Seu código, ao final do vídeo, poderá ser elaborado de
modo a realizar tomada de decisões simples e complexa e alterar o fluxo
principal para fluxos alternativos, dependendo da resposta a cada decisão.
Saiba mais
Por meio do projeto Portugol, escolhendo a opção “Abrir Exemplo” à Algoritmos
sequenciais, você irá encontrar exemplos práticos para a definição de variáveis
(exemplo “Troca Variáveis”), além da utilização de condicionais simples
(exemplo “Maioridade penal”). Ao escolher o menu “Desvios condicionais”,
ainda nos exemplos disponíveis, é possível ver um exemplo de uso do
condicional complexo escolha em “Escolha – Caso”, além dos demais
exemplos, que apresentam variações do uso do condicional se.
Aula 3
ESTRUTURAS DE REPETIÇÃO
Nesta aula, você aprenderá os conceitos e a utilização das principais estruturas de
repetição de trechos de código em um algoritmo.
INTRODUÇÃO
Olá, estudante!
Nesta aula, você aprenderá os conceitos e a utilização das principais estruturas de repetição de
trechos de código em um algoritmo. Irá aprender em quais situações deverá aplicar cada uma das
estruturas apresentadas, o que são condições de parada e como elaborá-las para cada tipo de laço de
repetição.
Também serão apresentados os principais símbolos para representação dos laços de repetição em
fluxogramas. Desta forma, os diagramas de fluxo que você irá criar serão mais completos, podendo
representar lógicas mais complexas.
Lembre-se que você é responsável pelo seu aprendizado, então, não se limite apenas ao visto em
aula, mas busque enriquecer seus conhecimentos por meio de outras fontes confiáveis.
Bons estudos!
https://dgadelha.github.io/Portugol-Webstudio/
O QUE SÃO ESTRUTURAS DE REPETIÇÃO E COMO UTILIZÁ-LAS
Em sua lógica para a resolução de uma determinada tarefa do dia a dia, você poderá precisar que
um trecho desta tarefa se repita por uma quantidade limitada de vezes (até que uma condição de
parada seja satisfeita). Um bom exemplo é quando implementamos um algoritmo para subir uma
escada. Como você não sabe, logo no começo do processo, quantos degraus serão necessários subir
para que se chegue ao topo da escada, seu algoritmo deverá fazer uma sequência de passos, subindo
cada degrau individualmente, até que não existam mais degraus a subir e, consequentemente, se
tenha chegado ao topo da escada (objetivo final).
A ação de subir um degrau e realizar um teste (se chegou ou não ao topo) é listada uma única vez na
sequência de passos lógica do seu algoritmo, porém, esta ação se repetirá até que uma condição de
parada seja satisfeita (que é chegar ao topo da escada).
Existem diferentes formas de implementar uma estruturade repetição, como apresentado por
Forbellone (1993), sendo que cada uma será utilizada conforme a lógica que se deseja construir e os
dados disponíveis sobre o trecho que deverá ser repetido (que denominamos iteração).
O primeiro laço de repetição que você aprenderá é o enquanto – faça. Neste caso, a lógica deve ser
entendida como enquanto uma condição for verdadeira, então faça <sequência de comandos>. A
partir do momento que o teste desta condição especificada tiver resultado lógico falso, então o laço
não mais se repetirá, permitindo que as demais instruções declaradas após este laço sejam
executadas.
Um outro tipo de estrutura de repetição é o para – até – faça, no qual um número de repetições já
conhecido é informado para que o trecho da lógica seja repetido. Então, voltando ao exemplo do
algoritmo para subir uma escada, caso seja conhecida a quantidade de degraus que serão percorridos
por quem desejar subir a escada, esse número exato poderá ser utilizado para que a iteração do
trecho da lógica seja feita.
Porém, nem sempre é possível conhecer, em um momento prévio, a quantidade de vezes que um
determinado trecho da lógica será executado, mas sabe-se que ele deve ser executado ao menos uma
vez, antes que uma condição de parada possa ser testada e, caso a condição seja dada como falsa,
então o trecho será executado novamente e o teste será repetido até que dê verdadeiro, finalizando
a sequência de repetições. A esta estrutura, damos o nome de repita até.
Quando construirmos um fluxograma, além de comandos sequenciais e estruturas condicionais,
você poderá representar as estruturas de repetição apresentadas, utilizando uma combinação de
símbolos de decisão, controle de fluxo e leitura de dados (caso necessário), além do símbolo de
preparação, conforme apresentado na Tabela 1.
Tabela 1 | Símbolos utilizados em fluxogramas com laços de repetição
Elemento Significado
Preparação
para início de
um fluxo para
– até – faça,
indicando qual
variável irá
controlar o
fluxo, seu
valor inicial e
Elemento Significado
final.
Indica leitura
de dados já
armazenados,
fornecidos
pelo usuário.
Indica entrada
de dados de
forma manual
pelo usuário.
Indica uma
estrutura
condicional
(pergunta) que
poderá levar a
fluxos
diferentes,
conforme a
resposta (sim
ou não).
Indica um
conector, que
poderá
representar o
início de um
fluxo ou, para
laços de
repetição, o
início do laço.
Indica um
bloco de
comandos a
ser executado,
como fluxo
alternativo a
uma condição.
Indica a
finalização de
um
fluxograma.
Fonte: elaborada pela autora.
A Tabela 1 apresenta símbolos que podem ser utilizados na elaboração de fluxogramas que utilizam
laços de repetição. Muitas vezes, é necessário que o usuário forneça dados para que o algoritmo
possa realizar um processamento ou fazer algum cálculo matemático para se obter um resultado.
Desta forma, a leitura de dados deverá preceder laços que irão se repetir até que um objetivo seja
alcançado.
Quando se deseja subir uma escada, por exemplo, é possível que seja necessário percorrer vários
degraus, sendo que cada escada terá um número finito, porém diferente da quantidade de degraus de
outras escadas existentes. Iremos utilizar este exemplo para apresentar as mais variadas formas de
utilização dos laços de repetição, ainda nesta aula.
COMPREENDENDO AS SITUAÇÕES-PROBLEMA MAIS ADEQUADAS
PARA CADA TIPO DE ESTRUTURA DE REPETIÇÃO
Para que você possa compreender a sintaxe de cada laço de repetição e em quais situações aplicar
cada uma, vamos utilizar o exemplo já apresentado de algoritmo para subir uma escada.
Para que sejam percorridos degrau a degrau, é necessário que um laço de repetição aconteça, já que
não se sabe, ao certo, quantos degraus serão percorridos até que a escada chegue ao seu fim. Cada
laço terá, por sua vez, uma condição de parada diferente, ou seja, um teste que deverá ser executado
para saber se haverá ou não necessidade de subir mais um degrau.
A seguir veja o exemplo da condição para se utilizar o laço enquanto – faça.
1 enquanto <condição de parada> então faça
2 <lógica a ser executada caso condição de parada
for verdadeira>
3 fim enquanto
A linha 1 indica o início do laço de repetição. Caso a condição seja verdadeira, então, os comandos
da linha 2 serão executados, caso seja falsa, o fluxo terá sua execução interrompida.
A Figura 1 apresenta uma comparação entre a estrutura de um fluxograma para o laço enquanto –
faça e um exemplo de lógica real. Considerando o algoritmo da escada, a condição de parada é a
pergunta “a quantidade de degraus já percorridos é menor ou igual à quantidade total de degraus?”.
Caso a resposta seja sim, então mais um degrau será percorrido, repetindo o teste até que todos os
degraus tenham sido percorridos.
Figura 1 | Fluxograma para um laço enquanto – faça
Fonte: elaborada pela autora.
Em outro laço de repetição, o repita – até, todo o ciclo é executado ao menos uma vez para que,
após cada execução, a condição de parada possa ser testada e, caso falso, então uma nova iteração
será feita, porém, caso verdadeiro, então a execução será interrompida. Veja a seguir a sintaxe do
laço de repetição repita – até.
1 repita
2 <lógica a ser executada caso condição de parada
for falsa>
3 até <condição de parada>
Na linha 1, o início do laço de repetição com a palavra reservada repita. A linha 2 deverá englobar
todas as instruções que serão executadas, pelo menos uma vez, até que o teste da condição de
parada seja verdadeiro.
Fazendo uma analogia com o exemplo da escada, a condição de parada deve ser “até que a
quantidade de degraus percorrida seja igual à quantidade total de degraus informada”.
Figura 2 | Fluxograma para o laço repita – até
Fonte: elaborada pela autora.
A Figura 2 apresenta o fluxograma para o laço de repetição repita – até, fazendo uma comparação
com o fluxograma para a lógica da escada. A condição de parada deverá ser testada apenas após ao
menos uma iteração do ciclo. Perceba que, em comparação com a lógica utilizada para o
laço enquanto – faça, a condição de parada é alterada para até que a quantidade de degraus
percorridos seja igual ao máximo de degraus da escada. Além disso, como o laço deverá
acontecer ao menos uma vez, a variável qtdDegraus irá iniciar em zero, não mais em um (como
no enquanto – faça), sendo incrementada em uma unidade antes de cada teste.
Utilizando o exemplo da escada, temos que uma escada é composta por um ou mais degraus,
justificando a execução do laço ao menos uma vez.
Um outro laço, conhecido como para – até – faça, irá fazer uma iteração crescente ou decrescente
de uma variável, partindo de um valor inicial, até se atingir um valor final. Ao se chegar ao valor
final, que é a condição de parada deste laço, o ciclo será interrompido. Veja a seguir a sintaxe do
laço para – até – faça.
1 para <variável> de <início> até <final> faça
2 <lógica a ser executada caso o valor da variável
seja diferente do valor final>
3 fim para
A Figura 3 apresenta o fluxograma para um laço de repetição do tipo para – até – faça. Este fluxo
utiliza o símbolo de preparação, que contém a configuração inicial do fluxo, sendo uma variável e
seus valores inicial e final. É possível definir, também, um incremento, ou seja, um valor que será
somado ao inicial para se chegar ao final (também conhecido como passo), sendo necessário apenas
caso o incremento não seja sequencial.
Figura 3 | Fluxograma para o laço para – até – faça
Fonte: elaborada pela autora.
Considerando ainda o exemplo da escada, a lógica do para – até – faça pode ser aplicada quando
se pensa “para quantidade degraus percorridos de 1 até quantidade máxima degraus,
incrementando em uma unidade, faça”. Perceba que, neste laço, não é necessário que você faça o
incremento manual da variável qtdDegraus, que é feita de forma automáticapelo laço. Além disso,
não é necessário inicializar a variável qtdDegraus, já que ela irá receber um valor inicial no
momento da declaração do laço.
APLICANDO ESTRUTURAS DE REPETIÇÃO EM ALGORITMOS
A aplicação de cada tipo de laço de repetição será determinada pela necessidade de execução da
lógica e pela posição do teste de parada. Caso o teste de parada necessite ser executado primeiro, é
preciso utilizar o laço enquanto faça. Nesta situação, você não sabe quantas iterações serão
executadas ao certo, mas deverá realizar o teste antes de cada nova execução.
O laço enquanto faça irá repetir uma sequência lógica de passos até que uma determinada condição
se torne verdadeira, percorrendo, por exemplo, uma coleção de dados em busca de um dado que
satisfaça a condição de parada. Um exemplo poderá ser apresentado fazendo alusão ao nosso
algoritmo para subir os degraus de uma escada. Como não se sabe, ao certo, quantos degraus a
escada tem e você deseja utilizar o mesmo algoritmo (mesma lógica) para percorrer diferentes
escadas (com mais ou menos degraus), então você poderá pensar conforme o algoritmo para subir
uma escada com enquanto – faça, apresentado a seguir.
1 inteiro : qtdDegraus;
2 inteiro: topoEscada;
3
4 leia(topoEscada);
5 qtdDegraus = 1;
6
7 enquanto (qtdDegraus <= topoEscada) faça
8 qtdDegraus = qtdDegraus + 1; //sobe para o próximo degrau
9 escreva ("Subindo para o degrau " + qtdDegraus);
10 fim enquanto
No exemplo, será solicitado ao usuário que entre com a informação de quando se chegará ao topo
da escada (linha 7), com a quantidade total de degraus para se subir. O algoritmo, então, irá testar se
o degrau atual que o usuário está já é o topo e, caso ainda não se tenha chegado ao final da escada,
irá subir para o próximo degrau, por meio do incremento de uma unidade ao total de degraus já
percorridos (linha 8). Após se atingir o topo, ou seja, a quantidade de degraus já percorridos ser
maior que o topo da escada informado, então o laço deixará de se repetir. Note que, na linha 5,
atribuímos um valor inicial para a variável qtdDegraus, para que o laço se inicie a partir do
primeiro degrau da escada.
A seguir, veja um exemplo de utilização do laço repita – até. Neste exemplo, a quantidade de
degraus a ser percorrida (variável qtdDegraus) será inicializada com valor zero, sendo
incrementada em uma unidade até que se torne igual à quantidade total do topo, informada pelo
usuário. Uma diferença para o laço enquanto faça é a forma de elaboração da condição de parada.
Enquanto, no repita – até a condição de parada deverá ser verdadeira para que as repetições sejam
interrompidas, no laço enquanto faça a condição de parada deverá ser falsa para que o fluxo seja
interrompido.
1 inteiro : qtdDegraus;
2 inteiro: topoEscada;
3
4 leia(topoEscada);
5 qtdDegraus = 0;
6
7 repita
8 qtdDegraus = qtdDegraus + 1; //sobe para o próximo degrau
9 escreva ("Subindo para o degrau " + qtdDegraus);
10 até (qtdDegraus = topoEscada);
Quando se tem um número máximo de repetições para fazer a iteração de uma lógica, o laço de
repetição para – até – faça pode ser utilizado. Enquanto os laços enquanto – faça e repita –
até são utilizados quando não se sabe, exatamente, a quantidade de iterações que precisarão ser
feitas, com o laço para esta quantidade é bem definido, já que será o trecho da lógica será
percorrido uma quantidade N de vezes, de forma crescente ou decrescente, a partir de um contador
inicial. A seguir veja um exemplo de aplicação da estrutura de repetição para – até – faça.
1 inteiro : qtdDegraus;
2 inteiro: topoEscada;
3
4 leia(topoEscada);
5
6 para qtdDegraus de 1 até topoEscada faça
7 escreva ("Subindo para o degrau " + qtdDegraus);
8 fim_para;
A estrutura inicia na linha 6, o laço para – até – faça, de modo que a variável qtdDegraus terá seu
início com o valor 1, sendo incrementada de uma unidade até que seu valor seja maior que a
variável topoEscada, que é seu limite máximo, fazendo o ciclo interromper. Note que, na linha 7, o
comando escreva irá apresentar qual o degrau atual que está sendo percorrido.
VÍDEO RESUMO
Olá, estudante! Neste vídeo você aprenderá como aplicar cada laço de iteração na construção de
seus algoritmos, de modo a saber identificar as principais situações que necessitam de laços de
repetição e quais laços mais se adequam a quais situações. Também irá compreender a sintaxe
correta de construção de cada tipo de laço e como construir as condições de parada para cada
estrutura de repetição .
Saiba mais
Por meio do projeto Portugol, escolhendo a opção “Abrir Exemplo” à Laços de
repetição, você irá encontrar exemplos práticos para cada tipo de estrutura de
repetição apresentada. Se atente à forma de construção das condições de
parada em cada tipo de laço.
Aula 4
VARIÁVEIS INDEXADAS
Nesta aula, você aprenderá o conceito e a aplicação de estruturas de armazenamento de
dados mais complexas, como vetores, matrizes e registros.
INTRODUÇÃO
Olá, estudante!
Nesta aula, você aprenderá o conceito e a aplicação de estruturas de armazenamento de dados mais
complexas, como vetores, matrizes e registros. Você deverá, ao final desta aula, compreender o
funcionamento de cada estrutura e a melhor situação para aplicar cada uma no processo de
elaboração de seus algoritmos, tornando-os mais completos e com suporte a lógicas mais
complexas. Com o aprendizado destas estruturas, você terá concluído o estudo das principais
estruturas disponíveis para armazenamento e manipulação de dados em algoritmos.
Lembre-se que você é responsável pelo seu aprendizado, então, não se limite apenas ao visto em
aula, mas busque enriquecer seus conhecimentos por meio de outras fontes confiáveis.
Bons estudos!
https://dgadelha.github.io/Portugol-Webstudio/
O QUE SÃO VETORES, MATRIZES E REGISTROS
Ao elaborar uma lógica para um algoritmo, muitas vezes, você poderá ter a necessidade de
armazenar ou manipular um conjunto de dados do mesmo tipo ou até de tipos diferentes. Pense, por
exemplo, como você faria para armazenar uma faixa de valores inteiros, como a idade de todas as
pessoas de uma sala de aula, ou o nome de todas estas pessoas. Ao declarar uma variável de um tipo
primitivo, como inteiro ou caractere, você estaria armazenando apenas um único valor por vez, o
que não iria satisfazer a sua atual necessidade (de armazenar um conjunto de valores).
Para que exista a possibilidade de armazenamento de um conjunto de valores de um mesmo tipo,
temos o que se conhece como vetor ou variáveis compostas homogêneas, conforme nos explica
Forbellone (1993).
Um vetor unidimensional é uma estrutura que tem uma quantidade delimitada de posições, como
caixas de correio que podem estar armazenando diferentes valores do mesmo tipo. Sendo assim, em
analogia ao exemplo das pessoas, o vetor seria do tipo caractere e armazenaria uma quantidade de
valores que corresponda ao total de pessoas da sala de aula, o que se define como posições do vetor.
Cada posição, então, irá armazenar um nome (ex.: posição 1 armazena o nome “Maria”, posição 2
armazena o nome “João” e assim sucessivamente).
A denominação unidimensional é proveniente do conceito de existir uma única dimensão, ou seja,
seguir uma única direção (como uma fila indiana).
Figura 1 | Exemplo de vetor unidimensional
Fonte: elaborada pela autora.
A Figura 1 ilustra um exemplo de representação de um vetor unidimensional, no qual as
informações são armazenadas em sequência, sendo todas do mesmo tipo (caractere).
Existem outras situações, no entanto, que necessitam de uma estrutura de armazenamento mais
complexa que um vetor unidimensional, tendo mais de uma dimensão, ou seja, se comportando
como uma tabela (com linhas e colunas). Neste caso, podemos fazer uma analogia com o endereço
de uma casa, no qual o nome da rua deve ser procurado primeiro, seguindo-se do número da casa,
encontrando, assim, o endereço desejado. Trazendo esteconceito para a elaboração de algoritmos,
temos o que se denomina variáveis compostas multidimensionais ou matrizes.
Uma matriz é composta por mais de uma dimensão, o que implica que, caso uma informação seja
adicionada ou pesquisada, será necessário percorrer todas as dimensões do vetor para que o objetivo
(de armazenamento ou pesquisa) seja atingido.
Um conceito em comum entre matrizes e os vetores unidimensionais, porém, é o armazenamento
de um único tipo de dados, ou seja, todas as informações armazenadas deverão, obrigatoriamente,
ser do mesmo tipo (inteiro, real, caractere, lógico).
Figura 2 | Exemplo de uma matriz ou vetor multidimensional
Fonte: elaborada pela autora.
A Figura 2 ilustra um exemplo de um vetor multidimensional, também conhecido como matriz.
Neste caso, para que uma informação seja armazenada ou consultada, é preciso que todas as
dimensões sejam percorridas, ou seja, caso você esteja interessado em acessar o nome “Nilo”,
deverá ir até a linha 3, coluna 3 para que o objetivo seja alcançado.
O tipo mais complexo de armazenamento de dados são os registros, nos quais você poderá
armazenar diferentes tipos de dados que estejam correlacionados com um mesmo conceito, como o
nome, a idade, o endereço, CPF e altura de uma pessoa, por exemplo. Cada um destes dados está
atrelado a um tipo diferente de informação (inteiro, real e caractere), mas todos os dados estão
correlacionados com a mesma pessoa.
Cada informação armazenada por um registro é denominada campo deste registro. Então, pense no
registro como uma ficha de cadastramento, na qual cada campo da ficha corresponderá a um campo
do registro, conforme apresentado na Tabela 1.
Tabela 1 | Exemplo de uma ficha com diferentes tipos de informação sobre uma pessoa
Cadastro de pessoa
Nome: Fulano de Tal
Idade: 20 anos
Altura: 1,70m
CPF: 111.111.111 - 11
Endereço: Rua X, 1.
Fonte: elaborada pelo autor.
COMO APLICAR VARIÁVEIS INDEXADAS EM ALGORITMOS
Ao pensar na lógica para construção do seu algoritmo, você deve se deparar, em algum momento,
com situações nas quais é necessário armazenar uma coleção de dados, como uma faixa de valores.
Nestes casos, o tipo de estrutura que você vai utilizar dependerá de qual tipo de dados você deverá
coletar.
Caso sejam vários valores, porém todos de um mesmo tipo, o ideal é a utilização de um vetor
linear, ou seja, uma estrutura homogênea unidirecional. Como exemplo, podemos citar o
armazenamento de valores de uma determinada quantidade de mercadorias (como os produtos de
uma lista de compras), todas as matrículas dos funcionários de um setor e assim por diante.
Uma matriz, por outro lado, é composta por mais de uma dimensão, ou seja, mais de um vetor
linear. Desta forma, você poderá utilizar esta estrutura em situações nas quais necessite encontrar
uma informação dentro de uma determinada posição. Como exemplo, podemos citar os
apartamentos de um prédio. Digamos que cada andar tenha três apartamentos. Então, para que você
acesse o terceiro apartamento do quinto andar, por exemplo, você deverá se dirigir à quinta posição
do vetor de andares (primeira dimensão) e terceira posição do vetor de apartamentos (segunda
dimensão). Considerando que a matriz prédio seria representada como a junção de duas dimensões
(vetor de andares e vetor de apartamentos) lineares, sua representação visual seria como apresentada
na Figura 3.
Figura 3 | Exemplo de uma matriz com duas dimensões
Fonte: elaborada pela autora.
Os andares, na Figura 3, representam a primeira dimensão, já que deverá ser a primeira informação
a ser percorrida para que você consiga chegar ao apartamento desejado. Em seguida, a numeração
do apartamento, a qual representa a segunda dimensão da matriz, deverá ser procurada.
Observe que, tanto em vetores lineares quanto em matrizes homogêneas, o tipo de dado que será
armazenado deve ser do mesmo tipo em todas as posições. Sendo assim, a matriz prédio irá
armazenar, para a posição três do quinto andar, o número 503 (que representa o número do
apartamento), a posição dois do quinto andar irá armazenar o número 502 e assim sucessivamente.
Já para situações heterogêneas, você deverá armazenar diferentes tipos de dados (como uma coleção
de dados) que se referirão a uma determinada entidade (um objeto ou algo concreto do mundo real).
Retornando ao exemplo do prédio, imagine que você queira armazenar os dados do proprietário de
cada unidade (nome completo, CPF, telefone de contato, data de nascimento). Neste caso, você
deverá utilizar uma matriz heterogênea, ou seja, que irá armazenar diferentes tipos de informações
em suas posições. Para tanto, deverá utilizar um registro, que irá conter todos os dados necessários
para serem armazenados, que poderá ser nomeado como proprietário. Então, você terá a
representação apresentada na Figura 4.
Figura 4 | Conjunto de dados heterogêneos em um registro
Fonte: elaborada pela autora.
A Figura 4 apresenta o registro proprietário sendo armazenado em cada posição da matriz prédio.
Desta forma, para cada posição de apartamento do prédio, um conjunto de dados referentes ao
proprietário será armazenado, sendo estas informações de tipos primitivos diferentes (numérico,
real, caractere ou lógico).
EXEMPLOS DE UTILIZAÇÃO DAS ESTRUTURAS INDEXADAS
Para utilizar uma estrutura indexada em sua lógica, você deverá, após escolher qual o tipo de
estrutura que fará uso, declará-la como uma variável, definindo o valor de cada dimensão, ou seja,
quantas posições seu vetor linear terá ou, caso seja uma matriz, qual a quantidade de linhas e
colunas que ela terá. Já para o caso dos registros, será necessário declará-los e definir seus campos
(com os respectivos tipos).
Denominamos de índice a posição de uma informação em um vetor ou matriz. Então, caso você
queira armazenar ou recuperar uma informação em uma estrutura unidimensional ou
multidimensional, será necessário informar o(s) respectivo(s) índices para cada dimensão da
estrutura, analogamente a um endereço. Veja a seguir, um exemplo de declaração de um vetor
linear
1 inteiro vetorMatriculas [10];
2 caractere vetorNomes[] = {"Maria", "João", "José"};
O exemplo apresenta duas formas de declaração de um vetor linear. Na linha 1, um vetor linear de
10 posições, que irá armazenar informações do tipo inteiro, é declarado. Já na linha 2, você encontra
um vetor de caracteres que está, ao mesmo tempo, sendo declarado e inicializado, ou seja, tendo
seus valores iniciais definidos. Ainda nesta linha 2, perceba que não é definida a quantidade de
posições que o vetor irá armazenar dentro dos colchetes. Isso acontece devido à quantidade de
posições que deverão ser armazenadas estar sendo definida pela quantidade de informações
passadas na sua inicialização, ou seja, três posições.
Após a declaração de um vetor, a sua utilização se dará por meio do acesso à posição que se deseja
armazenar ou ler. Veja a seguir operações básicas de leitura e atribuição em vetores.
1 inteiro vetorMatriculas [10];
2 caractere vetorNomes[] = {"Maria", "João", "José"};
3
4 vetorMatriculas[1] = 123;
5 vetorMatriculas[2] = 456;
6
7 escreva(vetorMatriculas[1]);
As linhas 4 e 5 apresentam como uma informação pode ser armazenada em uma posição de um
vetor. É preciso definir qual a posição válida do vetor que irá receber a informação, ou seja, qual o
índice do vetor que receberá a informação, sendo que esta precisa ser do mesmo tipo definido para o
vetor. A linha 7, por sua vez, apresenta como a informação previamente armazenada poderá ser lida
(recuperada) e apresentada ao usuário. Note que apenas o índice 1 do vetor (posição 1) está sendo
acessado e terá sua informação escrita na tela, enquanto as demais posições do vetor não terão suas
respectivas informações exibidas ao usuário. Veja a seguir, um exemplo de utilização de um laço de
repetição para preenchimento de um vetor.
1 inteiro vetorMatriculas[10];
2 caractere vetorNomes[] = {"Maria", "João", "José"};
3 inteiro contador ;
4
5 para (inteiro = 1) até (inteiro = 10) faça
6 leia(vetorMatriculas[inteiro]);
7 fim - para;
O exemplo apresenta uma combinação de um laço de repetição para – até – faça com vetores. A
linha 5 define um laço de repetição de uma variável do tipo inteiro que irá iterar pedindo que o
usuário informe valores (por meio da operação de leitura da linha 6), que serão atribuídos a cada
respectiva posição do vetor. Desta mesma forma, é possível realizar operações de escrita
percorrendo cada posição de um vetor. Veja o exemplo de declaração de uma matriz.
1 inteiro matrizPredio [5][3];
2
3 matrizPredio[1][1] = 101;
4 matrizPredio[1][2] = 102;
5 matrizPredio[1][3] = 103;
6 matrizPredio[2][1] = 201;
7 matrizPredio[2][2] = 202;
8 matrizPredio[2][3] = 203;
A linha 1 apresenta a declaração de uma matriz, que deve conter o tipo do dado que será
armazenado, o nome da variável e as dimensões, com suas respectivas quantidades de posições.
Então, teremos cinco linhas e três colunas para a variável matrizPredio. As linhas 3 a 8 apresentam
como as posições da matriz poderão ser acessadas, sendo necessário informar um valor para todas
as dimensões definidas, ou seja, indicar os índices que serão acessados para cada dimensão. Veja a
seguir o exemplo de leitura e preenchimento de uma matriz com laço de repetição para – até –
faça.
1 inteiro matrizPredio [5][3];
2 inteiro contadorColunas;
3 inteiro contadorLinhas;
4
5 //Bloco para preenchimento da matriz
6 para (contadorLinhas = 1) até (contadorLinhas = 5) faça
7 para (contadorColunas = 1) até (contadorColunas =
3) faça
8 leia(matrizPredio[contadorLinhas]
[contadorColunas]);
9 fim - para;
10 fim - para;
11
12 //Bloco para escrita da matriz
13 para (contadorLinhas = 1) até (contadorLinhas = 5) faça
14 para (contadorColunas = 1) até (contadorColunas =
3) faça
15 escreva(matrizPredio[contadorLinhas]
[contadorColunas]);
16 fim - para;
17 fim - para;
O exemplo apresenta um exemplo de como deve ser feito o preenchimento e a leitura de uma
matriz. O bloco para – até – faça, definido na linha 6, deverá percorrer as linhas, sendo o mais
externo, enquanto o bloco para – até – faça definido na linha 7, irá percorrer as colunas,
executando até o final de sua quantidade de iterações. Desta forma, para cada linha (laço da linha
6), o laço da linha 7 irá executar três vezes consecutivas.
Veja agora um exemplo de definição e utilização de um registro.
1 tipo proprietario = registro
2 | inteiro : cpf,
dataNascimento;
3 | caractere : nomeCompleto,
telefone;
4
5 leia (proprietario.cpf);
6 leia (proprietario.dataNascimento);
7 leia (proprietario.nomeCompleto);
8 leia (proprietario.telefone);
9
10 proprietario matrizPredioProprietario [5][3];
11
12 matrizPredioProprietario [1][1] = proprietario;
No exemplo, em sua linha 1, define o tipo de dados registro, que terá os campos CPF e
dataNascimento como do tipo inteiro, enquanto os campos nomeCompleto e telefone como do tipo
caractere. Para acessar cada campo, você deverá seguir os exemplos apresentados nas linhas 5 a 8.
A linha 10 define uma matriz, do tipo do registro proprietário definido, que irá armazenar, para
cada posição, um registro com todas as informações do proprietário daquela unidade.
VÍDEO RESUMO
Olá, estudante! Neste vídeo, você aprenderá as estruturas de armazenamento de dados homogêneas,
como os vetores unidimensionais e as matrizes, além da estrutura de armazenamento de dados
heterogênea (os registros). Irá aprender em quais situações deverá utilizar cada tipo de estrutura e
verá exemplos práticos de como aplicar estes conceitos ao elaborar seus algoritmos.
Saiba mais
A manipulação de caracteres e inteiros pode ocasionar dificuldades na
legibilidade do código, principalmente pelas conversões implícitas que a
linguagem C permite na execução dos programas. Para essas construções
específicas, Luís Damas organizou uma subseção em sua obra, com alguns
exemplos detalhadamente descritos.
O livro Linguagem C está na nossa biblioteca virtual, e o capítulo que aborda
esse assunto está na subseção Situações em que inteiros e caracteres não se
devem misturar, na página 43.
REFERÊNCIAS
Aula 1
FORBELLONE, A. L. V.; EBERSPÄCHER, H. F. Lógica de programação –
A construção de algoritmos e estrutura de dados. São Paulo: Makron Books,
1993.
PRESSMAN, R. S. Engenharia de software. São Paulo: Makron Books,
1995.
Aula 2
FORBELLONE, A. L. V.; EBERSPÄCHER, H. F. Lógica de programação –
A construção de algoritmos e estrutura de dados. São Paulo: Makron Books,
1993.
Aula 3
FORBELLONE, A. L. V.; EBERSPÄCHER, H. F. Lógica de programação –
A construção de algoritmos e estrutura de dados. São Paulo: Makron Books,
1993.
https://integrada.minhabiblioteca.com.br/reader/books/9788521632474
Aula 4
FORBELLONE, A. Luiz Villar; EBERSPÄCHER, Henri Frederico. Lógica de
Programação – A construção de algoritmos e estrutura de dados. São
Paulo:Makron Books, 1993.
UNIDADE 3
CONCEITOS DE PROGRAMAÇÃO
Aula 1 - Introdução a conceitos de programação
Aula 2 - Introdução à linguagem C
Aula 3 - Estruturas condicionais em linguagem C
Aula 4 - Operadores na linguagem C
Referências
Aula 1
INTRODUÇÃO A CONCEITOS DE PROGRAMAÇÃO
Chegamos à unidade em que estudaremos os conceitos de lógica de programação
aplicados a uma linguagem específica de programação: a linguagem C!
INTRODUÇÃO
Olá, estudante! Chegamos à unidade em que estudaremos os conceitos de
lógica de programação aplicados a uma linguagem específica de programação:
a linguagem C! Essa linguagem é o meio pelo qual os comandos que
indicarmos serão realizados pelo computador para produzir a saída esperada
para o programa. Você já aprendeu que a assertividade de um programa
depende de sua construção, isto é, da escolha correta dos passos que o
compõem, e de forma que os comandos sejam executados em uma sequência
lógica. Nesta unidade, estudaremos como a linguagem de programação e um
ambiente de desenvolvimento nos fornecem as estruturas necessárias para
realizarmos o processamento lógico das informações. Te convido para vivenciar
essa realidade que é a base de qualquer sistema ou produto digital, vamos lá?
CONCEITOS BÁSICOS DE LINGUAGEM DE PROGRAMAÇÃO
Todos os sistemas que utilizamos no nosso dia a dia foram desenvolvidos em
alguma linguagem de programação! Do mais avançado software de engenharia
ao jogo mais popular dos smartphones, todos eles são uma construção de
comandos de programação organizados de forma lógica. As linguagens de
programação foram evoluindo com o tempo, e para cada propósito de aplicação
escolhemos a mais adequada.
Uma analogia pode ser feita com a língua nativa, a língua estrangeira, ou ainda
uma linguagem mais formal ou mais descolada, que deriva de uma língua.
Ah, aqui também cabe uma observação interessante, um programa construído
com uma linguagem de programação tem o mesmo significado no mundo todo;
outra informação importante é que praticamente todas as linguagens de
programação têm seus comandos escritos em inglês.
Nossa disciplina adota a linguagem C, uma linguagem amplamente utilizada e
que é base para diversas outras linguagens comerciais atualmente, e por meio
dos exemplos práticos você verá como ela realiza as operações necessárias no
campo da programação. Em relação à linguagem adotada na nossa disciplina,saiba que a linguagem C é umas das mais populares, e por suas características
de acesso e manipulação de recursos computacionais como a memória, é muito
utilizada em áreas da engenharia, computação e especialmente na eletrônica,
além de também ser utilizada para construir bibliotecas nativas de outras
linguagens de programação.
Como toda linguagem, a linguagem C possui uma quantidade finita de palavras
e símbolos, eles são chamados de tokens, isso quer dizer que para criarmos um
código-fonte devemos escolher tokens que existam na linguagem. Cada token
da linguagem tem um significado no contexto da programação, que inclusive
pode mudar conforme a ordem em que são organizados. Estes tokens podem
ser um comando na linguagem, um operador (relacional, condição ou lógico) ou
ainda uma palavra reservada para caracterizar algum identificador.
Agora que você já conhece as características de linguagens de programação
pode estar se perguntando como seus tokens são compreendidos pelo
computador, certo? Aqui surge a necessidade de abordarmos o Compilador e o
Interpretador, que são os sistemas computacionais capazes de receber um
código escrito em uma linguagem de programação e tornar esse código um
programa executável.
Os programadores escrevem códigos-fonte com comandos da linguagem de
programação, e o compilador é o responsável por criar um código de significado
equivalente ao código do programador, de forma que o computador processe
esse código e execute os comandos adotados.
Aqui cabe destacar que problemas de lógica não são identificados pelo
compilador, ou seja, um programa que foi construído com os elementos corretos
e respeitando as regras da linguagem pode, ainda assim, apresentar erros de
lógica e possíveis erros de execução dependendo das entradas a que foi
submetido.
Tanto para elaborar quanto para editar o código-fonte é necessário um software,
assim como o compilador e o interpretador também são um software
executável. É possível que um mesmo sistema integre o software de editor e o
compilador, a ele damos o nome de Ambiente Integrado de Desenvolvimento,
também conhecido pela sigla IDE, do inglês Integrated Development
Environment. Uma descrição dessa composição é apresentada pela Figura 1.
Figura 1 | Composição de uma IDE
Fonte: elaborada pela autora.
Até aqui você foi apresentado:
• À linguagem C.
• Ao compilador necessário para transformar o código escrito em C em um
programa executável pelo computador.
• E à IDE, uma ferramenta de software que serve como um ambiente de
trabalho.
COMPILADORES E INTERPRETADORES
Para aprofundar mais nossos conhecimentos sobre as linguagens vamos
conhecer mais algumas de suas características:
• Podem ser de mais alto nível: como Python, java e php.
• Podem ser de mais baixo nível: como C e Assembly.
• E ainda existem linguagens que derivam de outras linguagens: como C# e C+
+.
Dizemos que uma linguagem é de alto nível quando o usuário se distancia dos
aspectos estruturais do código, utilizando um alto nível de abstração para
executar comandos. Em uma comparação, é como se estivéssemos localizando
um país no globo terrestre, obtendo sua localização, limites e fronteiras, porém
sem maiores detalhes.
Já uma linguagem de baixo nível é aquela em que o usuário tem total controle e
conhecimento das estruturas e dados que estão sendo manipulados, o que
também faz com que mais detalhes precisem ser adicionados para a construção
do programa. Utilizando a mesma comparação anterior, é como se
estivéssemos nos localizando em uma cidade com o GPS, observando as ruas
e características das quadras.
Assim como na comunicação que conhecemos na sociedade, em que
utilizamos as palavras disponíveis na linguagem, e respeitamos as regras de
construção das frases, no contexto de programação também há regras a serem
respeitadas em todas as linguagens, independentemente do nível em que
esteja inserida.
Algumas linguagens como PHP e JavaScript normalmente não necessitam de
compilador, e sim de interpretador, enquanto a linguagem Java costuma
depender tanto de compilador quanto de interpretador e a linguagem C,
utilizada na nossa disciplina, utiliza compilador (MANZANO, 2015), e mais
adiante vamos detalhar seu funcionamento prático.
Primeiramente, vamos entender o contexto e a necessidade de utilizar um
compilador: o computador trabalha com estruturas e objetos binários, ou seja,
independentemente se o computador está manipulando um texto, um número,
uma imagem ou as instruções de um programa, na prática ele está processando
0s e 1s. Porém, você deve concordar que seria humanamente inviável para os
programadores escreverem programas e instruções somente com a
representação de 0s e 1s.
Podemos então definir o compilador como um tradutor de linguagens, em que a
linguagem de saída é sempre de um nível mais baixo que o nível de entrada. O
programa de saída costuma ser construído em binário, linguagem simbólica ou
linguagem de máquina, sempre constituído somente por cadeias de 0s e 1s.
Em alguns casos, o erro apontado pelo compilador não o impede de gerar o
programa em binário, porém, em alguns casos, o compilador não consegue
gerar o programador executável, sendo preciso localizar o erro e corrigi-lo, para
depois tentar compilar novamente. Essa é uma atuação importante do
compilador, pois evita que um programa com uma construção falha seja
executado, pelo contrário, o compilador muitas vezes aponta para o
programador qual foi o erro encontrado.
Cada IDE tem uma forma visual de representar esses possíveis erros, algumas
delas até mostram os erros na construção do programa enquanto o
programador digita, ou seja, ainda antes da análise do compilador.
• Essas e outras funcionalidades fazem com que as IDEs sejam vistas como
ferramentas que melhoram a produtividade dos programadores. As IDEs
evoluíram muito com o tempo, há uma grande variedade disponível para
linguagens populares como o C, e algumas delas são: Visual Studio,
CodeBlocks, DevC, Eclipse, NetBeans.
E para outras linguagens também podem ser usadas as IDEs citadas acima ou
ainda outras tantas existentes no mercado.
AMBIENTE DE PROGRAMAÇÃO
Estudante, chegamos ao momento em que aplicamos os conceitos aprendidos!
Assim como na nossa língua, para o perfeito entendimento do código
realizamos a análise léxica e a sintática, sendo a primeira sobre a grafia correta
ou existência de cada token presente no código-fonte, e a segunda sobre a
forma e a ordem em que os tokens foram inseridos no código-fonte, se há uma
concordância entre si.
Ou seja, na prática, a atividade do compilador é similar à de um tradutor que
realiza a dublagem ou a legenda de um filme, quando a frase ou a palavra que
está sendo traduzida se apresenta de maneira errônea, dúbia ou que não
permita o entendimento, esse profissional busca entender o contexto, realiza
uma sugestão de adequação ou mesmo para a execução para elucidar a
dúvida. No caso do compilador é muito parecido, pois quando o programador
cria um código que apresenta erros ou falhas em sua construção, o compilador
precisa reconhecer e apontar essa divergência, para que o programador
proceda com a correção.
Quando o código não apresenta erros, o compilador então cria um código de
máquina “semanticamente equivalente”, ao código criado pelo programador na
linguagem de programação. Neste aspecto novamente aparece a figura do
ambiente de programação como um aliado do programador! Pois algumas IDEs
identificam em tela a estrutura física do código, a posição dos pares de
parênteses, chaves e colchetes, podendo realizar o autopreenchimento do
nome de variáveis e ainda outras facilidades como sugestão de melhoria e,
consequentemente, menos erros no código. Um destaque de diferentes cores
está apresentado na Figura 2.
Figura 2 | Tela de um código sendo editado em uma IDE
Fonte: captura de tela de Code: Blocks elaborada pela autora.
Assim como existem variações entre ferramentas, existem IDEs mais amigáveis, mais
robustas,mais profissionais, mais leves e com mais ou menos recursos ao
programadores, sendo que algumas são gratuitas e outras são pagas. A escolha da IDE
também dependerá da linguagem de programação adotada e do compilador selecionado.
Os programadores podem (e devem!) configurar e customizar a IDE que escolheram para
trabalhar, pois além de realizar as atividades básicas de programação, ela acaba
oferecendo outros recursos desejáveis para o programador. A grande maioria das IDEs
oferecem identificador de erros por meio de uma análise léxica no próprio editor e no
instante em que o programador digita, sem a necessidade de compilar o código.
Esses e outros recursos são essenciais no dia a dia do programador para que ele ganhe
em produtividade, principalmente quando o tamanho dos projetos cresce
consideravelmente.
Neste contexto, inicialmente a IDE parece ser muito complexa para programas simples,
mas como ela é uma ferramenta profissional, foi desenvolvida para organizar pacotes de
software que precisam ter a referência de bibliotecas, classes, scripts e outros códigos.
Importante destacar que a IDE é uma ferramenta, e embora seja certeza que você
precisará de uma IDE para construir e compilar seus códigos, você deve se concentrar
em aprender a programar em uma linguagem pelo menos, e então se adaptar à IDE será
uma consequência! Nesta unidade serão apresentados os códigos-fonte para que você
acompanhe a disciplina, entenda a composição do código e a construção de cada
comando, para que, assim, você possa desenvolver seus próprios códigos.
Essa disciplina requer a leitura do material e a resolução de exercícios do material, e é
indicado que você programe “mão na massa” para também desenvolver seu raciocínio
lógico e sua capacidade de resolver problemas computacionais.
VÍDEO RESUMO
Olá, estudante! Conhecemos os conceitos de linguagem de programação, compiladores e
ambientes de desenvolvimento, e como eles se relacionam. Agora vamos aprofundar mais
na parte prática quanto à interface de desenvolvimento.
Neste vídeo, você conhecerá o funcionamento da IDE CodeBlocks, e alguns dos
principais passos para conferir se a instalação está 100%! Vamos lá?
Saiba mais
O que fazer quando se faz necessário utilizar um outro computador para as tarefas da
disciplina? Bem, deixar de realizá-las não é uma opção!! Então eu trouxe para você uma
opção de editor e compilador online, o Jdoodle!
Aproveite para salvar o link como uma opção a mais de estudo e ferramenta para praticar
os exercícios da disciplina caso você não esteja com outro Ambiente Integrado de
Desenvolvimento local devidamente instalado.
Aula 2
INTRODUÇÃO À LINGUAGEM C
Nesta aula você entenderá como manipular dados em C e realizar operações com eles,
sempre respeitando os comandos da linguagem.
INTRODUÇÃO
Olá, estudante! Agora que você já conhece a linguagem de programação da
nossa disciplina e já sabe a necessidade de adotar um ambiente de
desenvolvimento, nesta aula, vamos conhecer com detalhes cada estrutura do
programa em linguagem C. Assim como uma receita seus ingredientes com
unidades e ordens pré-definidas, os algoritmos também têm campos para
declaração do que será necessário para aquele código-fonte, isso consiste em
um padrão no qual o programa deve ser construído para que gere um código de
máquina válido ao ser interpretado pelo compilador. Nesta aula você entenderá
como manipular dados em C e realizar operações com eles, sempre
respeitando os comandos da linguagem. Não deixe de realizar os exercícios
propostos, eles são essenciais para seu aprendizado! Vamos juntos conhecer
esses comandos?
CONSTRUINDO UM PROGRAMA EM C
Vamos começar identificando quais as estruturas básicas de um programa em
linguagem C, começando com um exemplo na Figura 1. A linha 1 é o cabeçalho
do programa, e entre as linhas 2 e 4 está o Programa principal, identificado
como main.
Figura 1 | Estrutura do Programa em Linguagem C
Fonte: elaborada pela autora.
Nas primeiras linhas ficam localizados os comandos de pré-processamento, ou
pré-compilação, sempre iniciando com o sinal # (hashtag), esses comandos
servem para inclusão de bibliotecas e definições e formam o cabeçalho do
programa. Dependendo do tipo de estrutura a ser manipulada são adicionadas
as bibliotecas necessárias, no exemplo da Figura 1 foi necessário adicionar
somente uma biblioteca, a stdio.h, uma biblioteca que manipula funções de
entrada e saída, e adicionando-a o programador pode simplesmente chamar o
comando scanf e printf dentro do programa principal, sem a necessidade de
conhecer os detalhes internos de operação destes comandos no sistema
operacional.
Em seguida fica localizado o programa principal, sempre identificado
por main(), e tendo delimitando os comandos de seu trecho com os
tokens { e }, que na Figura 1 estão entre as linhas 3 e 6. Observe que, ao ser
https://www.jdoodle.com/c-online-compiler/
executado, este programa sempre executa o comando printf(), que é um
comando de saída para mostrar informações na tela, e a informação é sempre a
mesma frase que está entre as aspas: “Meu primeiro programa!!”.
Ele não recebe nenhuma entrada ou interação que dependa do usuário, mas as
aplicações se tornam muito mais diversas quando permitimos que o usuário
interaja com o programa! Essa interação é feita por meio de comandos de
entrada, e o mais comum na linguagem C é o scanf(), que permite ler números
ou letras do teclado.
Quando o programa lê uma informação, ele precisa armazená-la em algum local
apropriado da memória, e depois recuperá-la. Isso é possível se o programador
previamente reservar uma região da memória e dar a ela um nome
(identificador) para que possa ser acessada sempre que necessário. Então, no
código, sempre que for preciso utilizar essa informação, chamamos o
identificador dela.
Imagine se na necessidade de alterar a informação a gente precisasse reservar
uma outra região de memória, e tentar usar o mesmo identificador? Seria um
desperdício de espaço e uma confusão, não é mesmo?
É por isso que esse espaço reservado recebe o nome de variável, pois
sempre que for necessário substituir seu conteúdo nós informamos o nome do
identificador e o novo valor. Utilizando um raciocínio semelhante, chegamos à
definição de constante, uma região de memória reservada, com um nome
identificador, porém que não pode ter seu conteúdo alterado ao longo do
programa.
Assim, as informações manipuladas pelo computador que estão em uma região
específica de memória ou são uma variável ou uma constante. Ambas as
configurações constituem o que chamamos de dados. Os dados têm um
determinado tipo e tamanho, inclusive isso influencia no espaço ocupado na
memória.
Todas as ações que realizamos com os dados são por meio dos operadores, e
na linguagem C os operadores podem ser:
• Aritméticos: para cálculos matemáticos, e estão apresentados na Figura 2.
• Relacionais: para comparar se dois valores são iguais, diferentes ou se um
é maior que o outro.
• Lógicos: para combinar um ou mais operadores relacionais em uma lógica
de multifatores de entrada.
Figura 2 | Operadores aritméticos
Operador Operação Tipo Resultado
+ Manutenção de sinal Unário -
- Inversão de sinal Unário -
Operador Operação Tipo Resultado
% Resto de divisão (módulo) Binário Inteiro
/ Divisão Binário Inteiro ou Real
* Multiplicação Binário Inteiro ou Real
+ Adição Binário Inteiro ou Real
- Subtração Binário Inteiro ou Real
= Atribuição Binário Inteiro, Real ou Lógico
Fonte: adaptado de Manzano (2015), p. 44.
Isso quer dizer que tudo que o programa precisar processar será construído
com base nos 3 tipos de operadores disponíveis na linguagem e respeitando as
limitações quanto ao tipo de dados e as construções dos comandos.
PROGRAMAS PARA MANIPULAR DADOS
Agora que você já conhece os recursos que tornam o programa mais completo,
vamos analisar um exemplo que utiliza umavariável e um comando de leitura e
escrita para calcular e mostrar o dobro de um valor:
1.#include<stdio.h>
2.int x;
3.int y;
4.int main() {
5. scanf("%i", &x);
6. y = 2 * x;
7. printf("valor de y: %i", y);
8 }
Neste programa, se a entrada for 3, a saída é 6, já se for 4, a saída é 8, e assim
por diante, e percebemos isso ao analisar a linha de código (y = 2 * x), que
contém os operadores aritméticos como conhecemos.
Nas linhas 2 e 3 declaramos duas variáveis do tipo inteiro e sabemos que é do
tipo inteiro pelo uso da palavra reservada int. Se precisássemos de outro tipo
de variável, iríamos usar outra palavra reservada para declará-la. E x e y foram
os nomes dados às variáveis, ou seja, seu identificador.
Podemos (e devemos!) utilizar identificadores que contextualizem melhor seu
papel no programa, como demonstrado no código a seguir:
1;#include<stdio.h>
2.int valor;
3.int dobro;
4.int main() {
5. scanf(\"%i\", &valor);
6. dobro = 2 * valor;
7. printf(\"O dobro é: %i\", dobro);
8. }
Embora essa mudança melhore consideravelmente o entendimento e a
legibilidade do programa, como regra, nem todas as combinações de letras e
números são válidas como identificadores de variáveis e constantes
(MANZANO, 2015):
• Máximo de 32 caracteres de letras e números, sem espaço.
• Iniciar com uma letra ou “_” (underline), nunca com um número.
• Não pode ser uma palavra reservada da linguagem C, ou seja, uma palavra
que já tem uma funcionalidade atribuída na linguagem.
• Não pode utilizar outro caractere especial, o único permitido é “_”.
Já que mencionamos as regras dos identificadores, vamos conhecer outros
tipos de dados presentes na linguagem C, alguns deles estão descritos na
Tabela 1.
Tabela 1 | Tipos de dados na linguagem C
Tipo de
dado
Tamanho
em
memória
Menor valor
representado
Maior valor
representado
Usado para
Exemplo de
aplicação
int 16 bits - 32.768 32.767
Inteiros em
geral
Contagem de
números inteiros
unsigned
short int
16 bits 0 65.535
Inteiros em
geral
Contagem de
números naturais
(não negativos)
long int 32 bits - 2.147.483.648 2.147.483.647
Inteiros
grandes
Grandes
quantidades de
inteiros
float 32 bits - 3.4028235e38 3.4028235e38
Ponto flutuante
(notação
exponencial)
Valores com
precisão de 10-38 a
1038
char 8 bits - - Símbolos
Caracteres
especiais, letras ou
números
Fonte: adaptada de Manzano (2015).]
O comando scanf() da linha 5 tem duas regras de construção importantes:
• “%i” significa que irá ler um número do tipo inteiro, para outros tipos é
necessário usar outra construção.
• &valor significa que irá armazenar o valor lido na variável valor.
Já o comando printf() da linha 7 tem as seguintes regras:
• O conteúdo das aspas será mostrado na íntegra, exceto quando houver o
símbolo %, que representa um código de escape.
• Para mostrar o conteúdo de uma variável do tipo inteiro utilizamos %i e %d,
para outros tipos é necessário usar outra construção.
• Após o fechamento das aspas, deve vir uma vírgula e o nome da variável de
interesse;
• Se for necessário mostrar mais uma variável, adiciona-se mais uma vírgula e
a outra variável.
CONSTRUINDO PROGRAMAS MAIS ROBUSTOS
Nós já estudamos que um programa válido é aquele que respeita as regras da
linguagem no quesito léxico e semântico, e que irá gerar um código de máquina
que realize o processamento lógico desejado. Isso nos leva a 2 pontos
importantes:
1. Assim como em toda operação matemática, o resultado obtido não
necessariamente depende de como os operadores aparecem na linha do
comando, e sim de acordo com a regra de precedência de operadores, que é a
ordem em que são executados.
Essa ordem está apresentada na Figura 5.
Figura 5 | Ordem das operações matemáticas
Fonte: elaborada pela autora.
2. As construções dos comandos dependem do tipo de dado que será
manipulado, então, para utilizar os comandos scanf() e printf() em dados do tipo
não inteiros, utilizamos após o sinal % as seguintes construções sintáticas:
- %c para o tipo char;
- %lf para o tipo double;
- %f para o tipo float, com a opção de determinar a quantidade de casas antes
e após a vírgula, como descrito no código a seguir:
1.#include<stdio.h>
2.float pi;
3.int main() {
4. pi = 3.14159265359;
5. printf(\"PI: %5.2f\", pi);
6. }
Agora vamos conhecer os operadores relacionais da linguagem C, em
que dois termos são comparados por meio do operador, sendo que os termos
podem ser variáveis, constantes ou números fixados no código. Os operadores
relacionais estão apresentados na Tabela 2, com seu respectivo significado de
teste.
Tabela 2 | Operadores relacionais na linguagem C
Operador Relação testada
< Primeiro operando menor que o segundo operando
> Primeiro operando maior que o segundo operando
<= Primeiro operando menor ou igual ao segundo operando
>= Primeiro operando maior ou igual ao segundo operando
== Primeiro operando igual ao segundo operando
!= Primeiro operando diferente do segundo operando
Fonte: adaptada de Microsoft (2022).
A saída de uma relação testada pode ser falsa ou verdadeira, na linguagem C
usa-se o valor “0” (zero) como indicativo falso deste teste, e 1 ou qualquer outro
valor diferente de zero é considerado verdadeiro. Duas comparações estão
sendo apresentadas no código a seguir, sendo a primeira comparando se doze
é igual a zero, com resultado falso (como esperado, mostrando 0 na tela!), e a
segunda em que comparamos se a variável chamada número é menor que o
número 12, e como seu conteúdo é 10, o resultado é verdadeiro, mostrando 1
na tela.
1.#include <stdio.h>
2.#include <stdlib.h>
3.int numero;
4.int resultado1, resultado2;
5.int main()
6.{
7. numero = 10;
8. resultado1 = (12 == 0);
9. printf(\"Resultado 1: %i \n\", resultado1);
10. resultado2 = (numero < 12);
11. printf(\"Resultado 2: %i \n\", resultado2);
12. return 0;
13.}
Esses operadores relacionais que produzem como saída “falso” ou “verdadeiro”
ficam ainda mais interessantes quando usados de forma combinada, por meio
dos operadores lógicos! Assim como na matemática esses operadores
relacionam 2 condições em sua tabela verdade, e tanto sua entrada como sua
saída são valores lógicos, ou seja, verdadeiro ou falso.
Os operadores lógicos estão apresentados na Tabela 3, com seu respectivo
significado na lógica booleana.
Tabela 3 | Operadores lógicos na linguagem C
Token na linguagem
C
Operador matemático Significado
&& And (E) Conjunção
! Not (NÃO) Negação
|| Or (OU) Disjunção inclusiva
^ Xor (XOR) Disjunção exclusiva
Fonte: elaborada pelo autor.
Com esses recursos, nós conseguimos construir programas para diversas
aplicações matemáticas!
VÍDEO RESUMO
Estudante, nesta aula, conhecemos como manipular dados em linguagem C,
por meio de variáveis e constantes, também estudamos como funcionam os
comandos de entrada e saída de dados e sua importância para tornar o
programa mais dinâmico. Estudamos também os operadores aritméticos,
relacionais e lógicos, que são estruturas essenciais para construirmos
programas mais profissionais. Venha comigo no próximo vídeo para
executarmos um programa que abrange todos estes conteúdos!
Saiba mais
Para melhor entendimento dos operadores lógicos é importante que você
conheça a tabela verdade dos operadores, um conceito matemático e de muita
aplicação na computação.
Você pode desenvolver a tabela verdade conforme a necessidade do programa
em desenvolvimento, e se precisar validar ou tirar a prova real de algum
operador você pode acessá-la online!
Acesse a Calculadora Online (Tabela-Verdade) para treinar seus
conhecimentos em lógica booleana.
Aula 3
ESTRUTURAS CONDICIONAIS EM LINGUAGEM C
Você deverá observar os sistemas que utiliza, como o gerenciador de e-mails, o
editor de texto e o aplicativo do banco.
INTRODUÇÃO
Olá, estudante! Nesta aula, você deverá observar os sistemas que utiliza, como
o gerenciador de e-mails, o editor de texto e o aplicativo do banco. Esses
sistemas interagem com você e respondemde acordo com as suas ações, por
meio de condições que foram previamente implementadas. Isso só é possível
porque, a cada opção que você pode acionar no sistema, há uma programação
que determina qual caminho o programa deve seguir ou o que ele deve fazer.
Neste contexto, você está convidado a conhecer como construímos essas
opções e os possíveis caminhos do programa. Vamos nessa? Lembre-se de
reforçar os conceitos estudados com os exercícios da aula!
PROGRAMAS COM OPÇÕES
A linguagem C é executada linha a linha, assim como você acompanha este
material – e, se necessário, desvia a sua leitura para uma linha diferente, ou
para outra área específica do programa. Na linguagem de programação, os
possíveis caminhos que um programa pode tomar são organizados nas
estruturas condicionais, mais precisamente nos desvios condicionais.
À primeira vista, o código tem seu mesmo aspecto textual e em sequência
tradicional, mas ele pode, a cada comando, ter seu curso alterado de acordo
com a interação do usuário. Quando pensamos em programas que interagem
de acordo com nossas entradas, estamos lidando com o contexto dessas
estruturas condicionais, e como o próprio nome diz, a forma de sua execução
depende de uma condicional.
Na prática, essas estruturas organizam o código de forma que as entradas
fornecidas pelo usuário sirvam como decisores lógicos quanto aos próximos
passos de execução do programa.
A lógica das estruturas condicionais é muito parecida com o nosso raciocínio ao
resolver desafios do dia a dia. Por exemplo: se abrimos um e-mail para lê-lo, o
https://www.calculadoraonline.com.br/tabela-verdade%20
gerenciador remove a notificação de nova mensagem, assim como ele exibirá
uma mensagem de erro se for identificado que estamos sem internet. O
comando para essa lógica é o if(), pois if, em inglês, significa “se”.
Esse conjunto de verificação e reação é chamado de estrutura condicional e é
composto por uma verificação acerca de uma condição e uma reação a ser
executada se essa condição for satisfeita. Tal condição pode ser a relação de
um ou mais eventos, e a reação pode ser a execução de um conjunto de
comandos ou de um único comando.
Inclusive, a reação a ser executada pode ser outra estrutura condicional,
consistindo em uma estrutura dentro de outra, chamada de estrutura
condicional encadeada. Por serem muito versáteis, essas estruturas permitem
inúmeras combinações.
Adicionalmente, pode haver um senão acompanhando a lógica do se. Por
exemplo: se a bateria estiver com a carga abaixo de 15%, mostre o ícone em
vermelho; senão, mostre o valor da carga. Na linguagem C, o comando
equivalente ao senão é o else, e veremos mais adiante os exemplos de sua
implementação.
Muitas vezes, são tantas as possibilidades do programa que uma estrutura
condicional poderia tornar confusa sua legibilidade. Nessas circunstâncias,
utilizamos a seleção de casos, a qual é muito útil quando o usuário tem diversas
opções, sendo por isso também chamada de estrutura de controle com múltipla
escolha. Na linguagem C, o comando para essa seleção é o switch.
Assim como as estruturas condicionais são a base para organizar desvios no
programa, elas também servem como estruturas de controle de repetição,
devido ao mesmo princípio. A linguagem C tem dois recursos diferentes para
essa finalidade: o for e o while, sendo que ambos também avaliam condições
para controlar as repetições.
CONHECENDO AS ESTRUTURAS CONDICIONAIS
Um ponto relevante para detalharmos as estruturas condicionais é a sua base
de verificação: uma lógica constituída por operadores lógicos e relacionais. Os
operadores relacionais sempre retornam verdadeiro ou falso, e os operadores
lógicos atuam combinando esses retornos de acordo com a tabela verdade de
cada operador.
Sendo assim, a condição será testada na execução do comando, e somente se
ela for verdadeira o programa acessará o trecho especial do código. Em uma
linguagem bem desprendida, podemos dizer que o programa “entrou” no if. A
demonstração da sintaxe e da construção do comando da estrutura condicional
simples if pode ser vista no código a seguir:
1.#include<stdio.h>
2.int main() {
3. float temperatura;
4. printf(\"Digite a temperatura da sua cidade no dia de hoje: \
n\");
5. scanf(\"%f\", &temperatura);
6. if (temperatura < 5)
7. {
8. printf(\"Teste verdadeiro \n\");
9. printf(\"Prepare o agasalho!! \n\");
10. }
11. printf(\"A temperatura digitada foi: %f\", temperatura);
12. }
Na instrução if, a condição testada fica entre parênteses. No exemplo, temos
um único teste sendo executado no programa, e quando ele é verdadeiro o
programa entra no bloco de código e mostra na tela as duas frases: “Teste
verdadeiro” e “Prepare o agasalho!!”. Quando a condição é falsa, o programa
sai da linha de verificação do comando if e vai para o final do código, que exibe
na tela: “A temperatura digitada foi:”, ou seja, a linha localizada imediatamente
após a estrutura condicional do if.
Já no código a seguir está apresentada uma estrutura condicional composta.
Neste caso, o programa tem somente duas opções de execução: o bloco
referente ao if, quando a condição testada é verdadeira, ou o bloco referente ao
else, quando a condição testada é falsa. Ou seja, ele mostrará “saldo negativo”
somente se o teste do comando if der verdadeiro, ou saltará, ignorando o bloco
do if, e entrará no bloco do else, mostrando “saldo positivo”. Após executar o
bloco do if ou do else, ele sempre irá para a linha que mostra “Fim do
programa”. Veja o código com instrução if e else a seguir:
1.#include<stdio.h>
2.int main() {
3. float saldo = 12.00;
4. if (saldo < 0)
5. printf(\"Saldo negativo \n\");
6. else
7. printf(\"Saldo positivo \n\");
8. printf(\"Fim do programa.\");
9.}
E se quisermos deixar o programa ainda mais elaborado, podemos utilizar a
estrutura condicional composta, a qual é apresentada no código a seguir.
Observe que o if que testa se o saldo é igual a zero só é acessado pelo
programa quando a condição do primeiro teste for falsa, ou seja, quando não é
um número negativo. Observe também que a segunda estrutura condicional,
dentro do primeiro else, representa um único comando, e embora tenha sido
escrita em quatro linhas, ela não precisa de delimitadores de chaves { } em sua
sintaxe. Veja o código com instrução if encadeada, a seguir:
1. #include<stdio.h>
2. int main() {
3. float saldo = -12.00;
4. if (saldo < 0)
5. printf(\"Saldo negativo \n\");
6. else
7. if (saldo == 0)
8. Printf(\"Saldo zerado \n\");
9. else
10. printf(\"Saldo positivo \n\");
11. printf(\"Fim do programa.\");
12.}
Observe nesse código com a instrução if encadeada que temos um ótimo
exemplo de como utilizar recursos de indentação, que consiste no
deslocamento padrão do início do código na linha para caracterizar em que
nível ele está. Embora a indentação auxilie na leitura humana do código,
quando se faz necessário utilizar muitas estruturas condicionais encadeadas é
recomendado empregar seleção de casos, como no código a seguir. Veja o
código com seleção de casos, a seguir:
1. #include<stdio.h>
2. int main() {
3. int opcaoDigitada;
4. printf(\"Digite um numero:\");
5. scanf(\"%d\", &opcaoDigitada);
6. switch (opcaoDigitada)
7. {
8. case 1: printf(\"Um\"); break;
9. case 2: printf(\"Dois\"); break;
10. case 3: printf(\"Tres\"); break;
11. case 4: printf(\"Quatro\"); break;
12. case 5: printf(\"Cinco\"); break;
13. case 6: printf(\"Seis\"); break;
14. default: printf(\"Invalido\"); break;
15. }
16. }
Observe que dentro de cada “case” há uma única instrução “printf;” entretanto,
também poderia haver um bloco de comandos, e ele seria delimitado por
chaves. É importante observar que qualquer outra tecla ou valor digitado e lido
no “scanf”, que não estivesse nas opções, cairia no caso da linha 14: Invalido.
Se este último código tivesse sido escrito somente com condicionais,
certamente o programa ficaria bem menos elegante. Antes que vocêpense que
isso pode ser bobagem, imagine realizar a manutenção em um código escrito
por outra pessoa (ou por você mesmo) há um tempo. A forma de elaborar o
código facilitará ou dificultará o trabalho e o entendimento no futuro.
PROGRAMAS COM LAÇOS
Muito do propósito dos sistemas computacionais é realizar tarefas e ações
repetitivas, e para isso a linguagem C tem comandos específicos. Em
português, chamamos essa circunstância de laço (loop, em inglês). Na prática,
o programa fica executando um comando ou um conjunto de comandos de
forma repetida, em looping, enquanto uma condição for verdadeira.
Na linguagem C, utilizamos o comando while() – o termo while significa
“enquanto”, em inglês –, e sua construção é muito similar à do comando if, mas
com algumas diferenças. A principal delas é que, quando a condição é
verdadeira, além de o programa entrar naquele trecho de código, ele
continuamente repete o ciclo de executar os comandos e checar
novamente essa condição, parando de executar os comandos desse
trecho quando a condição for falsa.
Um exemplo prático é o de verificar a autenticação de um usuário pela digitação
correta da senha. Se usássemos só o comando if, realizaríamos a verificação e
retornaríamos indicando se a senha estava correta ou não, porém ainda não
teríamos um mecanismo que repetisse essa verificação até que o usuário
digitasse a senha correta. O código-fonte a seguir resolve o problema da senha.
Veja o código com while, a seguir:
1. #include<stdio.h>
2. int main() {
3. int senhaDigitada;
4. int senhaCadastrada = 1923;
5. printf(\"Digite a sua senha: \n\");
6. scanf(\"%d\", &senhaDigitada);
7. while (senhaCadastrada != senhaDigitada)
8. {
9. printf(\"\nSenha incorreta, por favor digite a sua senha: \
n\");
10. scanf(\"%d\", &senhaDigitada);
11. }
12. printf(\"Fim do programa! \n\n\");
13.}
Observe o comando de leitura da senha: se quisermos deixar o programa mais
compacto, poderemos utilizar o comando do { } while. Neste tipo de
comando, a instrução (ou o conjunto de instruções) é executada e depois se
realiza a verificação da condição. O código a seguir apresenta essa construção.
Veja o código com do while, a seguir:
1. #include<stdio.h>
2. int main() {
3. int senhaDigitada;
4. int senhaCadastrada = 1923;
5. do
6. {
7. printf(\"\nPor favor digite a sua senha: \n\");
8. scanf(\"%d\", &senhaDigitada);
9. }
10. while (senhaCadastrada != senhaDigitada);
11. printf(\"Fim do programa! \n\n\");
12. }
Quando você estiver construindo seus programas, identificará quais são o
comando e a construção mais adequados para o problema a ser resolvido. Em
resumo (MANZANO, 2015):
• O comando while é chamado de laço pré-teste, pois realiza o teste lógico no
início do laço, verificando se é possível executar o trecho de instruções
subordinadas a ele.
• O comando do while é chamado de laço pós-teste. Ele sempre executa o
bloco subordinado ao laço pelo menos uma vez, e então realiza o teste lógico
para decidir se continua no looping ou se sai dele.
Tanto o comando while quanto o do while permitem que sejam criados laços
iterativos e interativos:
• Iterativo: que se repete.
• Interativo: que interage com o usuário.
Como a condição de parada é o teste lógico dar falso, ao construir os comandos
o programador precisa estabelecer o controle dessa parada, ou seja, quando o
programa deve sair do loop. Porém, há casos em que há a necessidade de
manter o programa em um loop infinito, como um código que monitora
constantemente um processo industrial ou uma cancela de pedágio, por
exemplo. Para casos assim, é comum encontrar a seguinte construção: while
(1), pois 1 é sempre verdadeiro e o programa ficará permanentemente neste
loop.
A linguagem C ainda oferece uma terceira opção para execuções sequenciais: o
comando for (para, em português). Podemos ler o comando da seguinte
maneira: “para i variando de 0 a 10, de um em um, faça tal ação”. Uma
característica dessa construção é que, normalmente, ela é utilizada para laços
com um número finito e conhecido de execuções, como processar dados de
uma lista ou um conjunto de números.
Um exemplo da utilização do comando for é apresentado no código a seguir.
1.#include<stdio.h>
2.int main() {
3. int i, resultado;
4. for (i = 0; i <= 10; i++)
5. {
6. resultado = i * 2;
7. printf(\"2 x %d = %d \n\", i, resultado);
8. }
9.}
VÍDEO RESUMO
Estudante, nesta aula conhecemos como utilizar condições para controlar os
desvios e as repetições dos nossos programas. Você viu como o uso dos
operadores lógicos e relacionais é a base para toda a construção das lógicas e
o controle da execução do programa. A partir de estruturas condicionais como if
e else, podemos criar desvios, e com os comandos while, do while e for
conseguimos estruturar repetições de trechos específicos do código, sujeitos à
parada por intervenção do usuário ou não, a depender da forma que são
construídos. Vamos agora estudar mais alguns aspectos de implementação do
nosso conteúdo?
Saiba mais
Como saber se seu programa está executando passo a passo de forma
correta? Ou então, quando ele apresenta uma resposta incorreta, como saber
em que momento o algoritmo se perdeu, para que possa ser estudada uma
estratégia de correção? Na nossa aula, que aborda os desvios e os laços,
vimos que é essencial poder “entrar” na execução do programa e acompanhar
passo a passo cada linha executada.
A melhor alternativa para isso é debugar seu código. A maioria dos ambientes
de desenvolvimento integrado (IDEs) possui esse recurso.
Como você sabe, cada IDE tem sua interface e seu posicionamento de botões.
Então, para conseguir acessar o recurso na sua versão instalada, você deve
realizar uma pesquisa no Google contendo o nome do IDE que você está
utilizando, além dos termos “debugar” e “watches”.
Na maioria dos IDEs instalados localmente, você deve posicionar o mouse em
linhas estratégicas, que contenham as operações de interesse, e dar um clique
duplo na linha ou clique com botão direito. O objetivo é inserir um ponto de
interrupção (ou breakpoint), simbolizado por um círculo colorido, naquela linha.
Ao executar o programa, ele parará em todos os pontos criados e mostrará os
conteúdos de memória e os últimos cálculos realizados.
Para excluir estes pontos, o processo é o mesmo.
Outra possibilidade é utilizar o IDE OnlineGBD, que também permite
o debug online. Neste caso, basta clicar uma vez ao lado esquerdo do número
da linha para adicionar o breakpoint, e realizar um click duplo para removê-lo.
Figura 1 | Tela do OnlineGBD com breakpoint na linha 17
Aula 4
OPERADORES NA LINGUAGEM C
Nesta aula, veremos como as operações de atribuição podem ser versáteis e nos fornecer mais
opções de implementação quando complementadas com os operadores aritméticos.
INTRODUÇÃO
Olá, estudante! Nesta aula, veremos como as operações de atribuição podem
ser versáteis e nos fornecer mais opções de implementação quando
complementadas com os operadores aritméticos. Você deve ter percebido que
quanto mais recursos uma linguagem possui, melhores ficam o entendimento e
a legibilidade do código-fonte, mais opções de comando o programador possui
à sua disposição e há mais o que aprender. Muitas vezes, uma sutil alteração
no sinal ou na escolha dos tipos e operadores pode produzir resultados
totalmente diferentes, e consequentemente impactar a execução do programa.
Venha conosco nesta aula para aprender as variações desses comandos e não
ter problemas em seu código-fonte!
https://www.onlinegdb.com/
https://www.onlinegdb.com/
ATRIBUIÇÕES E TIPOS DE DADOS NA EXECUÇÃO
Estudante, você tem visto na criação de programas com a linguagem C que é
necessário realizar uma série de predefinições já no início da construção do
código-fonte, como a definição dos tipos de variáveis. Ao longo do código, uma
escolha que também impactará em como será o funcionamento do programa é
a forma com que construímos os comandos para realizar operações
matemáticas, por meiodos operadores aritméticos, já que a linguagem permite
variações com o mesmo símbolo.
Isso quer dizer que, caso não conheçamos as particularidades da linguagem,
podemos correr o risco de escrever um programa que apresente uma execução
diferente daquela que esperávamos. Essas particularidades são decisões
internas que o compilador está programado para tomar e que nem sempre
estão explícitas no código ou no nosso pensamento lógico.
Vamos tomar como ponto de partida a atribuição simples e, então, seguiremos
estudando suas variações. O operador de atribuição, que tem seu símbolo
representado por um único sinal de igual (=), é utilizado para inserir no termo à
sua esquerda o resultado processado da operação à sua direita. Por exemplo:
“resultado = 2 * valor”.
Embora essa construção seja a mais simples que existe quando se trata de
atribuição, pode ocorrer de o programador definir as variáveis “resultado” e
“valor” em tipos diferentes, e o compilador precisar decidir sobre como
processar o resultado, se apresenta um erro, se aceita a construção ou se
realiza uma conversão durante essa atribuição. A conversão em tempo de
execução junto com a atribuição é chamada de conversão de tipos em
atribuições, e estudaremos suas variedades ao longo desta aula.
Além desse tipo básico de atribuição, a linguagem C também permite outros,
como as atribuições múltiplas, em que é possível atribuir o mesmo valor para
múltiplas variáveis em um mesmo comando, como mostrado no código a seguir:
1.#include <stdio.h>
2.int main()
3.{
4. int x, y, z;
5. x = y = z = 0;
6.}
Devido a outro recurso interessante e bastante utilizado nos programas
profissionais, as operações de atribuição também podem conter elementos
aritméticos na sua construção, os quais são chamados de operadores
aritméticos, como o incremento e o decremento, ambos apresentados no código
a seguir:
1.#include <stdio.h>
2.int main()
3.{
4. int x, y;
5. x = y = 10;
6. x++; // o resultado dessa linha é x = 11
7. y--; // o resultado dessa linha é y = 9
8.
9. printf(\"x = %d, e y = %d\", x, y);
10.}
Observe que, ao utilizar “x++”, o programador consegue o mesmo resultado que
teria se usasse “x = x+1”, porém com uma escrita mais compacta. E quando
usadas em conjunto com um comando de atribuição, tanto a operação de
incremento quando a de decremento possuem dois tipos de construção, como
pode ser visto no exemplo do código a seguir:
1.#include <stdio.h>
2.int main()
3.{
4. int x, A, B;
5. x = 10;
6. A = ++x; // incrementa antes de atribuir
7. printf(\"x = %d, e A = %d \n\", x, A);
8.
9. x = 10;
10. B = x++; // atribui e depois incrementa
11. printf(\"x = %d, e B = %d\", x, B);
12.}
Existe uma diferença sutil entre as sintaxes “++x” e “x++”, e como estão sendo
utilizadas junto com uma atribuição, a forma com que são construídos os
comandos interfere muito em seu significado para o programa. No primeiro
caso, é realizado o incremento na variável x, e ao atribuir esse valor para a
variável A, seu conteúdo já está incrementado, ou seja, ambas passam a valer
11. Já no segundo caso, o conteúdo de x, que é 10, primeiro é atribuído a B, e
depois a variável x é incrementada para 11. Assim, B tem conteúdo igual a 10 e
x é igual a 11.
Estudante, você percebeu que a linguagem C permite uma ampla variedade
nessas construções? Isso proporciona a você mais opções e recursos, mas ao
mesmo tempo exige maior entendimento de suas regras.
CONHECENDO AS VARIAÇÕES DAS ATRIBUIÇÕES
Os operadores em C podem ser unários, binários e ternários, e essa
classificação está relacionada a quantos operandos constituem uma sentença
correta para o operador. Vamos conhecer cada um deles com um exemplo:
• Unários: realizam uma modificação (ou não) em relação a apenas uma
variável, como o sinal de menos. Exemplo: -x; -10.
• Binários: relacionam-se com os conteúdos de dois valores para retornar um
terceiro valor como resultado, como o operador soma ou, ainda, o de atribuição.
Exemplo: a + b; x = 10.
• Ternários: relacionam-se com três conteúdos, sendo usados para substituir
as sentenças “if then else”.
Assim como existe a notação de incremento e decremento nessa construção
mais compacta, também existem opções compactas para implementar outras
operações na linguagem C. Vamos conhecer as principais delas na Tabela 1.
Tabela 1 | Operadores de atribuição
Operador Operação executada Equivalente a
*= Atribuição de multiplicação saida = saida * 2
/= Atribuição de divisão saida = saida / 2
%= Atribuição restante saida = saida % 2
+= Atribuição de adição saida = saida + 2
-= Atribuição de subtração saida = saida - 2
Fonte: adaptada de Microsoft (2022, [s. p.]).
Um exemplo desses operadores sendo implementados em um código-fonte é
apresentado a seguir:
1.#include <stdio.h>
2.int main()
3.{
4. int saida;
5. saida = 6;
6. printf(\"saida multiplicacao = %d \n\", saida *= 2);
7.
8. saida = 6;
9. printf(\"saida divisao = %d \n\", saida /= 2);
10.
11. saida = 6;
12. printf(\"saida restante = %d \n\", saida %= 2);
13.
14. saida = 6;
15. printf(\"saida adicao = %d \n\", saida += 2);
16.
17. saida = 6;
18. printf(\"saida subtracao = %d \n\", saida -= 2);
19.}
Observe que a cada comando precisamos atribuir novamente o valor inicial 6 na
variável saida, pois o comando de atribuição aritmética realiza tanto a operação
aritmética quanto a atribuição na variável, atualizando seu valor. Por manipular
dois operandos, os operadores da Tabela 1 são considerados binários.
Outra classe interessante dos operadores é sua aplicação com valores binários.
Para demonstrá-los, considere:
• Uma variável X, de valor 18, em binário 0001 0010.
• Uma variável Y, de valor 98, em binário 0110 0010.
A operação AND bit a bit entre X e Y se refere a realizar a operação AND
(operador lógico) entre todos os bits do número, um a um, e escrever o valor
correspondente. Para o exemplo, X & Y resulta em: 0000 0010, ou seja, 2. Cabe
destacar que a operação lógica && realizada em valores decimais produz um
resultado diferente da operação AND bit a bit, representada pelo símbolo
unitário &.
O operador &= realiza o AND bit a bit entre as variáveis que compõem o
comando e atribui esse valor ao operando da esquerda.
Seguindo o mesmo raciocínio, considere também os outros operadores
específicos para representações em binário, apresentados na Tabela 2.
Tabela 2 | Operadores de atribuição para binários
Operador Operação executada Equivalente a
<<= Atribuição de shift esquerda Deslocamento de bits para a esquerda
>>= Atribuição de shift direita Deslocamento de bits para a direita
&= Atribuição AND bit a bit Realizar a operação AND nos valores
^=
Atribuição OR exclusivo bit a
bit
Realizar a operação OR exclusivo nos valores
|= Atribuição OR inclusivo bit a bit Realizar a operação OR inclusivo nos valores
Fonte: adaptada de Microsoft (2022, [s. p.]).
E uma aplicação em código-fonte resulta no código a seguir.:
1.#include <stdio.h>
2.int main()
3.{
4. // 3 = 0b0111;
5. int x;
6. x = 0b1001; //valor 9 em decimal
7. x &= 3; // será 0b0001, ou seja, 1.
8. printf(\"saida AND bit a bit = %d \n\", x);
9.
10. x = 0b00001001; //valor 9 em decimal
11. x <<= 3; // será 0b01001000, ou seja, 72.
12. printf(\"saida shift esquerda = %d \n\", x);
13.}
O operador de deslocamento atua deslocando todos os bits do número à
esquerda ou à direita, sendo que, conforme os bits são deslocados para um
dado sentido, zeros são usados para preencher as lacunas. No exemplo
apresentado no código, a variável binária x teve seus bits deslocados em três
posições para a esquerda, e como esse novo número foi atribuído a ela, deixou
de ser o número 0b00001001 (9 em decimal) para ser 0b01001000 (72 em
decimal).
Uma curiosidade a respeito de números binários é que cada deslocamento para
a esquerda é equivalente a multiplicar o número por 2. Sua aplicação se dá
principalmente na programação de microcontroladores ou drivers que
necessitam de controle do hardware.
O maior desafiona utilização desses operadores é que a escrita deles é muito
similar às operações matemáticas tradicionais. Ao analisá-la, o programador
precisa ter o mesmo entendimento que o compilador terá ao realizar o build do
código, pois muitas vezes podemos cair em ambiguidades permitidas pela
linguagem. Na dúvida, devemos fazer o debug do código, a fim de verificar por
meio dos testes de mesa se a execução do nosso programa está ocorrendo
conforme esperado.
APLICANDO CONCEITOS DE CONVERSÕES DE TIPOS
Outro aspecto que também requer a atenção do programador diz respeito ao
tipo das variáveis manipuladas e aos desdobramentos lógicos que podem
ocorrer ao longo da execução do programa. Esse tipo de situação ocorre com a
utilização dos operadores multiplicação (*), divisão (/) e restante (%), pois essas
operações costumam interferir no tipo do operando. Considere que temos os
números 13 e 5 para realizar uma divisão. Sabemos que 13 dividido por 5 é
igual a 2,6. Ao mesmo tempo, quando lidamos com problemas do dia a dia,
podemos ter a necessidade de construir raciocínios mais específicos.
Por exemplo: recebemos 13 camisetas para serem distribuídas para 5 pessoas.
Como não faria sentido cortar as camisetas, teríamos que 13 (int) dividido por 5
(int) é igual a 2 (int) com resto 3 (int).
Com os operadores, essas sentenças seriam escritas como: 13 / 5 = 2 para a
divisão com inteiros e 13 % 5 = 3 para o cálculo da operação resto, também
chamada de restante ou módulo.
1.#include <stdio.h>
2.int main()
3.{
4. float resultado;
5. int x, y;
6.
7. x = 13; y = 5;
8. printf(\"resultado = %f \n\", resultado = x/y);
9.
10. x = 13.0; y = 5.0;
11. printf(\"resultado = %f \n\", resultado = x/y);
12.
13. x = 13.0; y = 5.0;
14. printf(\"resultado = %f \n\", resultado = x%y);
15.}
Observe que, mesmo tentando inserir um valor do tipo real nas variáveis x e y, o
resultado apresentado na divisão não é 2.6, pois x e y foram declarados como
inteiros e nas linhas de atribuição eles já perdem a precisão de 13.0 e 5.0,
sendo tratados como inteiros 13 e 5.
Avaliando o mesmo código-fonte, porém com x e y do tipo float, percebemos
que a divisão é feita como esperado, mas o código apresenta um erro de
compilação na linha do último printf, pois o operador % não pode ser utilizado
com variáveis de tipo float, já que o compilador tentaria realizar a divisão com
diversas casas após a vírgula, tantas quantas fossem necessárias, conforme a
quantidade de dígitos do tipo da variável escolhida, e, portanto, a divisão não
apresentaria resto.
Tipos diferentes podem incorrer em truncamento ou perda de precisão, como
detalhado a seguir:
• O truncamento consiste em salvar a parte inteira de um número, ignorando as
casas decimais.
• A perda de precisão é a representação de um número com menos casas
decimais do que ele possui, o que também ignora parte dos dígitos.
Ao mesmo tempo, a linguagem C permite que o programador “adeque” tipos de
variáveis para contornar problemas de tipos que poderiam ocorrer em tempo de
execução, como o truncamento ou a perda de precisão. A realização dessa
modificação pelo programador recebe o nome de casting. Damas (2016)
descreve que o casting se dá quando queremos modificar o tipo de uma
variável ou expressão, alterando-o para um tipo maior ou para um tipo mais
baixo, e que podemos indicar o tipo ao qual queremos “promover” esse valor
colocando o tipo pretendido entre parênteses antes do valor.
Um exemplo dessa modificação é apresentado no código a seguir:
1.#include <stdio.h>
2.int main()
3.{
4. float result;
5. int valor, div;
6.
7. valor = 10;
8. div = 4;
9.
10. result = valor / div;
11. printf(\"Resultado: %f \n\", result); // resultado truncado
12.
13. result = 1.0 * valor / div;
14. printf(\"Resultado: %f \n\", result); // resultado forçado
pelo 1.0 *
15.
16. result = (float) valor / div;
18. printf(\"Resultado: %f \n\", result); // valor convertido
em float (casting)
19.
20. result = valor / (float) div;
21. printf(\"Resultado: %f \n\", result); // div convertido em
float (casting)
}
Observe que esse código indica a solução para o problema do código anterior,
que não apresentava a saída em número real.
Neste último código também vemos outro recurso interessante, que é o
comentário no código. Tudo o que está escrito na mesma linha após o // é
ignorado pelo compilador. Então, tal recurso é usado para que o programador
possa registrar comentários que auxiliem na leitura e no entendimento do
código, embora as boas práticas de programação digam que um código bem
escrito, com padrão na nomenclatura de variáveis, não necessita de
comentários.
VÍDEO RESUMO
Estudante, aprendemos nesta aula como o programa pode apresentar
respostas inesperadas ou incompletas se não definirmos os tipos de variáveis
corretamente. Vimos que o compilador segue à risca os tipos que definimos,
mas também permite alguns recursos que alteram o tipo da variável mesmo em
tempo de execução, realizando uma conversão explícita. Quanto aos exemplos,
eles não acabaram, então acompanhe o vídeo para estudarmos como funciona
a conversão de tipos implícita.
Saiba mais
A manipulação de caracteres e inteiros pode ocasionar dificuldades na
legibilidade do código, principalmente pelas conversões implícitas que a
linguagem C permite na execução dos programas. Para essas construções
específicas, Luís Damas organizou uma subseção em sua obra, com alguns
exemplos detalhadamente descritos.
O livro Linguagem C está na nossa biblioteca virtual, e o capítulo que aborda
esse assunto está na subseção Situações em que inteiros e caracteres não se
devem misturar, na página 43.
REFERÊNCIAS
Aula 1
MANZANO, J. A. N. G. Linguagem C: Acompanhada de uma xícara de café.
São Paulo: Érica, 2015.
Aula 2
MANZANO, J. A. N. G. Linguagem C: Acompanhada de uma xícara de café.
São Paulo: Érica, 2015.
MICROSOFT. Operadores relacionais e de igualdade C. Disponível
em: https://learn.microsoft.com/pt-br/cpp/c-language/c-relational-and-equality-
operators?view=msvc-170. Acesso em: 22 nov. 2022.
Aula 3
MANZANO, J. A. N. G. Linguagem C: acompanhada de uma xícara de café.
São Paulo: Érica, 2015.
Aula 4
DAMAS, L. Linguagem C. 10. ed. Rio de Janeiro: LTC, 2016.
MANZANO, J. A. N. G. Linguagem C: acompanhada de uma xícara de café.
São Paulo: Érica, 2015.
MICROSOFT. Operadores de atribuição C. 2022. Disponível
em: https://learn.microsoft.com/pt-br/cpp/c-language/c-assignment-operators?
view=msvc-170. Acesso em: 27 nov. 2022.
UNIDADE 4
APLICAÇÕES DE PROGRAMAÇÃO
•Aula 1 - Programação e funções com vetores
•Aula 2 - Programação com matrizes
•Aula 3 - Introdução à função e recursividade
•Aula 4 - Registros e arquivos
https://learn.microsoft.com/pt-br/cpp/c-language/c-relational-and-equality-operators?view=msvc-170
https://learn.microsoft.com/pt-br/cpp/c-language/c-relational-and-equality-operators?view=msvc-170
https://integrada.minhabiblioteca.com.br/reader/books/9788521632474
•Referências
Aula 1
PROGRAMAÇÃO E FUNÇÕES COM VETORES
Nesta unidade estudaremos a sintaxe e a codificação destes vetores, usando a linguagem de
programação C.
INTRODUÇÃO
Olá, estudante, hoje vamos iniciar uma nova unidade da disciplina de algoritmos
e lógica de programação, em que você verá na prática a programação de uma
estrutura de dados baseada em vetores, que é um recurso muito utilizado na
engenharia.
Na programação, o vetor é usado para manipular um conjunto de dados de um
mesmo tipo primitivo (inteiro, real, caracter). Estes ficarão em posições
contiguas da memória do computador, permitindo o seu acesso de uma forma
mais fácil e rápida.
Nesta unidade estudaremos a sintaxe e a codificação destes vetores, usando a
linguagem de programação C.
Vamos ver que os conceitos de declaração de variáveis, estrutura de repetição
e de vetores estudados nas unidades anteriores serão importantes e muito bem
aplicados nesta unidade.
Então, estudantes, vamos em frente.
PROGRAMAÇÃO DE VETORES EM UMA PSEUDOLINGUAGEM:PROGRAMAÇÃO E FUNÇÕES COM VETORES
Caro estudante, o vetor é uma estrutura que permite armazenar vários dados do
mesmo tipo em uma mesma variável.
Por exemplo: se quisermos armazenar em um programa as notas que 40 alunos
tiveram em uma determinada prova de uma disciplina e não tivéssemos o vetor,
precisaríamos usar no programa 40 variáveis com nomes distintos, sendo
armazenada em cada variável a nota de um aluno. Com o uso de vetor, vamos
conseguir armazenar em uma única variável as notas dos 40 alunos. Esta
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U4/index.html#referencias
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U4/index.html#aula4
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U4/index.html#aula3
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U4/index.html#aula2
https://conteudo.colaboraread.com.br/202301/WHITE_LABEL/ALGORITMOS_E_LOGICA_DE_PROGRAMACAO/LIVRO/U4/index.html#aula1
https://learn.microsoft.com/pt-br/cpp/c-language/c-assignment-operators?view=msvc-170
https://learn.microsoft.com/pt-br/cpp/c-language/c-assignment-operators?view=msvc-170
variável terá dentro dela 40 posições, sendo que, em cada posição, vamos
incluir a nota de um aluno.
O vetor também é chamado de estrutura composta homogênea unidimensional,
em que:
• Estrutura composta consiste nas várias posições que teremos na
variável.
• Homogênea porque estas posições são do mesmo tipo de dado (inteiro,
real, caracter).
• Unidimensional porque tem uma única dimensão; o multidimensional é
uma matriz.
O vetor passa a existir a partir da sua declaração, quando, então, lhe são
associados um nome ou identificador e a respectiva posição de memória por ela
representada. Qualquer referência ao seu identificador significa o acesso ao
conteúdo de uma única posição de memória (FARRER, 1999).
As posições do vetor são guardadas em uma sequência contínua de memória,
ou seja, uma posição seguida da outra.
A diferença da declaração de um vetor e de uma variável normal do programa
está na parte que vem após o nome, em que, na declaração do vetor, tem-se a
quantidade de posições do vetor entre colchetes.
Exemplo de nome do vetor: Vnota[40];
Exemplo de declaração do vetor: Real Vnota[40];
No qual temos:
• Real: tipo primitivo de dados do vetor, indicando que em cada posição do
vetor, será inserido um número do tipo real da matemática;
• Vnota: nome da variável do tipo vetor. Neste exemplo, será a nota dos
alunos;
• 40: quantidade de posições do vetor. Neste exemplo, cada posição conterá a
nota de um aluno.
Percebam que na declaração do vetor, ele é definido com 40 posições. Estas
posições são numeradas sequencialmente, iniciando com a posição 0 até a
posição 39. Chamamos estas posições de índice do vetor.
Figura 1 | Vetor Vnota
Fonte: elaborada pelo autor.
Agora vamos trabalhar com este vetor, usando uma pseudolinguagem,
inserindo nas posições do vetor as notas dos alunos.
A posição que desejamos inserir a nota, colocamos entre os colchetes:
Vnota [ 6 ] = 6,5; // será inserido o valor 6,5 na posição 6 do
vetor
Vnota [ 1 ] = 7,8;
Vnota [ 3 ] = 5,3;
Figura 2 | Vetor Vnota
Fonte: elaborada pelo autor.
Conseguimos acessar as posições de forma aleatória, ou seja, fomos para a 6ª
posição, depois para a 1ª posição e depois para a 3ª posição do vetor.
Vamos incluir novos elementos no vetor, mas usando uma nova variável A, que
terá a posição em que será incluído o elemento no vetor.
Inteiro A;
Leia (A); // supondo que foi informado 5
Vnota[ A ] = 9,8;
Vnota [ A-1 ] = 9,1;
Leia (Vnota [ A+2 ] ); // supondo que foi informado 4,7
No final da execução, o vetor ficará da seguinte forma:
Figura 3 | Vetor Vnota
Fonte: elaborada pelo autor.
PROGRAMAÇÃO DE VETORES NA LINGUAGEM C
Vamos agora aprofundar nossos conhecimentos referentes à codificação de
vetores, trabalhando em um exemplo da codificação do vetor na linguagem de
programação C.
Vamos usar o mesmo vetor Vnota que codificamos anteriormente uma
pseudolinguagem, mas agora, vamos implementá-lo na linguagem de
programação C.
Para facilitar a aprendizagem, será mostrado o código em C, numerando as
linhas do programa e, em seguida, será comentada cada uma das linhas.
1 #include <stdio.h>
2 main()
3 {
4 float Vnota[40];
5 int A;
6 Vnota [6]=6.5;
7 Vnota [1]=7.8;
8 Vnota [3]=5.3;
Inicialmente, foi declarada na linha 1 do programa, a biblioteca stdio.h da
linguagem C, para usarmos os comandos de entrada e saída de
dados printf e scanf.
A linha 2 tem a declaração do programa principal e na linha 3 o início do seu
bloco.
Na linha 4, foi criado o vetor Vnota, com 40 posições e nas linhas 6, 7 e 8 foram
incluídas as notas 6,5, 7,8 e 5,3 nas posições 6, 1 e 3 do vetor.
Dando sequência na codificação do programa do vetor, temos:
9 printf (\"Digite o valor de A: \");
10 scanf(\"%d\",&A);
11 Vnota[A]=9.8;
12 Vnota[A-1]=9.1;
13 printf(\"Digite o valor de Vnota[A+3]: \");
14 scanf(\"%d\",&Vnota[A+3]);
15 printf (\"Valores do vetor:\");
16 for (int x=0;x<10;x++)
17 printf (\"\nVnota[%d] = %.1f\",x,Vnota[x]) ;
18 }
Nas linhas 9 e 10, foi solicitada a entrada de um dado do tipo inteiro que será
armazenado na variável A. O valor desta variável está sendo usado como
posição de memória para a inclusão da nota 9,8. Se for digitado o valor 5, a
nota 9,8 será inserida na posição 5 do vetor, conforme mostrado na linha 11.
Na linha 12, foi subtraído 1 do valor digitado, ou seja, se foi digitado o valor 5, a
nota 9,1 será incluída na posição 4 do vetor.
Na linha 13 e 14, foi solicitada a digitação de uma nota, sendo esta inserida na
posição A+3, ou seja, a nota digitada será inserida na posição 8, se o valor
digitado para A foi 5.
Para acessar todas as posições do vetor, precisamos usar uma estrutura de
repetição. Dentro desta estrutura de repetição conseguimos acessar todos os
elementos do vetor.
A estrutura de repetição mais indicada para a manipulação do vetor é o Para
(valor inicial do índice, condição de repetição, incremento do índice). A
codificação desta estrutura de repetição está nas linhas 16 e 17 deste código.
Como pode ser observado, a estrutura de repetição se inicia com o valor 0 no
índice, para acessar a 1ª posição do vetor, incrementando de 1 em 1 para cada
execução dos comandos que fazem do bloco da estrutura de repetição, até a
última posição do vetor.
Com a execução do programa, a saída que será mostrada será a seguinte:
Figura 4 | Tela do DEV C++ com a saída da execução do programa
Fonte: captura de tela do DEV C++ elaborada pelo autor.
MANIPULAÇÃO DAS VARIÁVEIS DO VETOR
Um algoritmo clássico em que precisamos usar vetor é quando precisamos ler
determinados valores, fazer algum tipo de cálculo com os dados e depois
comparar o que foi calculado com os valores lidos. Por exemplo: lançar as notas
dos alunos de uma determinada disciplina e depois mostrar a quantidade de
notas maiores que a média.
Para resolver, é necessário ler todas as notas e armazená-las em um vetor.
Com os valores armazenados, será possível manipulá-los.
Então vamos resolver da seguinte forma: (1) ler as notas dos alunos, (2)
calcular a média aritmética, (3) comparar cada nota com a média calculada (4)
contar as notas maiores que a média (5) mostrar a quantidade.
O algoritmo que implementa este exemplo segue abaixo:
1 #include <stdio.h>
2 main()
3 {
4 float Vnota[10], somanota=0, media;
5 int somamaior=0;
6 for (int x=0;x<10;x++)
7 {
8 printf (\"Digite a nota %d :\",x+1);
9 scanf(\"%f\",&Vnota[x]);
10 somanota = somanota + Vnota[x];
11 fflush(stdin);
12 }
13 media = somanota / 10;
14 printf (\" Media das notas: %.1f\",media);
15 for (int x=0;x<4;x++)
16 {
17 if (Vnota[x]>media)
18 somamaior ++;
19 }
20 printf (\"Quantidade de notas maiores que a media:
%d\",somamaior);
21 }
Vamos fazer um outro exercício com vetor, mas agora oselementos do vetor
serão inicializados quando forem declarados. Depois vamos somar os
elementos do vetor e mostrar o resultado da soma.
1 #include <stdio.h>
2 #include <stdio.h>
3 main()
4 {
5 int vetor[5]={1,3,5,7,9},soma=0;
6 for (int cont=0;cont<5;cont++)
7 soma = soma + vetor[cont];
8 printf(\"Soma dos elementos do vetor: %d\",soma);
9 }
Continuando este mesmo programa, agora vamos mostrar o vetor que foi
declarado e inicializado na linha 4, de trás para frente, ou seja, o último
elemento do vetor será o último mostrado, o penúltimo será o segundo e assim
sucessivamente.
9 #include <stdio.h>
10 for (int cont=4;cont>=0;cont--)
11 printf(\"\nElemento %d do vetor: %d\",cont,vetor[cont]);
12 }
Veja que, para mostrar o vetor de trás para frente, foi codificada uma estrutura
de repetição, iniciando com o valor do maior índice do vetor e decrementando
de 1 até a primeira posição do vetor.
VÍDEO RESUMO
Saiba mais
Para codificar programas na linguagem de programação C, você deverá usar
um aplicativo que tenha as ferramentas necessárias para programar em C/C++.
Recomendamos o uso do Bloodshed Dev C++. Este pacote compõe um
ambiente completo de desenvolvimento para a criação, debug e compilação do
código de programação em C, e pode ser analisado e ser feito download em
seu site.
Aula 2
PROGRAMAÇÃO COM MATRIZES
Nesta aula, estudaremos a sintaxe e a codificação de matrizes, usando a linguagem de programação
C.
INTRODUÇÃO
Olá, estudante, hoje vamos para um novo tópico da disciplina Algoritmos e Lógica de Programação,
em que você verá na prática a programação de uma estrutura de dados baseada em matrizes.
Nesta aula, estudaremos a sintaxe e a codificação de matrizes, usando a linguagem de programação
C.
Vamos ver que a aprendizagem do funcionamento de um vetor estudado anterioriormente é muito
importante para o entendimento de matrizes, por ser uma estrutura composta homogênea que traz
uma maior complexidade na sua codificação.
Vamos ver também que a matriz é um instrumento muito usado pelos programadores para resolver
vários problemas do dia a dia na programação.
Então, estudantes, vamos em frente.
DEFINIÇÃO, CARACTERÍSTICAS E SINTAXE DE MATRIZES
Caro estudante, vamos estudar outra forma de organizar os dados dentro de uma estrutura baseada
em matrizes da matemática.
Enquanto um vetor é uma estrutura de dados homogênea unidimensional, pelo motivo de crescer os
dados de estrutura apenas em uma direção, que é para o lado direito, na forma de linha, a matriz é
uma estrutura de dados homogênea multidimensional, por permitir crescer os dados da estrutura em
mais de uma direção, que é para o lado direito (linha) e para baixo (coluna).
Vamos ver isto no exemplo abaixo:
Exemplo de um vetor com 8 elementos, uma letra em cada posição do vetor:
Figura 1 | Vetor Letras[8]
Fonte: elaborada pela autora.
Se quisermos inserir novos elementos no vetor, estes deverão ser incluídos em novas posições, que
ficarão do lado direito, na mesma linha.
Agora vamos para um exemplo de uma matriz, com 8 elementos divididos em linhas e colunas.
Figura 2 | Matriz Letras[2,4]
https://www.bloodshed.net/
Fonte: elaborada pela autora.
Veja que organizamos os mesmos dados representados no vetor, mas agora em 2 linhas e 4 colunas.
Esta forma de organização de estrutura de dados foi feita em uma matriz [2,4].
Se quisermos incluir novos elementos na matriz, podemos inclui-los em uma nova coluna no lado
direito, mas também podemos incluí-los em uma nova linha, abaixo da existente.
Da mesma forma que o vetor, as matrizes precisam ter um nome e precisam ter índices para
identificar a posição dos seus elementos. Como a matriz que estamos representando possui 2
dimensões, baseada na linha e na coluna, precisamos de 2 índices para identificar uma posição de
um elemento na matriz, o primeiro identifica a linha e o segundo identifica a coluna.
Por exemplo:
• Elemento da posição da matriz Letra [0,2] = C.
• Elemento da posição da matriz Letra [1,3] = H.
A matriz também é uma estrutura composta homogênea, com isto, todos os seus elementos devem
ter o mesmo tipo primitivo de dado (inteiro, real, caracter). Com isto, quando declaramos uma
matriz, precisamos identificar qual é o tipo de dados que serão inseridos nas suas posições.
Por exemplo:
Caracter Letra[2,4] => é uma matriz em que poderão ser inseridos até 8 elementos do tipo caracter.
Em que temos:
• Caracter: tipo primitivo de dados do vetor, indicando que em cada posição do vetor, será inserido
um caracter.
• Letra: nome da variável do tipo matriz.
• 2: quantidade de linhas da matriz
• 4: quantidade de colunas da matriz.
Percebam que na declaração da matriz, ela é definida com 8 posições divididas em 2 linhas e 4
colunas. O índice para a linha é numerado sequencialmente, iniciando com 0, da mesma forma para
a coluna, que também tem um índice iniciando com 0.
Outro exemplo:
Real Nota[3,4] => é uma matriz em que poderão ser inseridos até 12 elementos do tipo real.
PROGRAMAÇÃO DE MATRIZES NA LINGUAGEM C
Vamos agora aprofundar nossos conhecimentos na codificação de matrizes na linguagem de
programação C.
Vamos usar como exemplo o mesmo Vnota que usamos para codificá-lo na forma de vetor, mas,
agora, vamos trabalhar com o Vnota na forma de uma estrutura de dados homogênea bidimensional,
que é uma matriz.
Para facilitar a aprendizagem, será mostrado o código em C, numerando as linhas do programa e,
em seguida, será comentada cada uma das linhas.
1 #include <stdio.h>
2 main()
3 {
4 float Vnota[4][10];
5 int x,y;
6 Vnota [0][0]=8.1;
7 Vnota [0][2]=6.5;
8 Vnota [1][4]=7.8;
9 Vnota [2][6]=9.4;
10 printf (\"Digite o valor de X: \");
11 scanf(\"%d\",&X); // Será digitado o valor 2
12 printf (\"Digite o valor de Y: \");
13 scanf(\"%d\",&Y); // Será digitado o valor 1
14 Vnota[x][y]=6.0;
15 Vnota[x][y+1]=3.9;
16 Vnota[x+1][y+2]=7.0;
17 printf(\"Digite o valor de Vnota[9.9]: \");
18 scanf(\"%d\",&Vnota[9][9]; // Será digitado o valor 8.4
22 }
Com a inserção destes elementos na matriz, ela fica desta forma:
Figura 3 | Matriz float Vnota[4,10]
Fonte: elaborada pelo autor
Na linha 4, foi declarada uma matriz com nome Vnota, com 40 posições, organizada na forma de 4
linhas e 10 colunas, sendo os elementos da matriz do tipo de dados float (Real).
Nas linhas 6 a 9, foram inseridos elementos na matriz nas posições [0,0], [0,2],[1,4] e [2,6].
Nas linhas 11 e 13 foram solicitadas a entrada de dois dados do tipo inteiro que serão armazenados
respectivamente nas variáveis x e y. Supondo neste exemplo que foram digitados os valores 2
para x e 1 para y.
Na linha 14 os valores da variáveis x e y foram usados para a inclusão do elemento 6.0 na posição
[2,1] da matriz.
Na linha 15 a variável y que é usada para indicar a coluna, foi incrementada de 1, com isto, o
elemento 3.9 foi incluído na posição [2,2] da matriz.
Na linha 16, a variável x que é usada para indicar a linha, foi incrementada de 1 e a variável y que é
usada para indicar a coluna, foi incrementada de 2, com isto, o elemento 7.0 foi incluído na posição
[3,3] da matriz.
Na linha 17 e 18, foi solicitado a digitação de uma nota, sendo está inserida na posição [9,9] da
matriz.
Para acessar todos os elementos de uma matriz, precisamos usar uma estrutura de repetição dentro
de outra estrutura de repetição, em que a estrutura de repetição externa vai passar por todas as linhas
e a estrutura de repetição interna vai passar pelas colunas da matriz.
Vamos ver este exemplo:
1 for (x=0;x<4;x++)
2 {
3 for (y=0;y<10;y++)
4 printf (\"\n Nota: %.2f,\",Vnota[x][y]);
5 }
A variável x é para a linha e a variável y é para a coluna. Iniciamos a variável x com o valor 0 na
estrutura de repetição que está na linha 1. A estrutura de repetição que está na linha 3 inicia com a
variável y com valor 0, então será mostrado o elemento de Vnota[0,0], que é o comando da linha 4.
A estrutura de repetição de linha 3 incrementa 1 em y, mostrando o elemento de Vnota[0,1] e fica
nestelooping até que y tenha o valor 10, ou seja, serão mostrados todos os elementos da linha 0 da
matriz. Depois, o programa volta para e estrutura de repetição da linha 1, incrementando 1 em x e
executa novamente a estrutura de repetição da linha 3, voltando y com o valor 0. Com isto, é
percorrida toda a linha 1 da matriz. Este processamento fica até que x tenha o valor 5, saindo da
estrutura de repetição da linha 1.
Como pode ser observado, a estrutura de repetição se inicia com o valor 0 no índice, para acessar a
1ª posição do vetor, incrementando de 1 em 1 para cada execução dos comandos que fazem do
bloco da estrutura de repetição, até a última posição do vetor.
IMPLEMENTAÇÃO DE MATRIZES
Agora vamos codificar uma matriz para atender o seguinte enunciado:
Faça um programa em C que tenha uma matriz M[3,4] e insira os valores 1 a 12 nos elementos da
matriz, conforme figura abaixo. Depois some os elementos da matriz que estão marcados em
vermelho.
Figura 4 | Matriz int M[3,4]
Fonte: elaborada pela autora.
Podemos perceber que a matriz tem valores sequenciais para os elementos e que os elementos que
estão marcados em vermelho são os que estão na posição em que o valor da coluna é maior que o
valor da linha. Desta forma, podemos codificar o programa da seguinte forma:
1 #include <stdio.h>
2 main()
3 {
4 int M[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12},soma=0;
5 for (int x=0;x<3;x++)
6 {
7 for (int y=0;y<4;y++)
8 {
9 if ( y > x)
10 soma= soma + M[x][y];
11 }
12 }
13 printf(\"Soma dos elementos:%d\",soma);
14 }
Na linha 4 do programa, inicializamos a matriz no mesmo momento da sua declaração, como uma
matriz [3][4] tem 12 elementos, fizemos uma definição sequencial de 1 a 12 entre chaves logo após
a declaração de matriz.
Como é solicitado que sejam somados somente os elementos em vermelho e estes elementos são os
que a coluna é maior que a linha, consideramos no programa que a variável x para a linha,
declarado na estrutura de repetição externa e y para a coluna, declarado na estrutura de repetição
interna.
Na linha 9, foi codificada uma condicional, considerando somente os elementos nos quais o valor
de y (coluna) for maior que x(linha).
Como resultado da execução do programa, teremos: Soma dos elementos: 36
Vamos para um segundo enunciado em que se faz necessário o uso de matriz:
Faça um algoritmo que leia uma matriz M[3,3] e um valor X. A seguir, multiplique cada elemento
da matriz pelo valor X, colocando o resultado da multiplicação de cada elemento da matriz em um
vetor V[9]. No final, o algoritmo deve listar todos os elementos do vetor.
Veja que para a codificação deste programa, vamos usar os conhecimentos de matrizes e vetores.
1 #include <stdio.h>
2 main()
3 {
4 int M[3][3],V[9],cont=0;
5 for (int x=0;x<3;x++)
6 {
7 for (int y=0;y<3;y++)
8 {
9 printf (\" Valor: \");
10 scanf(\"%d\",&M[x][y]);
11 V[cont]=M[x][y];
12 cont++;
13 }
14 }
15 for (cont=0;cont<9;cont++)
16 printf (\" %d \",V[cont]);
17 }
Na linha 4 do programa, declaramos uma matriz [3][3] e um vetor [9].
Na linha 10, fizemos a codificação para a leitura dos elementos da matriz M[3][3].
Na linha 11, atribuímos o valor de cada elemento da matriz para uma posição do vetor V[9].
Na linha 15 declaramos uma nova estrutura de repetição para percorrer todo do vetor V[9],
mostrando os elementos do vetor (linha 16].
A saída para a execução deste programa será a seguinte:
Figura 5 | Tela do DEV C++ com a saída da execução do programa
Fonte: captura de tela do DEV C++ elaborada pelo autor.
VÍDEO RESUMO
Olá, estudante, neste vídeo vamos estudar formas de organização dos dados em uma estrutura
baseada em matrizes da matemática. Vamos ver como ela deve ser usada, a sintaxe e a codificação
destas matrizes, usando a linguagem de programação C.
Saiba mais
Veja os conceitos e dicas para codificação de matrizes no site Learn da
Microsoft.
Aprofunde os seus conhecimentos sobre matrizes aplicadas na matemática e
na ciência da computação, no site do Khanacademy.
Aula 3
INTRODUÇÃO À FUNÇÃO E RECURSIVIDADE
Vamos ver que podemos criar as nossas próprias funções no programa e podemos usar as funções
pré-definidas, as quais ajudam, e muito, na organização dos programas.
INTRODUÇÃO
Olá, estudante, hoje vamos para um novo tópico da disciplina de Algoritmos e
Lógica de Programação, em que será abordado o recurso de funções na
https://pt.khanacademy.org/math/algebra-home/alg-matrices
https://learn.microsoft.com/pt-br/cpp/c-language/array-declarations
https://learn.microsoft.com/pt-br/cpp/c-language/array-declarations
https://learn.microsoft.com/pt-br/cpp/c-language/array-declarations
https://learn.microsoft.com/pt-br/cpp/c-language/array-declarations
programação de computadores.
Vamos ver que podemos criar as nossas próprias funções no programa e
podemos usar as funções pré-definidas, as quais ajudam, e muito, na
organização dos programas.
Também vamos estudar um tipo especial de função que permite a codificação
de recursividade, em que a função é chamada para si mesma.
Vamos ver que as funções são soluções elegantes e simples nos programas,
mas esta elegância e simplicidade têm um preço que requer muita atenção em
sua implementação. Então estudantes, vamos em frente.
DEFINIÇÃO E EXEMPLO DE FUNÇÕES
Caro estudante, quando precisamos resolver um problema na programação e
tentamos dividi-lo em subproblemas independentes, resolvendo o problema “em
pedaços”, de forma mais simples, podemos usar o recurso chamado de função.
A função cria uma forma de encapsulamento da sua lógica interna, expondo
como se fosse um serviço, na qual um bloco de comandos será executado,
recebendo alguns parâmetros de entrada e retornando um resultado como
saída da função.
O principal benefício de usar funções na programação é que podemos
evitar repetição de linhas de código, pois, se o programador quiser executar
uma operação mais de uma vez, ele pode simplesmente escrever a função uma
vez e utilizá-la diversas vezes, ao invés de escrever o mesmo código várias
vezes.
Outro benefício é que se você desejar alterar ou corrigir alguma coisa mais
tarde, é mais fácil alterar em um único lugar.
Toda função precisa ser invocada para ser executada. Desta forma, quando
uma função que já foi usada anteriormente é invocada, o programador não vai
mais precisar se preocupar como a lógica deve ser realizada na função e
também não vai precisar se preocupar com os testes da função.
Funções são codificadas independentemente umas das outras e as variáveis
usadas dentro de funções não são compartilhadas, ou seja, as variáveis
são locais a uma função.
As funções se comunicam por meio de parâmetros passados como entrada e os
valores retornados como saída, com isto, a comunicação entre as funções é
totalmente controlada.
A função poderá também chamar a si própria, criando-se uma função recursiva.
Este tipo de função torna-se uma implementação elegante e simples, por serem
executadas tarefas repetitivas sem utilizar nenhuma estrutura de repetição.
Para declarar uma função no programa, a seguinte sintaxe deve ser utilizada:
<tipo> nome_da_função (<tipo> parâmetro1,
<tipo> parâmetro2, ..., <tipo> parâmetroN)
{
<corpo da função>
return valor_de_retorno;
}
Toda função deve ter um tipo de dados. Esse tipo determina qual será o tipo de
seu valor de retorno, podendo ser inteiro, real, caractere, etc. Quando a função
não tem um tipo (void), então ela não pode retornar um valor, ou seja, passa a
ser um procedimento.
Os parâmetros são os valores passados para a função que vão sofrer algum
tipo de modificação durante a execução dos comandos da função como se
fosse uma função matemática, em que o parâmetro é o valor de entrada função.
As funções devem ser declaradas antes do programa principal (main).
Exemplo de função:
1 #include
2 int soma(int a, int b)
3 int soma;
4 soma = a + b;
5 return soma;
6 }
7 main() {
8 printf("Soma de 2 numeros: %d",soma(5,10));
9 }
Neste exemplo, foi codificada a função soma,que recebe 2 números inteiros
como parâmetro de entrada, faz a soma dos 2 números e retorna o resultado;
A função soma foi invocada no programa principal.
Existem algumas funções na linguagem C que já estão prontas, ou seja, estão
codificadas e testadas. Elas recebem o nome de funções pré-definidas.
Pará usá-las, precisamos somente declarar no programa o nome da biblioteca
onde está a função.
Por exemplo: para calcular a potenciação de um número, podemos usar a
função pré-definida pow(base, potência), da seguinte forma:
1 #include <stdio.h>
2 #include <math.h>
3 main() {
4 printf(\"Potenciação de 2 elevado a 3: %d\",pow(2,3));
5 }
Veja que incluímos a biblioteca <math.h> no programa. Dentro desta biblioteca
há a função chamada pow, que calcula a potenciação. No programa principal,
invocamos a função pow, passando como parâmetro o valor 2 como base e 3
como potência. O resultado que será mostrado neste programa será 8.
PROGRAMAÇÃO DE FUNÇÕES E RECURSIVIDADE A
LINGUAGEM C
Vamos agora aprofundar nossos conhecimentos de funções pré-definidas,
dando ênfase às funções matemáticas, devido a sua importância para a área de
engenharia.
Veja abaixo exemplos de funções pré-definidas que estão prontas na biblioteca
math.h da linguagem C.
Tabela 1 | Funções pré-definidas da biblioteca math.h
Função Descrição
fmod(dividendo,divisor) Retorna o resto da divisão (float dividendo, float divisor)
abs(numero) Retorna o valor absoluto do número (int numero)
sqrt(numero) Retorna a raiz quadrada do número
modf(num, *inteiro) Separa a parte fracionária da inteira de número
asin(numero) Retorna o arco seno de número
acos(numero) Retorna o arco cosseno de número
atan(numero) Retorna o arco tangente de número
floor(float num): Retorna o menor inteiro menor que número (ex. 9.9 retorna 9)
ceil(float num): Retorna o maior inteiro maior que número (ex. 9.9 retorna 10)
strrev(num) Retorna o inverso do número (número espelhado)
Fonte: elaborada pelo autor.
Considerando a existência da função sqrt(numero) para calcular a raiz
quadrada de um número, veja como fica fácil realizar o cálculo resolver a raiz
quadrada de 9:
1 #include <stdio.h>
2 #include <math.h>
3 main() {
4 printf(\"Raiz Quadrada de 9: %d\",sqrt(9));
5 }
Temos outras bibliotecas, com outros tipos de funções pré-definidas, tais como:
1. <stdio.h> Contém funções para entrada e saída de dados.
2. <time.h> Contém funções para manipular horários e datas.
3. <strings.h> Contém funções para manipulação de strings.
4. <conio.h> Contém funções para manipulação de vídeo.
5. <stdlib.h> Contém funções para conversão de números em texto e vice-
versa, locação de memória, números aleatórios, busca e ordenação.
6. <ctype.h> Contém funções para classificar caracteres pelo tipo ou para
converter entre caixa alta e baixa independentemente da codificação.
Por exemplo: já estamos acostumados em usar as funções pré-definidas printf()
e scanf() da biblioteca <stdio.h>, não sabemos como elas foram escritas, mas
sabemos como utilizá-las, ou seja, sabemos o nome das funções e quais
informações precisamos fornecer como parâmetros para que a função produza
os resultados esperados.
Implementação de funções recursivas
Vamos ver agora a codificação de funções recursivas, em que a função chama
a si própria ou chama outras funções que, em algum momento, chama a
primeira, tornando-se um processo recursivo.
Cada chamada da função recursiva é inserida numa espécie de pilha, sendo o
limite de vezes para a sua chamada limitada ao tamanho desta pilha. Se o
valor correspondente ao tamanho máximo da pilha for atingido, haverá um
estouro da pilha ou Stack Overflow, por este motivo, a sua codificação requer
muita atenção.
Trazendo a recursividade para a nossa realidade, vamos considerar como
exemplo a ação contar o valor em dinheiro que temos em um saco de moedas.
Cada ato de retirar uma moeda do saco, ver o valor e somá-lo ao valor das
moedas já retiradas é um processo recursivo.
Este processo de retirar uma moeda, identificar seu valor e somar com o
restante do saco se repete até que o saco esteja vazio, quando atingiremos o
ponto de parada e a função retornará o valor zero, indicando que não há mais
moedas no saco.
Nesse ponto a função contar dinheiro foi chamada um número de vezes igual a
quantidade de moedas no saco, e a última chamada começa a devolver os
valores de retorno de cada instância da função, iniciando por zero (saco vazio),
somado ao valor da última moeda, da penúltima etc., até retornar à primeira
chamada referente a primeira moeda, e nesse momento a função inicial se
encerra trazendo como valor de retorno a soma dos valores de todas as
moedas que estavam no saco.
EXEMPLOS PRÁTICOS DE RECURSIVIDADE
Estudante, vamos agora aplicar a recursividade nas linguagens de
programação, lembrando que, é um recurso de programação que pode ser
usado nas linguagens C, C++, Java, Visual Basic, Python, entre outras. Aqui
continuaremos usando a linguagem de programação C.
As funções recursivas contêm duas partes fundamentais:
1. Ponto de Parada ou Condição de Parada: é o ponto onde a função
será encerrada.
2. Regra Geral: é o método que reduz a resolução do problema através da
invocação recursiva de casos menores, que por sua vez são resolvidos pela
resolução de casos ainda menores pela própria função, assim sucessivamente
até atingir o “ponto de parada” que finaliza a função.
Cada vez que uma função é chamada de forma recursiva, são alojados e
armazenados uma cópia dos seus parâmetros, de modo a não perder os
valores dos parâmetros das chamadas anteriores.
A chamada a uma função recursiva é igual à chamada de uma função não
recursiva, na qual é necessário guardar uma “estrutura de invocação”, sendo
esta estrutura liberada depois do fim da execução da função e atualização do
valor de retorno.
Vamos então ver um exemplo de programa com recursividade, onde será criada
uma função que faça a soma dos números e fica chamando a si próprio até que
a condição de parada aconteça. Neste exemplo, será somado os números no
intervalo de 5 até o número 0.
1 #include <stdio.h>
2 int soma(int x)
3 {
4 int y;
5 if( x == 0 )
6 return 0;
7 else
8 {
9 y = x + soma(x -1);
10 return y;
11 }
12 }
13 main()
14 {
15 int num;
16 printf(\"\nA soma de 0 ate 5 = %d \",soma(5));
17 }
Na linha 2 do programa, temos a declaração da função soma.
Na linha 9, temos a chamada recursiva da função soma, onde será somado o
valor do número, acumulando a soma na variável y.
Na linha 5 temos a condição de parada, que é quando o número chega no valor
0, ou seja, está iniciando em 5, que é o parâmetro recebido na função e vai até
o valor 0.
Na linha 16 temos a chamada da função soma, passando o valor 5 como
parâmetro.
Os valores que estão sendo somados ficarão em uma pilha até a condição de
parada. De uma forma ilustrativa, ficará da seguinte forma:
Figura 1 | Função Recursiva
Fonte: elaborada pelo autor
Vamos para um segundo exemplo de recursividade, codificando-se agora uma
função recursiva para somar a quantidade de dígitos de um número. Será
usada na função recursiva, a função pré-definida abs(num) para teste da
condição de parada e será contado na função recursiva conta, a quantidade de
dígitos do número 10.000, sendo este passado como parâmetro para a função
recursiva conta.
1 #include <math.h>
2 #include <stdio.h>
3 int conta(int x)
4 {
5 int y;
6 if(abs(x) < 10 )
7 return 1;
8 else
9 y = 1 + conta(x/10);
10 }
11 main()
12 {
13 int num = 10000;
14 printf(\"Total: %d\",conta(num));
15 }
De uma forma ilustrativa, este programa funcionará da seguinte forma:
Figura 2 | Função recursiva para contar dígitos de um número
Fonte: elaborada pelo autor
VÍDEO RESUMO
A maior motivação que temos para estudar a codificação de funções nas
linguagens de programações contemporâneas é a redução da complexidade e a
melhoria da modularidade dos programas. Entãovamos ver neste vídeo, como
implementamos estas funções e também exemplos práticos com a sua
aplicabilidade.
Saiba mais
Você poderá criar o seu programa recursivo, usando um site Paiza.io para
compilar e executar o programa de forma on-line.
Agora faça um teste usando este site, copiando e colando o programa recursivo
abaixo, que faz a soma dos números que estão no intervalo de 0 a 5.
#include <stdio.h>
int soma(int x)
{
int y;
if( x == 0 )
return 0;
else
{
y = x + soma(x -1);
return y;
}
}
int main()
{
int num;
printf(\"\nA soma de 0 ate 5 = %d \",soma(5));
}
Aula 4
REGISTROS E ARQUIVOS
https://paiza.io/projects/eLk7pkGinhQcwFgf0UDv4g?language=c%20
https://paiza.io/projects/eLk7pkGinhQcwFgf0UDv4g?language=c%20
Vamos ver que o registro é um recurso importante para a organização dos dados utilizados nos
programas, pois permite tratar os dados na visão de um conjunto de dados heterogêneos.
INTRODUÇÃO
Olá, estudante, vamos para um novo tópico da disciplina de Algoritmos e Lógica
de Programação, em que será abordada a programação de registros e
manipulação de arquivos, usando a linguagem de programação C.
Vamos ver que o registro é um recurso importante para a organização dos
dados utilizados nos programas, pois permite tratar os dados na visão de um
conjunto de dados heterogêneos.
Vamos ver também como podemos manipular arquivos nos programas em C,
gravando e recuperando os conjuntos de dados a serem tratados nos
programas. Então, os registros serão tratados como um conjunto de campos e
os arquivos como um conjunto de registros.
DEFINIÇÃO DE REGISTROS E ARQUIVOS
Caro estudante, ao manusearmos dados nos programas, muitas vezes, nos
deparamos com informações que não são simples de armazenar em variáveis
homogêneas, como são os tipos inteiros, reais e caracteres, mas, na verdade,
eles são um conjunto de vários dados. Este conjunto de dados passa a ser
então composto com várias variáveis do tipo inteiro, real e caractere que, de
alguma forma, são interligadas, formando um registro.
Segundo Farrer (1999), os registros são um conjunto de dados logicamente
relacionados, mas de tipos diferentes, que facilita o agrupamento de variáveis
que não são do mesmo tipo e que têm estreita relação lógica entre eles.
Por exemplo: vamos definir um registro para representar um determinado
produto.
Figura 1 | Registro Produto
Fonte: elaborada pelo autor.
Este registro produto está definido com as variáveis Codigo, Descricao, Unidade
e Preco, sendo que cada variável precisa agora ser associada um determinado
tipo de dados, ficando então da seguinte forma:
Inteiro Codigo,
Caracter Descricao,
Caracter Unidade
Real Preco
Agora vamos atribuir valores para eles:
Figura 2 | Registro Produto
Fonte: elaborada pelo autor.
Neste exemplo, temos um registro definido para o produto de código 0001,
sendo ele formado por variáveis de tipos diferentes.
Os registros são classificados como variáveis compostas heterogêneas, pois
permitem agrupar variáveis de tipos diferentes, como mostrado no exemplo
acima.
Dependendo do volume de registros que deverá ser tratado no programa, não
será possível mantê-los em memória, por falta de espaço ou pela necessidade
de armazená-lo por um período de tempo longo. A alternativa para isto é
armazenar os registros em um arquivo.
O arquivo é então um conjunto de registros armazenados em algum dispositivo
secundário, como por exemplo, um disco HD.
As operações básicas que podem ser feitas neste arquivo, por meio de um
programa em C são: obtenção de um registro do arquivo, inserção de um novo
registro, modificação ou exclusão de um registro.
A disposição dos registros no arquivo pode favorecer determinadas operações
em detrimento de outras. O conhecimento das possibilidades de organização
dos registros nos arquivos permite ao programador escolher aquela que seja
mais adequada à solução do seu problema em termos de eficiência e eficácia.
Existem 2 possibilidades de organização dos arquivos:
1. Sequencial: os registros são inseridos ou consultados no arquivo na
ordem sequencial.
2. Direta: o acesso ao registro é feito em ordem aleatória.
Os arquivos podem assumir 2 formatos:
1. Texto: armazena caracteres que podem ser mostrados diretamente na tela
ou modificados por editores de texto simples.
- Exemplos: lista de dados, código C, texto simples, páginas HTML.
2. Binário: arquivo tem uma sequência de bits sujeita às convenções dos
programas que o geraram, não sendo legíveis diretamente.
- Exemplos: arquivos executáveis ou compactados.
Os registros, combinados com o seu armazenamento em arquivos, propiciam a
gravação dos dados de forma permanente, possibilitando a recuperação destes
dados toda vez que se fizer necessário tratá-los nos programas.
PROGRAMAÇÃO DE REGISTROS NA LINGUAGEM C
Vamos agora aprofundar nossos conhecimentos de registros e arquivos, dando
ênfase na programação destes recursos na linguagem de programação C.
Os registros são declarados como sendo uma estrutura na linguagem C, por
meio do comando struct, sendo uma coleção de um ou mais variáveis,
possivelmente de tipos diferentes, agrupadas sob um único nome.
Exemplo de uma declaração de registro:
struct data
{
int dia;
int mes;
int ano;
};
Onde:
• a palavra-chave struct informa ao compilador que um modelo de estrutura
está sendo definido;
• “data” é uma etiqueta que dá nome à definição da estrutura;
• os nomes dia, mes e ano declarados entre as chaves são as variáveis da
estrutura;
• uma definição de estrutura é um comando, por isso deve terminar com ponto-
e-vírgula.
As variáveis de uma mesma estrutura devem ter nomes diferentes, porém,
estruturas diferentes podem conter campos com o mesmo nome.
A definição de uma estrutura não reserva qualquer espaço na memória. No
exemplo dado, nenhuma variável foi declarada de fato, apenas a forma dos
dados foi definida. Essa definição, porém, cria um tipo de dados, que pode ser
usado para declarar variáveis.
Temos 2 formas de declarar uma variável x como sendo do tipo data:
struct data
{
int dia;
int mes;
int ano;
};
...
data x;
Nesta forma, definimos a estrutura e declaramos a variável x do novo tipo
definido em um único comando.
Os campos de uma estrutura podem ser de qualquer tipo, inclusive uma
estrutura previamente definida e a declaração do formato de uma estrutura
pode ser feita dentro da função principal (main) ou fora dela.
Vamos agora estudar um programa em C em que declaramos uma estrutura
Reg_Produto, com variáveis de tipos diferentes, que representam um registro
para um produto, conforme mostrado anteriormente, nas Figuras 1 e 2 deste
material.
1 #include <stdio.h>
2 main ()
3 {
4 struct Reg_Produto {
5 char codigo[10];
6 char descricao[30];
7 char unidade[5];
8 float preco;
9 };
10 Reg_Produto Prod;
11 printf(\"Digite o codigo:\");
12 scanf(\"%s\", &Prod.codigo);
13 printf(\"Digite a descricao:\");
14 scanf(\"%s\",&Prod.descricao);
15 printf(\"Digite a unidade:\");
16 scanf(\"%s\", &Prod.unidade);
17 printf(\"Digite o preco:\");
18 scanf(\"%.2f\",&Prod.preco);
19 }
Na linha 4 deste programa, declaramos a estrutura que chamamos de
Reg_Produto, contendo as variáveis código, descrição, unidade e preco,
declaradas nas linhas 5, 6, 7 e 8.
Na linha 10, declaramos a variável Prod, como sendo do tipo da estrutura
Reg_Produto, com isto, teremos dentro da variável Prod, os
campos codigo, descricao, unidade e preco.
Na linha 12, estamos lendo um valor do teclado e inserindo este valor na
variável código que está dentro da variável Prod. Veja então que este comando
de leitura tem o nome da variável associada à estrutura e depois o nome da
variável código, separados por um ponto (.). Esta é a forma de acessar
individualmente os campos de uma determinada estrutura como se fossem
variáveis comuns.
Nas linhas 14, 16 e 18, estamos lendo os valores para as
variáveis Prod.descricao, Prod.unidade e Prod.preco.
PROGRAMAÇÃO DEARQUIVOS NA LINGUAGEM C
Agora vamos complementar os nossos estudos com a codificação para
manipular os arquivos na linguagem de programação C.
Para tratar arquivos, a linguagem C fornece um nível de abstração entre o
programa e o dispositivo a ser usado. Esta abstração é chamada fila de bytes e
o dispositivo normalmente é o arquivo.
A biblioteca <stdio.h> tem um identificador FILE, que é uma estrutura que
define vários aspectos do arquivo, como nome, status, posição corrente no
arquivo, além de ter uma fila associada.
Para manipular o arquivo será necessário então criar no programa
este ponteiro, associado a esta estrutura FILE.
Exemplo: FILE *arq;
Onde arq será o ponteiro para um arquivo. É usando este tipo de ponteiro que
vamos poder manipular os arquivos na linguagem C.
Abertura de arquivos
Toda vez que for necessário trabalhar com arquivo, primeiramente precisamos
ABRIR o arquivo. Abrir o arquivo significa alocar o periférico em que o arquivo
se encontra e deixá-lo disponível para leitura/gravação.
Exemplo: arq = fopen(nome_arquivo, “modo”);
Onde arq é o ponteiro para o arquivo e modo é a forma como arquivo será
acessado, podendo ser das seguintes formas:
• w: para escrita (cria novo arquivo ou sobrepõe se arquivo já existir);
• r: para leitura (arquivo deve existir);
• a: para escrita no final do arquivo, e se não existir cria novo arquivo;
• w+: para leitura e gravação (cria novo arquivo ou sobrepõe se já existir);
• r+: para leitura e gravação (arquivo deve existir);
• a+: para leitura ou escrita no fim do arquivo, e se não existir cria novo arquivo;
• b: modo binário;
• t: modo texto.
Fechamento de arquivos
Da mesma maneira que precisamos abrir um arquivo antes do processamento,
também se faz necessário o fechamento dele, para que suas informações não
possam ser violadas ou danificadas. Fechar um arquivo significa liberar o
periférico que estava sendo utilizado.
Exemplo: fclose(arq);
Onde arq é o ponteiro para o arquivo.
Leitura de arquivos
Após abrir um arquivo é necessário LER os dados que estão em disco e
transferi-los para memória. Essa transferência é feita por registro. Esse
procedimento é gerenciado pelo próprio sistema operacional.
Exemplo: fscanf (arq, "%s", string);
Onde arq é o ponteiro para o arquivo e string é a variável que receberá a linha
apontada pelo ponteiro dentro do arquivo.
Gravação de arquivos
Da mesma maneira que os registros são lidos de um arquivo, também devemos
gravar registros em um arquivo. A gravação consiste na transferência de um
registro da memória, para um periférico.
Exemplo: fprintf (arq, "%s", string);
Toda vez que abrimos um arquivo ele posiciona o ponteiro no primeiro registro,
ou seja, no início do arquivo. Para que possamos trabalhar com os dados se
torna necessário saber onde está o ponteiro do registro. Isso poderemos fazer
testando se o ponteiro está no início (BOF – Bottom Of File) ou no final do
arquivo (EOF – End Of File). Esse é sempre executado após a leitura do
registro (mudança da posição do ponteiro). Simbolicamente podemos
representar esse passo da seguinte maneira:
Figura 3 | Representação dos registros em arquivos
Fonte: elaborada pelo autor.
Movimentação de registros
Quando um arquivo é aberto, o ponteiro está apontando para o primeiro registro
do arquivo. A cada leitura do arquivo o ponteiro se movimenta para o próximo
registro e assim por diante.
Exemplo de trecho do programa para fazer esta movimentação no arquivo:
1 while (feof(arq)==0) {
2 fscanf(arq, \"%s\", string);
3 printf(\"%s %d\n\",string,num);
4 }
Este trecho do programa está lendo todos os registros de um arquivo, em que a
função feof(arq) retorna 1 quando o ponteiro arq está apontando para o último
registro do arquivo, senão retorna 0.
Agora vamos analisar um programa que abre o arquivo exemplo.txt, lê e exibe
em tela todos os registros deste arquivo.
1 #include <stdio.h>
2 #include <stdlib.h>
3 main ()
4 {
5 FILE *arq;
6 char texto[256];
7 arq =fopen (\"exemplo.txt\",\"rt\");
8 if (arq == NULL)
9 {
10 printf (\"Erro na abertura do arquivo. Fim de
programa.\");
11 exit (1)
12 }
13 fscanf(arq,\"%s\", texto); /* Lê a primeira linha */
14 while(!feof(arq))
15 {
16 printf(\" %s\",texto); /* Exibe a linha na tela */
17 fscanf(arq,\"%s\", texto); /* Lê a \"próxima\" linha */
18 }
19 fclose(arq);
20 }
Na linha 5 deste programa, está sendo criado um ponteiro chamado *arq que é
usado para navegar no arquivo exemplo.txt, que está sendo aberto na linha 7
deste programa. Na linha 13 do programa, está sendo lida a 1ª linha do arquivo.
Na linha 14 tem-se uma estrutura de repetição, em que é testado se o ponteiro
do arquivo *arq chegou na última linha do arquivo. Enquanto a condição for
verdadeira, ou seja, não chegou na última linha, o programa mostra a linha e lê
a próxima linha.
VÍDEO RESUMO
Crie o seu programa de registros e arquivos, usando o site Paiza.io em que
você poderá codificar, compilar e rodar deforma on-line.
Saiba mais
A manipulação de caracteres e inteiros pode ocasionar dificuldades na
legibilidade do código, principalmente pelas conversões implícitas que a
linguagem C permite na execução dos programas. Para essas construções
específicas, Luís Damas organizou uma subseção em sua obra, com alguns
exemplos detalhadamente descritos.
O livro Linguagem C está na nossa biblioteca virtual, e o capítulo que aborda
esse assunto está na subseção Situações em que inteiros e caracteres não se
devem misturar, na página 43.
REFERÊNCIAS
Aula 1
FARRER, H. et al. Algoritmos estruturados. Rio de Janeiro: LTC Editora,
1999.
https://integrada.minhabiblioteca.com.br/reader/books/9788521632474
https://paiza.io/projects/eLk7pkGinhQcwFgf0UDv4g?language=c
MIZRAHI, V. V. Treinamento em Linguagem C: módulo 1 e 2. São Paulo:
Pearson Prentice Hall, 2007.
Aula 2
FARRER, H. et al. Algoritmos estruturados. Rio de Janeiro: LTC Editora,
1999.
MIZRAHI, V. V. Treinamento em linguagem C: módulo 1 e 2. São Paulo:
Pearson Prentice Hall, 2007.
Aula 3
FARRER, Harry; BECKER, Christiano; FARIA, Eduardo; MATOS, Helton;
Santos, Marcos Augusto; MAIA, Miriam L.. Algoritmos Estruturados. Rio de
Janeiro: LTC Editora, 1999.
KERNIGHAN, Brian W. e RITCH, Dennis M., C: A Linguagem de Programação,
Rio de Janeiro, Campus, 1986.
MIZRAHI, Victorine Viviane. Treinamento em Linguagem C: módulo 1 e 2. São
Paulo: Pearson Prentice Hall, 2007; ISBN 9788576051350.
Aula 4
FARRER, H. et al. Algoritmos estruturados. Rio de Janeiro: LTC Editora,
1999.
<Revisão e prática
Lógica de programação
<PARTE 01>
Revisão da unidade
//INTRODUÇÃO
Olá, estudante! Nesta unidade, você conheceu os conceitos que lhe orientarão no
restante de sua aprendizagem sobre lógica de programação e por isso têm grande
importância neste primeiro momento. Vamos revê-los!
//EXECUÇÃO DE PROGRAMAS
A programação de computadores é fundamentada na noção de criar comandos e
instruções para serem executados pelo computador em uma determinada ordem para
resolver certo problema. Nesse sentido, você pode pensar no seu celular (que também é
um computador) e quantos programas diferentes estão em execução quando ele está
ligado.
O sistema operacional, por exemplo, é um conjunto de programas que são executados
com o objetivo de gerenciar a manipulação do hardware por você. Além disso, toda vez
que um aplicativo é aberto, outros programas com centenas e milhares de comandos são
postos em execução.
//LÓGICA DE PROGRAMAÇÃO
Diante do exposto, é possível notar o grau de complexidade que exige a perfeita
execução de programas simultaneamente de modo que a operação seja harmônica.
Precisa-se ordenar e gerenciar as instruções seguindo determinadas lógicas.
É neste momento que o papel da lógica se faz presente. Afinal, as instruções devem estar
postas em uma sequência que faça sentido, o que demanda uma estrutura logicamenteorganizada. Para isso, é importante ter em mente que os princípios da lógica
proposicional são utilizados na programação.
//ALGORITMO
A apreensão dos conceitos da lógica é fundamental para que o elemento central da
programação seja dominado: o algoritmo. Um algoritmo é o elemento central para a
construção de programas eficientes. Trata-se da lógica de programação aplicada para
resolução de um dado problema, ou seja, são as instruções e os comandos em uma
determinada ordem.
+ INFO> Uma analogia interessante para compreender o conceito de algoritmo é pensar
em uma receita de bolo. Uma receita deve seguir passos bem definidos e especificados
para atingir o resultado esperado, e caso uma das etapas não seja seguida, a chance de
resultar em erro aumenta. Neste sentido, um algoritmo é uma sequência de passos que
também devem ser seguidos corretamente pelo computador.
//REPRESENTAÇÃO DOS ALGORITMOS
Existem várias maneiras para representar algoritmos sendo que, no início da
aprendizagem, é interessante se adaptar e utilizar:
1- DESCRIÇÃO NARRATIVA
Como uma receita, é a descrição dos passos em língua portuguesa. Não são
especificados detalhes das variáveis e outras estruturas, mas fica clara qual a estratégia
utilizada.
2- PSEUDOCÓDIGO
Também em linguagem natural, pode especificar maiores detalhes, como os nomes e
tipos das variáveis, além de utilizar uma sintaxe própria.
//CONCLUSÃO
Com esses conceitos iniciais, sua jornada pela programação pode ser iniciada e
esperamos que o aprofundamento destes conceitos somado às resoluções dos exercícios
sirvam como uma base sólida de sua aprendizagem.
RESUMO
A IMPORÂNCIA DA PROGRAMAÇÃO
• Mercado de TI aquecido
• Penetração em outras áreas
• Resolver problemas
• Profissional com curiosidade
OS ELEMENTOS E A LÓGICA DA PROGRAMAÇÃO
• Pensamento lógico
• Organização do pensamento
• Sequencia de passos
• Variáveis e dados
• Entrada processada
• Resulta em saída
ALGORÍTIMOS E OPERADORES
• Operadores aritmetricos (+, - , *, /)
• Operadores lógicos (&&, II)
• Operadores racionais (<, >, = =, ! =)
• Manipulação para construir algoritmos eficientes
AS REPRESENTAÇÕES INICIAIS
1- DESCRIÇÃO NARRATIVA
• Como uma receita de bolo
• Explicar em linhas gerais o algorítmo
• Sem muitos detalhes de implementação
2- PSEUDOCÓDIGO
• Algum grau de formalização
• Descrição geal do algorítmo
• Iniciação à síntese
<PARTE 02>
Estudo de caso
//APRESENTAÇÃO
Um dos grandes problemas da computação é encontrar o melhor caminho a ser seguido
para algum caso específico. Por exemplo: qual é o melhor caminho que um caminhão
deve percorrer para chegar mais rápido ao destino, considerando as melhores ruas,
menos trânsito, entre outros aspectos. Questões deste tipo, muito importantes e atuais,
demandam muito estudo e podem garantir um custo reduzido para empresas de entrega,
por exemplo.
Para contextualizar sua aprendizagem desta unidade, observe o cenário proposto:
imagine que você foi contratado por uma empresa de logística para projetar a solução que
encontre a melhor rota de entrega de mercadorias e alimentos. São 3 rotas disponíveis:
A rota A, pela estrada.
A rota B, por uma ferrovia.
A rota C, por uma hidrovia.
Para cada viagem, há o ponto de partida, um ponto de abastecimento e um ponto de
chegada. Além disso, são fornecidos os dados de distância entre os pontos para cada tipo
de rota e a velocidade média de cada trecho para cada rota. Por exemplo: a rota B terá
uma distância entre o ponto inicial até o ponto de abastecimento, em que a velocidade
média possui determinado valor, e outra distância entre o ponto de abastecimento e o
ponto de destino, que pode possuir outra velocidade média. A questão é que:
• Para cada nova entrega, os dados podem variar, pois o comprimento das rotas
pode sofrer variações, assim como a velocidade de transporte.
• O tempo final deve ser calculado com base nos dados fornecidos.
//DESAFIO
Desse modo, projete um algoritmo que, recebendo como entrada os dados informados,
deve oferecer como resultado a rota mais rápida entre A, B ou C para uma certa entrega
considerando o menor tempo. Assim, escreva, em formato de descrição narrativa, um
algoritmo capaz de resolver o problema.
Reflita
A programação de computadores está presente em todos os ambientes no mercado de
trabalho atualmente. Seja para otimizar os gastos, reduzir custos, salvar vidas, garantir o
entretenimento, entre outras. Um dos fatores que aparece cada vez mais é a dimensão
ética da computação. Afinal, cada vez mais a programação busca automatizar tarefas que
são realizadas por seres humanos e que, por muitas vezes, acabam extinguindo postos
de trabalho, podendo ocasionar em maiores taxas de desemprego. Um dos casos é o
abordado neste estudo de caso, em que tarefas de engenheiros e gerentes de logística
são executados por algoritmos e máquinas com elevado processamento.
É interessante refletir quanto o mercado de trabalho está sendo alterado com a
tecnologia, novas vagas surgem enquanto outros postos de trabalho tradicionais são
substituídos pelos computadores. A sociedade como um todo precisa estar ciente destas
transições e se preparar para vivenciá-las.
//RESOLUÇÃO
No problema apresentado, você foi contratado por uma empresa para criar um programa
que responda qual a melhor rota (com o menor tempo de trajeto) a se tomar dadas:
• A distância do ponto de partida até o ponto de abastecimento.
• A distância do ponto de abastecimento até o destino.
• A velocidade média entre os pontos de início, abastecimento e destino.
É preciso salientar que podem existir soluções diferentes da apresentada a seguir que
também resolvem o problema e poderiam ser utilizadas em situações reais. Contudo, o
foco da solução deve ser o cálculo do menor tempo resultante.
Assim, a nossa proposta de algoritmo é a seguinte:
1. Ler os dados de cada rota;
2. Para cada rota:
3. calcular o tempo gasto do ponto inicial ao ponto de abastecimento;
4. calcular o tempo gasto do ponto de abastecimento ao destino;
5. somar os tempos;
6. salvar o tempo total calculado.
7. Após calcular o tempo total de cada rota:
8. comparar a rota A com a rota B e salvar a que tiver o menor tempo;
9. comparar a com menor tempo calculado com a rota C e salvar a menor;
10. Imprimir na tela a rota com menor tempo.
OBS.:
• Dessa maneira, independentemente da fórmula utilizada para o cálculo do tempo
nas linhas 3 e 4 (que pode utilizar a distância e a velocidade média), o nosso
algoritmo sempre irá realizar o cálculo para cada uma das rotas e comparar todas
com todas. Dessa maneira, ao final, é possível garantir que a rota com menor
tempo foi calculada. Observe que, como utilizamos a técnica de descrição
narrativa, alguns detalhes não foram explicitados, como a própria fórmula de
cálculo. Isso se deve ao fato de essa ser uma primeira aproximação ao problema,
que nos permite pensar a solução sem perder tempo em alguns detalhes. Um
próximo passo seria descrever utilizando pseudocódigo, o que deixaria mais claro
quais estruturas e fórmulas seriam utilizadas.
//CONCLUSÃO
Assim, ficou demonstrado que o primeiro passo é representar a solução de modo ainda
incipiente, o que já permite a toda a equipe envolvida no projeto ter uma noção mais
ampla do tipo do problema e das estratégias de resolução.
<PARTE 03>
Síntese conceitual
Relembre os principais tópicos estudados ao longo das leituras e vídeos desta unidade!
LÓGICA DE PROGRAMAÇÃO
PROGRAMAS LÓGICA PROPOSICIONAL ALGORITMOS
• Variáveis • Conjunção Representação inicial:
• Operadores • Disjunção • Descrição narrativa
• Negação • Pseudocódigo
• Condicional
<PARTE 04>
Encerramento
Com o conteúdo exposto esperamos que você saiba utilizar as representações
algorítmicaspara a utilização da lógica de programação. Incentivamos que você busque
mais conhecimentos sobre esse tema.
Referências
DASGUPTA, S.; PAPADIMITRIOU, C.; VAZIRANI, U. Algoritmos. Porto Alegre: AMGH
Editora, 2009.
ZIVIANI, N. et al. Projeto de algoritmos: com implementações em Pascal e C. Luton:
Thomson, 2004.
UNIDADE 2
Elementos de algoritmos
<PARTE 01>
//ALGORITMO
Um algoritmo é definido como uma sequência lógica de passos para que uma tarefa seja
realizada, de forma automatizada, ou seja, que você possa repetir a mesma tarefa,
seguindo a mesma sequência de passos e chegando ao mesmo resultado.
//ALGORITMO
• Sequência lógica de passos
• Situações que podem ser automatizadas
• Repetição gera o mesmo resultado
Em seu cotidiano, você se depara com atividades que são feitas, mesmo que de forma
inconsciente, por meio de passos sequenciais repetitivos, de modo a se obter um padrão
de comportamento para a realização destas atividades. Como exemplo, podemos citar as
receitas culinárias, que têm uma lista de ingredientes, organizados previamente ao
preparo do prato, e uma sequência de passos que, se repetidos, irão atingir o mesmo
objetivo. Para estas tarefas, que podem seguir um padrão e ter os mesmos passos
repetidos inúmeras vezes, com o mesmo resultado atingido, podemos elaborar um
algoritmo.
//ESTRUTURAS CONDICIONAIS
Para muitas situações que podem gerar lógicas sequenciais, é comum que surjam
elementos condicionais que, a partir do teste em uma condição, possam seguir um
caminho ou outro. Nesse caso, temos a: Condicional simples ( se - então – senão)
Condicional complexa ( escolha – caso – caso contrário).
Condicional simples
Para lógicas simples, ou seja, aquelas em que você irá testar uma condição apenas, é
possível utilizar o laço se – então – senão. Como exemplo, temos a declaração: “Se não
chover hoje, então vou à praia, senão vou ler um livro”, que terá um teste a ser validado
ou não (não chover hoje).
Condicional complexa
Caso você se depare com uma situação na qual uma variável poderá assumir uma faixa
de valores pré-conhecidos, então, a melhor opção é utilizar o comando condicional
complexo escolha. Neste caso, o laço irá escolher qual fluxo deverá ser seguido, a
depender do valor que a variável testada irá assumir. Além dos valores possíveis, existe a
possibilidade de seguir um fluxo alternativo, conhecido como caso contrário ou fluxo
padrão.
//ESTRUTURAS CONDICIONAIS
Condicional simples Condicional complexa
• se - então – senão • escolha – caso – caso contrário
//ESTRUTURAS DE REPETIÇÃO
Além dos laços condicionais, também é possível utilizar laços de repetição para
construção da sua lógica algorítmica. Com estes laços, você será capaz de repetir um
trecho de comandos até que uma condição de parada seja satisfeita e as repetições
cessadas. Para cada laço, o momento no qual o teste da condição de parada acontece é
diferente, conforme o comportamento do laço.
A seguir, saiba quais são os laços de repetição possíveis:
Enquanto - Faça
Caso o intuito seja testar a condição de parada e, a depender da resposta, executar as
instruções, você deverá utilizar o laço enquanto – faça.
Repita – Até
Caso seja necessário realizar, ao menos uma vez, o laço de repetição, dê preferência
para o laço repita – até.
Para – Até – faça
Se a quantidade de repetições já for conhecida antes da criação do laço e a repetição for
feita de forma incremental, então você deverá utilizar o para – até – faça.
//ESTRUTURAS DE REPETIÇÃO
Enquanto - Faça Repita – Até Para – Até – faça
• Teste primeiro,
execução depois
• Execução primeiro,
teste depois
• Execução auto
controlada, teste
primeiro
//FLUXOGRAMAS
Podem ser utilizados para representar uma lógica sequencial de um algoritmo, por meio
da utilização de elementos gráficos. Qualquer pessoa, ao ler um fluxograma, deverá
compreender, com exatidão, qual a sequência de comandos a ser seguida e quais
mudanças de fluxo que deverão acontecer, em caso de elementos condicionais. A partir
da combinação de setas e elementos condicionais, é possível criar estruturas de
repetição.
A seguir, confira quais são os principais símbolos para elaboração de fluxogramas
//ESTRUTURAS DE ARMAZENAMENTO
Além de variáveis simples, você poderá utilizar estruturas mais complexas, como os
vetores, matrizes e registros. Entenda: Vetores e matrizes (estruturas homogêneas);
Registros (estruturas heterogêneas).
VETORES E MATRIZES
Vetores e matrizes são estruturas homogêneas, ou seja, armazenam informações de um
único tipo.
REGISTROS
Registros são estruturas heterogêneas, ou seja, podem armazenar informações de tipos
diferentes, mas que estejam relacionados a um mesmo conceito (como características de
uma pessoa).
UNIDADE 3
Conceitos de programação
<PARTE 01>
//INTRODUÇÃO
Olá, estudante! Na unidade Conceitos de programação, tivemos a oportunidade de
conhecer muitos comandos e, assim, construir os programas na linguagem C.
A seguir, vamos rever os principais pontos estudados!
//DESCRIÇÃO NARRATIVA VERSUS CÓDIGOS
Os comandos possuem uma construção um pouco mais complexa do que a construção
em pseudocódigo, por exemplo, sendo consequentemente bem mais detalhada que a
descrição narrativa. Entenda a diferença a seguir:
1- DESCRIÇÃO NARRATIVA E PSEUDOCÓDIGO
• Representam logicamente o propósito do algoritmo, com flexibilidade na escrita,
pois normalmente são feitos para pessoas os interpretarem.
2- CÓDIGOS ESCRITOS EM LINGUAGENS DE PROGRAMAÇÃO
• São produzidos com a finalidade de serem interpretados e/ou compilados por
máquinas.
//COMPILADOR
Tudo o que compõe o código escrito pelo programador é transformado pelo compilador
em um comando equivalente em linguagem de máquina, e nessa transformação não pode
haver ambiguidade ou erros. Por isso, o compilador também se antecipa em apontar erros
na construção do programa, que podem ou não impedir sua execução. Um software que
agrega o editor especializado de código e o compilador é o IDE (Integrated Development
Environment).
É importante saber que os compiladores verificam: Dados a serem manipulados pelo
programa; Comandos inseridos no programa
Dados a serem manipulados pelo programa
Algumas das verificações que o compilador realiza são em relação aos dados que o
programa manipulará, pois como variáveis ou constantes, seus identificadores e tipos
escolhidos devem ter comportamento coerente em todo o código. Por exemplo, se houver
algum identificador no código que não seja uma palavra reservada da linguagem nem
uma variável declarada pelo programador, o compilador apresentará um erro referente a
esse termo desconhecido.
Comandos inseridos no programa
Com o objetivo de construir adequadamente o código de máquina, os compiladores
também verificam os comandos que foram inseridos no programa, tais como comandos
de entrada e saída, operadores de atribuição, aritméticos e lógicos, além dos outros
termos que interagem com os comandos, como as variáveis, as constantes e os valores
inseridos diretamente no código.
//LINGUAGEM C
Nas aulas, estudamos os operadores existentes na linguagem C e como devem ser
construídos para cada caso de interesse.
Alguns dos comandos bem importantes na linguagem C são as estruturas condicionais e
de repetição, sendo que ambas são recursos que o programador possui para controlar os
caminhos que o programa pode tomar e que diferem da execução sequencial, linha após
linha.
Todos esses recursos são importantes para a construção de programas versáteis!
//LINGUAGEM C (Editor de código , Compilador)
UNIDADE 4
Aplicações de programação
<PARTE 01>
//ESTRUTURAS
Nesta unidade, estudamos formas de manusear dados por meio de estruturas que
permitem a manipulação de conjuntos de dados de mesmo tipo primitivo (inteiro, real,
caractere) e tipos primitivos diferentes.
Estas estruturas propiciama solução de algoritmos com lógicas complexas, enriquecendo
a implementação com recursos computacionais que facilitam a manipulação de dados
com maior qualidade e performance.
//DADOS BÁSICOS E COMPOSTOS
Vimos que existem os seguintes tipos de dados básicos:
Numéricos
(inteiros e reais)
Lógicos Caracteres
Baseando-se nestes tipos básicos podemos construir os tipos compostos de dados, que
são divididos em: Homogêneos (vetores e matrizes) e Heterogêneos (registros).
1- Homogêneos (vetores e matrizes)
Os tipos homogêneos são conjuntos do mesmo tipo primitivo de dados, os quais
podem ter uma única dimensão (vetor), na qual os dados de estrutura são inseridos
em uma única linha, ou ter mais de uma dimensão (matriz), em que os dados são
inseridos em mais de uma linha.
2- Heterogêneos (registros)
O tipo heterogêneo (registro) é formado por um conjunto de dados de tipos
diferentes, que são logicamente organizados. Este tipo facilita o agrupamento de
variáveis que têm uma estreita relação lógica entre eles.
Estes registros podem ser armazenados em arquivos e salvos em um dispositivo
secundário, como o disco HD. O conhecimento das possibilidades de organização
dos registros em arquivos permite ao programador escolher a forma mais
adequada para solucionar problemas em termos de eficiência e eficácia.
//FUNÇÃO
Foi apresentada também nesta unidade uma forma de resolver problemas na
programação por meio da divisão em subproblemas independentes, de forma simples e
elegante, usando o recurso de função, que cria um encapsulamento de uma lógica
interna, expondo como se fosse um serviço, no qual um bloco de comandos é executado,
recebendo alguns parâmetros de entrada e retornando um resultado como saída da
função.
• Vimos que usar funções na programação evita repetição de linhas de código, no
qual codificamos os comandos de uma função uma única vez e podemos utilizá-lo
diversas vezes, ao invés de escrever o mesmo código várias vezes.
• Um ponto importante no uso de funções é que elas podem ser usadas de forma
recursiva, ou seja, a função chama a si mesma.
//FUNÇÕES PREDEFINIDAS
Vimos também que podemos usar funções predefinidas, que são organizadas em
bibliotecas codificadas especificamente para cada linguagem de programação, como por
exemplo: biblioteca para funções matemáticas e biblioteca com funções para manipulação
de caracteres (strings).
<PARTE 02>
Estudo de caso
//APRESENTAÇÃO
Para contextualizar sua aprendizagem desta unidade, imagine que você trabalha para
uma empresa de construção civil e você será o engenheiro responsável pelo orçamento
da construção de um prédio. Você será responsável pela gestão dos custos da obra,
deverá fazer o controle dos gastos com os materiais básicos, equipamentos, mão de obra
operacional e de terceiros prestados e considerar um memorial descritivo de obra, que
traz os detalhes de tudo o que foi executado.
A obra será executada em várias etapas e os gastos da construção serão atualizados na
medida em que cada apartamento for finalizado.
O prédio terá 6 andares e cada andar terá 4 apartamentos, conforme a figura:
• Considere que os custos são variáveis para cada apartamento, devido a fatores
como o tempo da construção, a variação dos preços dos materiais e da mão de
obra.
• Note que a melhor lógica para o desenvolvimento do controle de custos é
considerar o uso de uma matriz. Nesta matriz, deve ser considerado cada andar
como uma linha e cada tipo de apartamento como uma coluna da matriz.
• Para o registro dos gastos de cada apartamento, a melhor alternativa,
considerando os recursos estudados nesta unidade, é implementar a declaração
de um registro (comando struct da linguagem C), que deverá manipular as
variáveis que serão tratadas para cada apartamento: número do apartamento,
custo dos materiais básicos, custo dos equipamentos, custo da mão de obra e
memorial descritivo.
Veja que você terá que construir um programa em C para ler estas variáveis, que serão
informadas no final da construção de cada apartamento.
Como serão informados os dados na finalização de cada apartamento, deverão sempre
ser informados o andar e o tipo do apartamento para depois serem informados os valores
das variáveis tratadas no programa.
Após a inclusão dos valores, vamos somar e mostrar o valor total gasto no apartamento.
Observação
• Para desenvolver o programa solicitado, você poderá usar os recursos de matrizes
e de registros, da programação estruturada.
• O uso destes recursos no programa propiciará uma melhor organização no
tratamento e manipulação dos dados, para fazer a gestão dos custos da obra e na
qualidade do código do programa em função de se ter um grande conjunto de
variáveis a serem tratadas pelo programa.
• Veja como o registro se encaixa perfeitamente na solução deste caso de uso, pelo
motivo de estarmos tratando um conjunto de dados que estão logicamente
relacionados, de tipos diferentes e que podemos tratá-los como um agrupamento
de variáveis que têm uma estreita relação lógica entre si.
//RESOLUÇÃO
O código do programa solicitado é composto por 32 linhas. A seguir, iremos apresentá-lo e
comentar algumas delas. Confira a explicação e aproveite para comparar a resolução
proposta com a solução a que você chegou!
LINHAS DE 1 A 11
Na linha 5 do programa, declaramos a estrutura que chamamos de CustosObra
contendo as variáveis:
• nro_apto
• materiais_basicos
• equipamentos
• mao_obra
• memorial
LINHAS DE 1 A 11 LINHAS DE 12 A 19
1 #include <stdio.h> 12
2 #include <string.h> 13 CustosObra Vcusto[7][4];
3 main () 14 int andar, tipo;
4 { 15 float custo_total;
5 struct CustosObra { 16 printf ("Digite o andar (de 0 a 6):");
6 int nro_apto; 17 scanf("%d",&andar);
7 float materiais_basicos; 18 printf ("Digite o tipo do apartamento (de
0 a 3):");
8 float equipamentos; 19 scanf("%d",&tipo);
9 float mao_obra;
10 char memorial[200];
11 };
LINHAS DE 12 A 19
• Na linha 13, declaramos o vetor Vcusto, como sendo do tipo de dados da estrutura
,CustosObra, com isto, teremos dentro de cada elemento deste vetor de 7 linhas e
4 colunas, os campos nro_apto, equipamentos materiais_basicos, mao_obra e
memorial.
• Na linha 17 e 19, estamos lendo os valores que definirão o andar e o apartamento
em que serão inseridos os valores referentes aos custos a serem lançados.
LINHAS DE 20 A 29
• Da linha 20 a 29 do programa, está sendo solicitada a entrada dos valores da obra.
• Veja que os comandos de leitura têm o nome da variável associada à estrutura e
depois o nome da variável código separados por um ponto (.). Esta é a forma de
acessar individualmente os campos de uma determinada estrutura como se fossem
variáveis comuns.
LINHAS DE 20 A 29
20 printf ("Digite o numero do apartamento:");
21 scanf("%d",&Vcusto[andar][tipo].nro_apto);
22 printf ("Digite o custo com materiais basicos:");
23 scanf("%f",&Vcusto[andar][tipo].materiais_basicos);
24 printf ("Digite o custo com equipamentos:");
25 scanf("%f",&Vcusto[andar][tipo].equipamentos);
26 printf ("Digite o custo com mao de obra:");
27 scanf("%f",&Vcusto[andar][tipo].mao_obra);
28 printf ("Digite o memorial descritivo:");
29 scanf("%s",&Vcusto[andar][tipo].memorial);
LINHAS DE 30 A 32
Na linha 30 está sendo calculado o custo total do apartamento e na linha 31 está sendo
mostrado este valor.
30 custo_total = Vcusto[andar][tipo].materiais_basicos + Vcusto[andar]
[tipo].equipamentos + Vcusto[andar][tipo].mao_obra;
31 printf ("\nValor total gasto no apartamento: %.2f",custo_total);
32 }
<PARTE 03>
Síntese conceitual
//APLICAÇÕES DE ALGORITMOS
A seguir, relembre os principais conceitos estudados ao longo desta unidade: Estruturas
de dados, Matriz, Funções, Registro, Arquivos, Vetor
//APLICAÇÕES DE ALGORITMOS
Estruturas de
dados
Estruturas de dados: enriquecem os programascom recursos
computacionais que facilitam a manipulação de dados com maior
qualidade e performance.
Matriz Matriz: tipo de dado composto homogêneo bidimensional.
Funções Funções: são uma forma de resolver problemas na programação
dividindo-os em subproblemas independentes, de modo simples e
elegante.
Registro Registro: tipo de dado composto heterogêneo.
Arquivos Arquivos: possibilitam o armazenamento dos dados em
dispositivos secundários
Vetor Vetor: tipo de dado composto homogêneo unidimensional.
<PARTE 04>
Encerramento
Encerramento
Com o conteúdo exposto esperamos que você seja capaz de desenvolver estruturas
compostas homogêneas e heterogêneas na linguagem de programação C. Incentivamos
que você busque mais conhecimentos sobre esse tema!
Referências
FARRER, H. et al. Algoritmos estruturados. Rio de Janeiro: LTC Editora, 1999.
KERNIGHAN, B. W. e RITCH, D. M.. C: A Linguagem de programação. Rio de Janeiro:
Campus, 1986.
MIZRAHI, V. V. Treinamento em linguagem C: módulo 1 e 2. São Paulo: Pearson Prentice
Hall, 2007.
INTRODUÇÃO
O que é algoritmo
Reflita
Variáveis, tipos e operadores
Modo de preparo:
Observação
Saiba mais
INTRODUÇÃO
INTRODUÇÃO À LÓGICA
ELEMENTOS DA LÓGICA PROPOSICIONAL
Negação
Conjunção
Disjunção
Condicional e bicondicional
A TABELA VERDADE E ALGUNS EXEMPLOS
Tabela verdade
Saiba mais
INTRODUÇÃO
OS ALGORITMOS NA PROGRAMAÇÃO
O USO DE OPERADORES E VARIÁVEIS
Operadores aritméticos
1. Adição
2. Subtração
3. Divisão
4. Multiplicação
Operadores relacionais
1. Igualdade
2. Diferença
3. Maior e menor
Operadores lógicos
Variáveis e constantes
EXEMPLOS DE ALGORITMOS COMPLETOS
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
CONSTRUÇÃO DE ALGORITMOS
Descrição narrativa
Pseudocódigo
Saiba mais
Aula 1
INTRODUÇÃO
O QUE SÃO ALGORITMOS E QUAIS SUAS APLICABILIDADES
PRINCIPAIS CARACTERÍSTICAS DE UM ALGORITMO
UTILIZANDO FLUXOGRAMAS PARA A REPRESENTAÇÃO DE ALGORITMOS
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
ESTRUTURAS SEQUENCIAIS E CONDICIONAIS DE UM ALGORITMO
COMO E QUANDO UTILIZAR CADA TIPO DE ESTRUTURA EM UM ALGORITMO
UTILIZANDO ESTRUTURAS SEQUENCIAIS NA CRIAÇÃO DE UM ALGORITMO
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
O QUE SÃO ESTRUTURAS DE REPETIÇÃO E COMO UTILIZÁ-LAS
COMPREENDENDO AS SITUAÇÕES-PROBLEMA MAIS ADEQUADAS PARA CADA TIPO DE ESTRUTURA DE REPETIÇÃO
APLICANDO ESTRUTURAS DE REPETIÇÃO EM ALGORITMOS
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
O QUE SÃO VETORES, MATRIZES E REGISTROS
COMO APLICAR VARIÁVEIS INDEXADAS EM ALGORITMOS
EXEMPLOS DE UTILIZAÇÃO DAS ESTRUTURAS INDEXADAS
VÍDEO RESUMO
Saiba mais
Aula 1
Aula 2
Aula 3
Aula 4
INTRODUÇÃO
CONCEITOS BÁSICOS DE LINGUAGEM DE PROGRAMAÇÃO
COMPILADORES E INTERPRETADORES
AMBIENTE DE PROGRAMAÇÃO
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
CONSTRUINDO UM PROGRAMA EM C
PROGRAMAS PARA MANIPULAR DADOS
CONSTRUINDO PROGRAMAS MAIS ROBUSTOS
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
PROGRAMAS COM OPÇÕES
CONHECENDO AS ESTRUTURAS CONDICIONAIS
PROGRAMAS COM LAÇOS
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
ATRIBUIÇÕES E TIPOS DE DADOS NA EXECUÇÃO
CONHECENDO AS VARIAÇÕES DAS ATRIBUIÇÕES
APLICANDO CONCEITOS DE CONVERSÕES DE TIPOS
VÍDEO RESUMO
Saiba mais
Aula 1
Aula 2
Aula 3
Aula 4
INTRODUÇÃO
PROGRAMAÇÃO DE VETORES EM UMA PSEUDOLINGUAGEM: PROGRAMAÇÃO E FUNÇÕES COM VETORES
PROGRAMAÇÃO DE VETORES NA LINGUAGEM C
MANIPULAÇÃO DAS VARIÁVEIS DO VETOR
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
DEFINIÇÃO, CARACTERÍSTICAS E SINTAXE DE MATRIZES
PROGRAMAÇÃO DE MATRIZES NA LINGUAGEM C
IMPLEMENTAÇÃO DE MATRIZES
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
DEFINIÇÃO E EXEMPLO DE FUNÇÕES
PROGRAMAÇÃO DE FUNÇÕES E RECURSIVIDADE A LINGUAGEM C
EXEMPLOS PRÁTICOS DE RECURSIVIDADE
VÍDEO RESUMO
Saiba mais
INTRODUÇÃO
DEFINIÇÃO DE REGISTROS E ARQUIVOS
PROGRAMAÇÃO DE REGISTROS NA LINGUAGEM C
PROGRAMAÇÃO DE ARQUIVOS NA LINGUAGEM C
VÍDEO RESUMO
Saiba mais
Aula 1
Aula 2
Aula 3
Aula 4