Baixe o app para aproveitar ainda mais
Prévia do material em texto
PROGRAMAÇÃO DE COMPUTADORES Pietro Martins de Oliveira Presidente da Divisão de Ensino Reitor Pró-Reitor de Graduação Coordenação Geral de EAD Coordenação de Metodologia e Tecnologia Autoria Parecer Técnico Supervisão Editorial Projeto Gráfi co e Capa Prof. Paulo Arns da Cunha Prof. José Pio Martins Prof. Carlos Longo Prof. Everton Renaud Profa. Roberta Galon Silva Pietro Martins de Oliveira Veronica Isabela Quandt Felipe Guedes Antunes Regiane Rosa © Universidade Positivo 2018 Rua Prof. Pedro Viriato Parigot de Souza, 5300 – Campo Comprido Curitiba-PR – CEP 81280-330 *Todos os gráficos, tabelas e esquemas são creditados à autoria, salvo quando indicada a referência. Informamos que é de inteira responsabilidade da autoria a emissão de conceitos. Nenhuma parte desta publicação poderá ser reproduzida por qualquer meio ou forma sem autorização. A violação dos direitos autorais é crime estabelecido pela Lei n.º 9.610/98 e punido pelo artigo 184 do Código Penal. Imagens de ícones/capa: © Thinkstock / ©123RF. VG EDUCACIONAL Análise de Qualidade, Edição de Texto, Design Instrucional, Edição de Arte, Diagramação, Design Gráfico e Revisão. Caro aluno, A metodologia da Universidade Positivo apresenta materiais e tecnologias apropria- das que permitem o desenvolvimento e a interação entre alunos, docentes e recursos didá- ticos e tem por objetivo a comunização bidirecional entre os atores educacionais. O seu livro, que faz parte dessa metodologia, está inserido em um percurso de apren- dizagem que busca direcionar a construção de seu conhecimento por meio da leitura, da contextualização teórica-prática e das atividades individuais e colaborativas; e fundamen- tado nos seguintes propósitos: valorizar suas experiências; incentivar a construção e a reconstrução do conhecimento; estimular a pesquisa; oportunizar a reflexão teórica e aplicação consciente dos temas abordados. COMPREENDA SEU LIVRO Metodologia Com base nessa metodologia, o livro apresenta a seguinte estrutura: Pergunta norteadora Ao fi nal do Contextualizando o cenário, consta uma pergunta que estimulará sua reflexão sobre o cenário apresentado, com foco no desenvolvimento da sua capacidade de análise crítica. Tópicos que serão estudados Descrição dos conteúdos que serão estudados no capítulo. Boxes São caixas em destaque que podem apresentar uma citação, indicações de leitura, de filme, apresentação de um contexto, dicas, curiosidades etc. Recapitulando É o fechamento do capítulo. Visa sinte- tizar o que foi abordado, reto mando os objetivos do capítulo, a pergunta nortea- dora e fornecendo um direcionamento sobre os questionamentos feitos no decorrer do conteúdo. Pausa para refletir São perguntas que o instigam a refletir sobre algum ponto estudado no capítulo. Contextualizando o cenário Contextualização do tema que será estudado no capítulo, como um cenário que o oriente a respeito do assunto, relacionando teoria e prática. Objetivos do capítulo Indicam o que se espera que você aprenda ao final do estudo do capítulo, baseados nas necessida- des de aprendizagem do seu curso. Proposta de atividade Sugestão de atividade para que você desenvolva sua autonomia e siste- matize o que aprendeu no capítulo. Referências bibliográficas São todas as fontes utilizadas no capítulo, incluindo as fontes mencio- nadas nos boxes, adequadas ao Projeto Pedagógico do curso. COMPREENDA SEU LIVRO Percurso BOXES assista Indicação de filmes, vídeos ou similares que trazem informações complementares ou aprofundadas sobre o conteúdo estudado. Biografia Dados essenciais e pertinentes sobre a vida de uma determinada pessoa relevante para o estudo do conteúdo abordado. Contexto Dados que retratam onde e quando aconteceu determinado fato; demonstram a situação histórica, social e cultural do assunto. Curiosidade Informação que revela algo desconhecido e interessante sobre o assunto tratado. Dica Um detalhe específico da informação, um breve conselho, um alerta, uma informação privilegiada sobre o conteúdo trabalhado. Exemplo Informação que retrata de forma obje tiva determinado assunto abordando a relação teoria-prática. afirmação Citações e afirmativas pronunciadas por teóricos de relevância na área de estudo. Esclarecimento Explicação, elucidação sobre uma palavra ou expressão específica da área de conhecimento trabalhada. SUMÁRIO Apresentação 15 O Autor 16 Capítulo 1 Introdução à linguagem C 17 Contextualizando o cenário 18 1.1. Primeiros passos 19 1.1.1 História 19 1.1.2 A linguagem estruturada C 20 1.1.3 Criando e compilando um programa na linguagem C 21 1.1.4 Primeiro programa em C 24 1.2. Escrevendo o código 27 1.2.1 Exemplo: imprimindo uma linha 27 1.2.2 A biblioteca padrão de C 31 1.2.3 Ponto inicial do programa 32 1.2.4 Funções I/O 33 1.3. Realizando operações básicas 39 1.3.1 Variáveis e a memória 39 1.3.2 Exemplo: somando dois números 42 1.3.3 Operações aritméticas 44 1.3.4 Operadores de atribuição e acumuladores 45 1.4. Trabalhando com mais tipos de dados 47 1.4.1 Tipos de variáveis 47 1.4.2 Exemplo: média de notas 48 1.4.3 Exemplo: recebendo e imprimindo caracteres 49 1.4.4 Exemplos dirigidos 51 Proposta de atividade 59 Recapitulando 60 Referências 61 Capítulo 2 operadores e Controle de Fluxo Simples 63 Contextualizando o cenário 64 2.1. Conversões de tipos 65 2.1.1 Padrão ANSI 65 2.1.2 Conversão implícita 66 2.1.3 Conversão explícita 68 2.1.4 Exemplo: programando com o auxílio da tabela ASCII 69 2.2. Operadores relacionais e lógicos 70 2.2.1 Operadores relacionais 70 2.2.2 Operadores lógicos 71 2.2.3 Operador ternário (?) 74 2.2.4 Exemplo: maior entre três números 77 2.3. Operador de seleção if 82 2.3.1 Estrutura do if e if-else 82 2.3.2 Estrutura de ifs Aninhados 86 2.3.3 Exemplo: condições para o sucesso 88 2.3.4 Exemplos dirigidos 91 2.4. Operador de seleção switch 94 2.4.1 Estrutura do switch 95 2.4.2 Comando break 96 2.4.3 Exemplo: imprimindo números na forma literal 96 2.4.4 Exemplos dirigidos 98 Proposta de atividade 105 Recapitulando 106 Referências 107 Capítulo 3 Controle de Fluxo avançado 109 Contextualizando o cenário 110 3.1. Conceitos básicos de repetição 111 3.1.1 A lógica do loop 111 3.1.2 Um loop infinito 114 3.1.3 Repetição com contadores, flags e valores de Entrada 116 3.1.4 Loops aninhados 118 3.2. Estrutura de repetição while 120 3.2.1 Estrutura do comando while 120 3.2.2 Múltiplas condições e operadores lógicos 121 3.2.3 Exemplo: repetição controlada por contador 123 3.2.4 Exemplos dirigidos 124 3.3. Estrutura de repetição do-while 129 3.3.1 Estrutura do do-while 129 3.3.2 Exemplo: repetição controlada por flags e valores de entrada 130 3.3.3 Exemplo: validando valores de entrada 133 3.3.4 Exemplos dirigidos 135 3.4. Estrutura de repetição for 140 3.4.1 Estrutura do for 140 3.4.2 Comandos continue e break em um loop 142 3.4.3 Exemplos dirigidos 143 Proposta de atividade 151 Recapitulando 152 Referências 153 Capítulo 4 Funções 155 Contextualizando o cenário 156 4.1. Definição de funções 157 4.1.1 O que é e para que serve uma função 157 4.1.2 A função main() 159 4.1.3 Tipo de retorno e parâmetros de entrada 160 4.1.4 Declaração e protótipo de função 162 4.2. Declarando e utilizando funções 163 4.2.1 Utilização básica 165 4.2.2 Escopo de variáveis 167 4.2.3 Exemplos dirigidos 170 4.3. Modularizando o código 175 4.3.1 O que é e para que serve a modularização 175 4.3.2 Modularizando com funções 176 4.3.3 Exemplo: desenvolvimento de uma calculadora 177 4.3.4 Exemplos dirigidos 182 4.4. Depurando o código 193 4.4.1 O que é e para que serve a depuração? 193 4.4.2 Funcionamento da depuração 194 4.4.3 Exemplos dirigidos 196 Proposta de atividade 207 Recapitulando 208 Referências 209 Capítulo 5 Vetores 211 Contextualizando o cenário 212 5.1. Definição de vetores 213 5.1.1 O que é um vetor?213 5.1.2 Declaração 215 5.1.3 Memória 216 5.1.4 Vantagens e desvantagens 218 5.2. Uso do vetor 219 5.2.1 Acesso a uma posição do vetor 219 5.2.2 Percorrendo um Vetor 222 5.2.3 Leitura e escrita de um vetor 224 5.2.4 Cuidado: invasão de memória 225 5.3. Exemplos com vetores 227 5.3.1 Exemplo: fazendo a média de um vetor 228 5.3.2 Encontrando o menor e maior número de um vetor 230 5.3.3 Exemplos dirigidos 232 5.4. Exemplos avançados de vetores 240 5.4.1 Concatenação 241 5.4.2 União 244 5.4.3 Intersecção 248 5.4.4 Interpolação 251 Proposta de atividade 254 Recapitulando 255 Referências 256 Capítulo 6 Matrizes 257 Contextualizando o cenário 258 6.1. Vetores multidimensionais 259 6.1.1 O que é um vetor multidimensional? 259 6.1.2 Utilização de um vetor multidimensional 260 6.1.3 Vantagens e desvantagens 262 6.2. Uso de matrizes 263 6.2.1 Dimensões e tamanho máximo de uma matriz 264 6.2.2 Percorrendo uma matriz 265 6.2.3 Leitura e escrita em uma matriz 269 6.2.4 Passando vetores e matrizes como parâmetro de uma função 273 6.3. Exemplos com matrizes 277 6.3.1 Produto de matrizes 277 6.3.2 Identificando uma matriz de permutação 280 6.3.3 Identificando uma matriz como quadrado mágico 285 6.4. Exemplos avançados de matrizes 291 6.4.1 Ponto de sela 291 6.4.2 Jogo da velha 295 6.4.3 Oito damas 302 Proposta de atividade 308 Recapitulando 309 Referências 310 Capítulo 7 Strings 311 Contextualizando o cenário 312 7.1. Definindo e utilizando uma string 313 7.1.1 O que é uma string? 313 7.1.2 Definição e limitações de uma string 314 7.1.3 Funções de leitura e escrita 316 7.1.4 Buffer do teclado 321 7.2. Manipulação de strings 323 7.2.1 Copiando strings 324 7.2.2 Concatenando strings 325 7.2.3 Verificando o tamanho de uma string 326 7.2.4 Comparando strings 328 7.3. Biblioteca string.h 330 7.3.1 Função de cópia strcpy() 330 7.3.2 Função de concatenação strcat() 332 7.3.3 Função para verificar tamanho strlen() 333 7.3.4 Função de comparação strcmp() 335 7.4. Exemplos com strings 337 7.4.1 Invertendo uma string 337 7.4.2 Identificando uma sequência de caracteres repetidos 339 7.4.3 Criptografando uma string 342 7.4.4 Exemplo dirigido 345 Proposta de atividade 348 Recapitulando 349 Referências 350 Capítulo 8 Estruturas, uniões, Enumerações e Headers 351 Contextualizando o cenário 352 8.1. Definindo estruturas 353 8.1.1 Definição e limitações de uma estrutura 353 8.1.2 Criando e inicializando uma estrutura 354 8.1.3 Acessando membros de uma estrutura 356 8.2. Uso de estruturas 358 8.2.1 Usando estruturas com funções 358 8.2.2 Vetores de estruturas 360 8.2.3 Exemplo: criando uma agenda de contatos 360 8.3. Uniões e enumerações 368 8.3.1 O que é e para que serve uma união? 369 8.3.2 Usando uma união 370 Pausa para refletir 372 8.3.3 O que é e para que serve um enumerador? 373 8.3.4 Usando um enumerador 375 8.4. Organizando o projeto 378 8.4.1 Como organizar o projeto? 378 8.4.2 Definição de headers 379 8.4.3 Criando e usando headers 379 8.4.4 Exemplo dirigido 384 Proposta de atividade 393 Recapitulando 394 Referências 395 APRESENTAÇÃO Desde o surgimento dos primeiros modelos computacionais, o mundo vem se trans- formando por meio dos computadores. Em meados da década de 1940, Alan Turing desen- volveu uma das primeiras máquinas eletromecânicas para realizar cálculos matemáticos. Nas décadas de 1970 e 1980, a humanidade acompanhou a popularização dos microcompu- tadores. Com a adoção da internet em larga escala, no final da década de 1990, houve uma verdadeira explosão de novos modelos de negócio e novas tecnologias. Atualmente, é mui- to comum que as organizações de várias áreas dependam diretamente de alguma tecnolo- gia, como os softwares. Os softwares são a parte virtual de um sistema computacional e, sem eles, a utiliza- ção das máquinas talvez seria inviável. Assim, os programas de computador se posicionam como uma das principais tecnologias que, nos dias atuais, dão apoio à solução de proble- mas, à execução de processos, às tomadas de decisão, à comunicação etc. Nesta disciplina, você verá como é possível construir software em linguagem C. A par- tir de seus conhecimentos em algoritmos, você terá condições de compreender os prin- cipais conceitos empregados no desenvolvimento de programas, partindo do início. Para isso, é de suma importância reproduzir todos os exemplos demonstrados neste livro e pra- ticar exaustivamente os exercícios propostos. Ao final, espera-se que você seja capaz de utilizar um ambiente de programação para construir soluções em C para os mais diversos problemas, das mais distintas áreas e negócios. O AUTOR O Professor Pietro Martins de Oliveira é Mestre em Ciência da Computação pela Universidade Estadual de Maringá (UEM) e Bacharel em Engenharia da Computação pela Universidade Estadual de Ponta Grossa (UEPG). Tem experiência como analista de sistemas e desenvolve- dor. Atuou como coordenador de cursos de graduação em Engenharia de Software, Sistemas de Informação, Engenharia de Produção e Técnico em Computação Gráfi ca. Currículo Lattes: <http://lattes.cnpq.br/1793084774574585> Dedico esta obra, primeiramente, a minha mãe, minha avó e meu avô, principais responsáveis pela formação de meu caráter e meus valores; a meu pai e meus tios, pelo exemplo de hombridade e história de vida; e, por fim, mas não menos importante, a minha esposa, com quem sigo com amor na jornada da vida. CAPÍTULO 1 Introdução à Linguagem C Pietro Martins de Oliveira oBJEtIVoS Do Capítulo • Compreender o funcionamento de uma linguagem de programação e as caracterís- ticas da linguagem C. • Construir o primeiro programa, assim como utilizar as funções básicas de entrada e saída. • Entender o conceito de variáveis, tipos de variáveis e memória. • Realizar operações aritméticas e utilizar acumuladores. tÓpICoS DE EStuDo 1 Primeiros passos • História. • A linguagem estruturada C. • Criando e compilando um programa na linguagem C. • Primeiro programa em C. 3 Realizando operações básicas • Variáveis e a memória. • Exemplo: somando dois números. • Operações aritméticas. • Operadores de atribuição e acumuladores. 2 Escrevendo o código • Exemplo: imprimindo uma linha. • A biblioteca padrão de C. • Ponto inicial do programa. • Funções I/O. 4 Trabalhando com mais tipos de dados • Tipos de variáveis. • Exemplo: média de notas. • Exemplo: recebendo e imprimindo caracteres. • Exemplos dirigidos. Programação de Computadores18 Contextualizando o cenário O dia a dia das pessoas e das corporações é permeado pelos mais variados problemas e situ- ações difíceis. Para os programadores, problema é sinônimo de oportunidade, uma vez que a função desse tipo de profissional é desenvolver algoritmos que solucionem situações proble- máticas ou que facilitem o dia a dia dos indivíduos. Por falar em algoritmos, podemos defini-los como uma sequência de passos finita para a re- solução de problemas computacionais. De maneira geral, algoritmos são escritos em uma lin- guagem estruturada, como a linguagem C. Assim, fica a pergunta: a partir de uma solução algorítmica, como é possível criar os primei- ros programas em linguagem C? 19Programação de Computadores 1.1. Primeiros passos Para que você possa iniciar seus estudos em programação, primeiramente, é preciso esco- lher uma linguagem de programação capaz de apoiar o desenvolvimento de instruções que pos- sam ser compreendidas por uma máquina. Assim sendo, é importante optar por uma linguagem estruturada, livre de ambiguidades, que dê recursos suficientemente úteis para que o programa- dor esteja apto a resolver problemas do mundo real por meio de algoritmos e programas. Desse modo, será tomada por base a linguagem C, por ser uma linguagem que dá a possibilidade de trabalhar tanto com interfaces para aplicações de mais baixo nível quanto com interfaces gráficas de alto nível. Além disso, existemcompiladores eficientes de C para computadores completamente distintos, que vão desde máquinas Apple, passando por ambientes Microsoft e indo até sistemas baseados em UNIX (SCHILDT, 1997). 1.1.1 História Segundo Schildt (1997), as origens do C remetem à linguagem BCPL, desenvolvida por Martin Richards. A influência da BCPL sobre C ocorreu indiretamente por meio de outra lingua- gem, chamada B, que, por sua vez, foi desenvolvida por Ken Thompson em 1970. A linguagem B é que tinha como base a BCPL, conforme ilustra a figura “Linguagens de influência sob o C”. linguagens de influência sob o C A linguagem C, por sua vez, foi concebida em 1972 por Dennis Ritchie, que utili- zou para sua criação um computador DEC PDP-11 com sistema operacional UNIX. Assim, surgiu o primeiro padrão para essa linguagem, o C UNIX (ASCENCIO; CAMPOS, 2012). Todavia, devido à disseminação do uso de microcomputadores nas décadas de 70 e 80, começaram a surgir implementações distintas do C, fazendo com que surgissem divergên- cias e falta de padronização nos códigos-fonte. Programação de Computadores20 Devido às discordâncias entre as várias implementações do C, em 1983, foi criada uma comissão, pelo American National Standards Institute (ANSI), para definir uma padro- nização moderna e compreensiva do C. De acordo com a Universidade de Leicester, no Reino Unido, o resultado da definição foi o padrão “C ANSI”, que foi publicado por com- pleto apenas em 1988 (INTRODUCTION…, on-line). Com isso, apareceu uma nova lingua- gem que dá suporte ao desenvolvimento de softwares de alta relevância até os dias de hoje, como é o exemplo dos sistemas operacionais Linux. 1.1.2 A linguagem estruturada C De acordo com Ascêncio e Campos (2012), o paradigma de programação estruturado também pode ser chamado de imperativo ou procedural e permite que problemas sejam divididos em subproblemas de menor complexidade. Pode-se encarar a solução de um sub- problema como sendo uma sub-rotina ou função. Uma função, geralmente, recebe dados de entrada que são, então, processados para se produzir um resultado. Para isso, uma linguagem estruturada se apoia nas estruturas algorítmicas sequen- cial, de decisão e de repetição, fazendo com que as linguagens estruturadas sejam turing- completas (ASCÊNCIO; CAMPOS, 2012). Assista Em 2014, foi lançado o filme O jogo da imitação, inspirado na história de Alan Tu- ring, matemático e cientista da computação que teve papel fundamental durante a Segunda Guerra Mundial. Schildt (1997) argumenta que uma linguagem estruturada permite que se seccione o código-fonte e se escondam, do resto do programa, os dados que dizem respeito a uma tarefa específica. Com isso, são reduzidos efeitos indesejados, que poderiam ser acarreta- dos pelas sub-rotinas nos demais pontos de um software. A linguagem C obedece ao paradigma de programação estruturada, diferentemente do C++, que segue o paradigma orientado a objetos. Sabendo disso, é possível afirmar que o C possui as três estruturas algorítmicas mencionadas anteriormente (sequencial, con- dicional e iterativa), dando ao programador o poder necessário para desenvolver as mais variadas aplicações. Além disso, a linguagem C também permite a modularização dos pro- blemas, uma vez que dá suporte à criação de funções que executarão sub-rotinas para resolver subproblemas dentro de uma solução mais ampla. 21Programação de Computadores Pausa para refletir A linguagem C segue o paradigma estruturado. Além do paradigma de programação estrutu- rado e do orientado a objetos, será que existem outros paradigmas? O reaproveitamento de sub-rotinas é muito comum na área da Engenharia de Software. O conceito de reúso vem sendo discutido desde o surgimento dos primeiros pro- gramas de computador. Assim, reforçamos o argumento de que a linguagem C é plena- mente adequada para o desenvolvimento de software. 1.1.3 Criando e compilando um programa na linguagem C Para que se possa criar o primeiro código, é necessário, antes de tudo, entender como um programa em C é construído. Partindo do pressuposto de que o código-fonte é de fácil compreensão para os seres humanos, devido a sua sintaxe, é preciso compreender que o processador de uma máquina não é capaz de interpretar e executar diretamente o código- fonte original, da forma que foi escrito pelo programador. Para transformar um código-fonte em C em um programa executável pela máquina, é preciso “traduzir” esse código-fonte por meio do processo de compilação. Assim, surge a figura do compilador, que é um software sofisticado capaz de transformar o código-fonte de uma linguagem de programação em código binário, o qual pode ser executado pela máquina. O compilador faz uma análise sintática do arquivo que contém o código-fonte original para criar o chamado código-objeto. De acordo com Schildt (1997), o processo de compila- ção deve ser refeito toda vez que o programador alterar o código original em C. Afirmação Existem, também, linguagens interpretadas. Nesses casos, sempre que for execu- tado, o código-fonte passa por análise sintática, ao contrário das linguagens compiladas, nas quais o código é analisado uma vez e pode ser executado quantas vezes forem precisas. Caso o programa seja curto, ele pode ser escrito todo em um único arquivo-fonte. Todavia, em aplicações comerciais reais, é comum que os programas possuam milhares de linhas de código, distribuídas entre diversos arquivos distintos. Assim, pode-se refle- tir sobre o tempo que o compilador levaria para compilar um programa muito grande. Programação de Computadores22 Obviamente, a conclusão é a de que, quanto maior o programa, maior o tempo que o com- pilador leva para finalizar seu trabalho. Imagine que você está trabalhando em um software muito grande, que está descrito em vários arquivos-fonte. Caso o código-fonte de apenas uma função seja alterado, em somente um arquivo, seria possível compilar todos os arquivos para gerar um binário exe- cutável? A resposta é não! Schildt (1997) salienta que é possível compilar apenas os arqui- vos-fonte que o programador desejar. É aí que entra em cena o processo de linkedição. Geralmente, o compilador ou o sistema operacional possui um linkeditor (linker), que é capaz de linkeditar (“linkar”) códigos binários já compilados ao novo arquivo binário recém-compilado. Isso facilita a modularização, a manutenção e a reutilização do código- fonte; por isso, é usual que programadores utilizem as chamadas “bibliotecas” durante o desenvolvimento de seus softwares. As bibliotecas são programas que possuem funcionalidades pré-programadas, as quais podem ser invocadas no código sem que seja preciso “reinventar a roda”. A figura “Processo de compilação e linkedição” mostra um esquema de como o código-fonte, o código-objeto, as bibliotecas, o compilador e o linkeditor interagem para a produção de um arquivo executável. processo de compilação e linkedição 23Programação de Computadores Existem, ainda, softwares chamados de ambiente de programação ou, simplesmente, Integrated Development Environments (IDEs). Os ambientes de programação são úteis ao programador que deseja trabalhar no desenvolvimento de software facilitado por uma interface gráfica capaz de reunir, além do compilador, várias outras funcionalidades. É pos- sível encontrar diversas IDEs gratuitas, como Dev C++, NetBeans, Eclipse, Visual Studio Code, Code::Blocks, dentre outras. Um programador robusto não deve depender de uma interface gráfica para construir seus softwares. Dessa forma, opta-se por compilar os códigos-fonte utilizando o compilador C/C++ do conjunto de compiladores GNU Compiler Collection (GCC). Existem versões do GCC tanto para sistemas baseados em UNIX quanto Apple e Microsoft; por isso, é uma boa esco- lha, por ser praticamente independente de plataforma (GCC HOMEPAGE, 2018, on-line). Pausa para refletir: Como você viu, o compiladoré um programa que produz outros programas. Porém, nesse caso, qual foi o programa que produziu o compilador? Compilação e execução de um programa em linguagem C A execução de programas também se dará via terminal, por linhas de comando. A figura “Compilação e execução de um programa em linguagem C”, mostrada anteriormente, demonstra um exemplo de compilação do código-fonte “Hello_world.c” em um binário exe- cutável (“Hello_world.exe”) e posterior execução em um ambiente Microsoft Windows. Programação de Computadores24 1.1.4 Primeiro programa em C Para criar o primeiro código-fonte em C, é necessário utilizar um editor de texto sim- ples, como Notepad, Gedit, Vim, Nano etc. Não é aconselhável criar arquivos-fonte em pro- cessadores de texto como o Microsoft Word, pois tais softwares adicionam metadados aos arquivos, os quais não serão aceitos pelo compilador. No presente exemplo, serão utilizados os editores open-source e Notepad++. Poderia ser utilizado, caso fosse necessário, qualquer editor de texto com interface de linhas de comando, como o Vim, sem maiores prejuízos. Para criar um novo arquivo de texto no Notepad++, basta acessar o menu “File > New”, como ilustrado na figura “Criando um novo arquivo fonte no Notepad++”. Criando um novo arquivo fonte no Notepad++ Após executar o passo a passo recém-descrito, é esperado que se abra uma nova aba dentro do seu Notepad++, na qual é possível inserir texto via teclado. O texto a ser inserido será o código-fonte do primeiro programa. A figura “Novo arquivo-fonte intitulado “new 1”” ilustra a nova aba, de nome “new 1”, para a criação e a edição do programa em C. 25Programação de Computadores Novo arquivo-fonte intitulado “new 1” Agora que você já sabe como criar um novo arquivo-fonte, precisa ambientar-se quanto à estrutura básica de um programa em C. Assim como em toda linguagem de pro- gramação, é preciso seguir uma sintaxe bem definida, levando em conta a existência de palavras reservadas que representam comandos únicos e específicos. A tabela “Palavras reservadas do C ANSI” lista as principais palavras reservadas do C ANSI. palavras reservadas do C aNSI auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while Fonte: SCHILDT, 1997, p. 10. Programação de Computadores26 Vale a pena lembrar que a sintaxe da linguagem C é case sensitive, ou seja, ela dife- rencia caixa-alta de caixa-baixa. Assim, a palavra if (minúsculo) é tratada de maneira diferente da palavra IF (maiúsculo) pelo compilador. Além disso, a sintaxe da linguagem C também possui alguns caracteres especiais com propósito específico. Observe a figura “Caracteres especiais com propósito específico - sintaxe da linguagem C”. “Caracteres especiais com propósito específico - sintaxe da linguagem C”. © P av el L un ev ic h / / 1 23 R F. (A da pt ad o) . 27Programação de Computadores Por fim, para poder criar o primeiro código-fonte, é preciso entender que todo algo- ritmo possui um corpo principal de instruções. Na linguagem C, esse bloco de comandos principal é delimitado pela função main(). Todo software desenvolvido em C deve declarar a função e, dentro dela, deve ser invocado todo o código do programa, como comandos de interação com o usuário, operações matemáticas etc. Quando o programa for executado, a função main() será a primeira a ser invocada e executada. Quando se esquece de declará -la, ocorre um erro de linkedição. Sinteticamente, pode-se definir a estrutura geral de um programa em C da seguinte forma: primeiramente, faz-se a inclusão das bibliotecas (facultativo); depois, declaram-se as variáveis globais (facultativo); por fim, obrigatoriamente, declara-se a função main() e, opcionalmente, declaram-se outras funções. 1.2. Escrevendo o código Como visto anteriormente, para se criar o primeiro programa em C, será adotado o compilador GCC. Dessa forma, será escrito o primeiro código-fonte. 1.2.1 Exemplo: imprimindo uma linha Para começar, crie um novo arquivo-fonte, como descrito na subseção 1.1.4. Em seguida, copie o código-fonte do Exemplo 1a, a seguir, e cole no arquivo-fonte dentro do editor de texto. Exemplo 1a - Código-fonte do programa Hello_world.c 1 2 3 4 5 #include <stdio.h> main(){ printf("Hello, world!"); return 0; } Repare que o primeiro código-fonte possui alguns dos elementos básicos da estrutura de um programa em C: na linha 1 do Exemplo 1a, tem-se a inclusão de uma biblioteca que possui funcionalidades pré-programadas; na linha 2, tem-se o início da declaração da fun- ção principal, main(); ainda na linha 2, tem-se a abertura de uma chave ({) que delimita o início do bloco de comandos da função main(); na linha 5, fecham-se as chaves (}), delimi- tando o fim do bloco de comandos do main(); e nas linhas 3 e 4, há dois comandos, cada um deles sendo encerrado por ponto e vírgula (;). Programação de Computadores28 O comando “printf(“Hello, World!”);”, da linha 3, fará com que a frase “Hello, world!” seja impressa na tela. O printf() é uma função pré-programada que se encontra implementada dentro da biblioteca stdlib.h. A biblioteca foi incluída junto ao programa na linha 1, por meio do comando “#include <stdio.h>”. O comando “return 0;”, da linha 4, tem o intuito de encerrar o programa, produzindo um código zero (0) como valor de retorno. Quando o código-fonte do Exemplo 1a estiver devidamente replicado no código-fonte, dentro do Notepad++, é preciso salvar o arquivo com o nome e a extensão “Hello_world.c”, de acordo com a figura “Salvando o programa Hello_world.c”. Vale salientar que todo arquivo- fonte que contém código escrito no padrão C ANSI levará o “.c” como extensão, seja em ambientes baseados em UNIX, em ambientes Microsoft Windows ou em qualquer outro. Salvando o programa Hello_world.c Em seguida, deve-se compilar o código-fonte por meio do terminal de linhas de comando. Para isso, é possível abrir o terminal e acessar, por meio de comandos de texto, a pasta na qual se encontra salvo o arquivo-fonte. Para acessar o terminal, em ambientes Microsoft Windows, basta: (1) clicar no botão “iniciar” (start) na barra de tarefas; (2) pes- quisar (ou executar) por “cmd”; com isso, deve aparecer a opção para (3) abrir o terminal de linhas de comando. O passo a passo para abrir a janela do terminal pode ser visualizado na figura “Passo a passo para acessar o terminal de comandos no Windows”. 29Programação de Computadores passo a passo para acessar o terminal de comandos no Windows Uma vez acessada a pasta local na qual se encontra o arquivo-fonte, dentro do ter- minal de comandos de texto, deve-se compilar o programa, executando um comando de acordo com a sintaxe do Exemplo 1b, a seguir. Exemplo 1b - Sintaxe para compilação de um programa com o GCC 1 gcc -o <executável> <código-fonte> O campo executável do Exemplo 1b deve ser substituído pelo nome e extensão do arquivo binário que será produzido após a compilação. No campo código-fonte, é preciso informar o nome do arquivo fonte e sua extensão (.c). No exemplo da figura “Compilando o programa Hello_world.c”, nota-se que o arquivo se encontra no desktop e pode-se observar como utilizar a linha de comando para compilação, na prática. Programação de Computadores30 Compilando o programa Hello_world.c Caso existam erros sintáticos no código, o compilador informará, por meio de men- sagens na tela, qual a linha e a coluna nas quais se encontra o erro. O compilador não será capaz de gerar o arquivo binário executável, caso existam erros de sintaxe. Também será possível ler mensagens de warning, caso o compilador julgue importante informar ao pro- gramador sobre possíveis problemas. De qualquer maneira, caso existam warnings, o pro- cesso de compilação ocorrerá normalmente. Veja a figura “Execução e saída (resultado)do programa Hello_world.c”. Execução e saída (resultado) do programa Hello_world.c O resultado da execução do primeiro software desenvolvido em linguagem C deve ser algo parecido com o ilustrado na figura “Execução e saída (resultado) do programa Hello_ world.c”. Repare que o programa imprimiu exatamente a frase que havia sido especificada na linha 3 do código-fonte (Exemplo 1a). 31Programação de Computadores 1.2.2 A biblioteca padrão de C De modo geral, seria possível criar um programa plenamente funcional apenas com os códigos do próprio desenvolvedor. Todavia muitas das funcionalidades básicas que uma solução exige teriam que ser escritas a partir do zero. Como dito anteriormente, a lingua- gem C possui comandos nativos em forma de palavras reservadas. Ocorre que tais coman- dos, isoladamente, não suprem todas as necessidades dos programadores (SCHILDT, 1997). Por isso, existem, em C, funcionalidades pré-programadas que podem ser utilizadas nos códigos-fonte, facilitando a vida dos programadores. Tais funcionalidades estão imple- mentadas nas chamadas bibliotecas. Por exemplo, para realizar operações de entrada e saída de dados, pode-se utilizar a biblioteca padrão para entrada e saída, stdio.h (SCHILDT, 1997). Em outros casos, pode ser que o programador julgue necessário realizar chamadas de sistemas para executar comandos de texto em um terminal. Em outras situações, pode ser que se deseje trabalhar com números aleatórios. Para tais funcionalidades, seria necessário incluir a biblioteca C padrão, stdlib.h. Existe uma ampla gama de opções de bibliotecas disponíveis para programadores. Acompanhe a figura “Lista das principais bibliotecas e suas funcionalidades”. lista das principais bibliotecas e suas funcionalidades © K ri an gk ra iw ut B oo nl om / / 1 23 R F. (A da pt ad o) . Programação de Computadores32 Para trabalhar com alguma funcionalidade de uma biblioteca qualquer, é preciso incluir a biblioteca no código-fonte por meio da diretiva “#include”. A linha 1 do Exemplo 1a mostra o comando “#include <stdio.h>” para a inclusão da biblioteca padrão de entrada/saída. Assim, podem ser utilizados comandos de inclusão de bibliotecas sempre que se quiser adicionar funcionalidades pré-programadas aos softwares. 1.2.3 Ponto inicial do programa Do ponto de vista de algoritmos, a solução para um problema sempre parte de um iní- cio, pois há um processamento e, então, o algoritmo é finalizado. Quando se transporta esse conceito para os programas em linguagem C, pode-se traçar uma analogia com a função main(). Como dito anteriormente, a função main() é o corpo principal do código-fonte. Comparando o programa com um algoritmo a ser executado, pode-se considerar que o programa começará sua execução a partir do bloco de comandos do main(). De maneira geral, um programa irá processar sua estrutura de instruções de maneira sequencial e será encerrado quando atingir a delimitação do fim do bloco de comandos do main(), em que suas chaves foram fechadas no código-fonte. A função principal de um programa em C, por padrão, deve ser produzir um resultado (retorno) do tipo inteiro, quando ocorre seu término. Por isso, de maneira geral, precede-se a declaração da função main(), informando que ela é do tipo int, para que, de fato, o pro- grama seja capaz de retornar um dado inteiro. O dado retornado deve ser feito por meio do comando return, como você verá nos exemplos ao longo do capítulo. É de suma importância entender que a função main() será a primeira instrução a ser processada pela máquina, quando o programa é executado. Tudo o que estiver sendo declarado e invocado no main() terá chance de ser executado. Ou seja, todo e qualquer código que não seja invocado dentro dessa função, seja direta ou indiretamente, não será executado pelo processador. Caso o código-fonte não declare a função principal, ocorrerá um erro durante a linkedição, e o programa não será capaz de ser executado. 33Programação de Computadores 1.2.4 Funções I/O Até o presente momento, foi apresentado um breve histórico a respeito do surgimento da linguagem C. Você teve contato com alguns conceitos básicos da estrutura de um pro- grama em C e criou seu primeiro código-fonte. Dessa forma, pode-se, agora, partir para um entendimento mais aprofundado do que é possível criar por meio dessa linguagem de pro- gramação. Para isso, é necessário entender como é possível fazer com que o software interaja com o usuário por meio de funções da biblioteca de entrada e saída padrão, a stdio.h. Como dito anteriormente, o propósito de um algoritmo é solucionar problemas e facili- tar a vida do usuário. Se o foco é facilitar a vida das pessoas, seria interessante que o compu- tador conseguisse comunicar-se com os seres humanos de forma efetiva. Atualmente, uma das formas mais comuns de receber alguma informação de uma máquina é pela tela. Assim, nos programas, haverá condições de externalizar dados ao usuário por meio do monitor. O ato de mostrar alguma informação para quem está utilizando o software é cha- mado de operação de Saída, ou Output (O). Nessa situação, o programa escreve dados em buffers, os quais, posteriormente, serão tratados pelo sistema operacional para que sejam impressas, na tela, as mensagens que o programador desejar exibir. Em C, uma das principais funções para mostrar informações na tela é o printf(). A sintaxe de como utilizar essa função está destacada no exemplo a seguir. Exemplo 2 - Sintaxe de utilização da função printf() printf(“<texto_de_controle>”, <lista_de_argumentos>); No Exemplo 2, o campo texto_de_controle pode ser composto de dois tipos de informações: i. caracteres literais: letras, números e dígitos que serão impressos literalmente na tela; ii. comandos de formatação. Já o campo lista_de_argumentos refere-se aos dados que estarão relacionados com alguns comandos inseridos no texto_de_controle. Programação de Computadores34 Primeiramente, serão detalhados os caracteres literais. Sempre que o programador quiser mostrar algo no monitor, pode inserir os caracteres alfanuméricos diretamente den- tro das aspas que delimitam o texto_de_controle. Todavia é preciso estar atento, pois nem sempre um caractere é interpretado de maneira literal pelo printf(). Quando foi criado o primeiro programa (Exemplo 1), a função printf() foi utilizada para imprimir uma mensagem simples na tela. Para compreender melhor como realizar uma impressão literal simples, observe o Exemplo 3. Exemplo 3 - utilizando o printf() como um comando isolado para imprimir uma men- sagem literal printf(“Somos programadores iniciantes.”); O resultado da execução do Exemplo 3, de maneira isolada, seria algo como o demonstrado na figura “Resultado da execução do Exemplo 3”. Resultado da execução do Exemplo 3 Perceba, comparando o Exemplo 3 com a figura “Resultado da execução do Exemplo 3”, que o texto foi impresso por completo, como esperado. Ou seja, tudo o que o programador especificou entre as aspas do printf() foi escrito por completo no momento da execução. Assim, conclui-se que todos os caracteres desse exemplo foram interpretados literalmente. 35Programação de Computadores Caracteres que não são impressos literalmente na tela são utilizados como comandos de formatação. Basicamente, podem-se citar dois caracteres que indicam o início de um comando dentro do campo texto_de_controle, a saber: o percentual (%) e a barra inver- tida (\). Para ficar mais claro, veja o Exemplo 4, sobre como utilizar um comando dentro das aspas do printf(), a seguir. Exemplo 4 - Empregando comandos dentro do printf() printf("Estamos\nProgredindo\nNa\nLinguagem\nC."); O resultado da execução do printf() do Exemplo 4 seria algo parecido com o que se exibe na figura “Resultado da execução do Exemplo 4”. Resultado da execução do Exemplo 4 Pode-se notar que, para cada \n encontrado dentro do texto_de_controle do printf()do Exemplo 4, há como resultado, na execução (figura “Resultado da execução do Exemplo 4”), uma quebra de linha. Ou seja, nesse caso, o \n não foi interpretado literal- mente, mas, sim, como um comando, para que, durante a impressão do texto na tela, uma linha fosse pulada a cada vez que esse comando aparecesse. Assim, percebe-se que é possível formatar o texto a ser impresso na tela utilizando comandos precedidos da barra invertida (\). Para auxiliar na formatação de textos, serão mostrados, a seguir, alguns comandos que podem ser úteis ao programador. A tabela “Comandos para formatação do texto dentro de um printf( )” mostra alguns comandos para formatar a disposição dos caracteres no texto. Programação de Computadores36 Comandos para formatação do texto dentro de um printf() Comando ação \n Salta para uma nova linha. \t Cria um avanço na mesma linha (tabulação). \b Retrocede um caractere (backspace). \0 Delimita o fim de um string (texto), ou seja, um caractere nulo. Dica Caso seja necessário imprimir a barra invertida, o percentual ou as aspas duplas, de maneira literal, será preciso incluir mais uma barra invertida (\) precedendo tais caracteres. Com isso, o printf() irá interpretar tais caracteres literalmente, ao invés de encará -los como comandos. Quando se deseja especificar o formato da apresentação de um dado alfanumérico, é pos- sível utilizar os comandos que levam em conta o caractere percentual (%). Tais comandos per- mitem formatar, por exemplo, quantas casas decimais serão exibidas em números reais “com vírgula”. A seguir, o Exemplo 5 mostra como é possível modificar a exibição de um número real com cinco casas decimais, para que sejam impressas apenas duas casas após a vírgula. Exemplo 5 - Formatando o número de casas decimais de um número real em um printf() printf("Duas casas decimais: %.2f.", 5.12345); O resultado da execução do printf() do Exemplo 5 pode ser observado na figura “Resultado da execução do Exemplo 5”. Resultado da execução do Exemplo 5 37Programação de Computadores É necessário atentar-se para o fato de que, dessa vez, o printf() possui elementos a mais dentro de seus parênteses. No campo texto_de_controle, o comando %.2f é utilizado para informar ao printf() que se quer imprimir apenas duas casas decimais de um número real qual- quer. O valor numérico em questão é o 5.12345, que possui exatamente cinco casas decimais. Repare que o número real foi listado, no printf() do Exemplo 5, após a vírgula que sucede o fechamento das aspas duplas. Isso ocorre porque o dado numérico faz parte do campo lista_ de_argumentos, mencionado no Exemplo 2. Com isso, duas situações são constatadas: i. a lista_de_argumentos serve para indicar ao printf() quais são os dados que estão sendo manipulados pelos comandos de formatação de apresentação do texto_de_controle. ii. os comandos de formatação de apresentação que constam no campo texto_de_ controle devem, obrigatoriamente, estar relacionados a algum dado listado na lista_de_argumentos. Esclarecimento No padrão C ANSI, utiliza-se o caractere ponto (.) para delimitar o início das casas decimais de um número real (ponto flutuante), ao invés da vírgula (,). Todavia é possível utilizar funções da biblioteca locale.h para utilizar a vírgula ao invés do ponto. Na tabela “Comandos de especificação de formato para apresentação”, estão listados outros comandos de especificação de formato para apresentação de dados. Esses coman- dos podem ser utilizados tanto na saída de dados, por meio do printf(), quanto para rea- lizar entrada de dados, com o scanf(), que será visto mais adiante. Comandos de especificação de formato para apresentação Comando Formato de exibição %c Caractere %d Inteiro decimal com sinal %i Inteiro decimal com sinal %e Notação científica %f Ponto flutuante decimal (real) %s Texto (string de caracteres) %x Hexadecimal sem sinal Fonte: SCHILDT, 1997. (Adaptado). Programação de Computadores38 Agora que você já tem os subsídios básicos para imprimir informações na tela, é necessá- rio seguir adiante e compreender como é possível inserir dados junto ao programa por meio do teclado. Chama-se de operação de Entrada, ou Input (I), a ação de ler dados informados por um usuário. Para isso, a biblioteca stdio.h implementa a função scanf(). A sintaxe de utiliza- ção do scanf() para realizar a leitura de dados do teclado pode ser observada no Exemplo 6a. Exemplo 6a - Sintaxe de utilização do scanf() scanf(“<texto_de_controle>”, &<variável1>[, &<variável2>, …, &<variávelN>]); Como se pode observar, a sintaxe da função scanf() é muito semelhante à do printf(), porém com funcionalidade “inversa” (SCHILDT, 1997). Perceba que existem, novamente, dois campos: • texto_de_controle: nesse campo, deve-se colocar, entre as aspas, qual é o especificador de formato de apresentação que melhor se adequa ao tipo dos dados que se deseja ler via teclado, de acordo com a tabela “Comandos de especificação de formato para apresentação”; • variáveis: de maneira similar ao printf(), o scanf() precisa referenciar o destino para o qual os dados serão enviados após o usuário inserir os dados via teclado. Esse destino, geralmente, é uma variável, como será visto mais adiante. Imagine que se queira que o usuário insira um dado do tipo inteiro, por meio do teclado, por exemplo, que seja informada a idade da pessoa que está utilizando o pro- grama. Assim, seria necessário invocar a função scanf(), informando o especificador de formato %d (ou %i), e relacionar a esse especificador qual é o destino (variável idade - o conceito de variáveis será estudado logo adiante) para o qual o dado irá após a leitura via teclado, como se pode observar no Exemplo 6b. Exemplo 6b - Invocando o scanf() para realizar a leitura de um dado do tipo inteiro scanf(“%d”, &idade); Assim, já existem condições para serem realizadas operações de entrada/saída, tam- bém conhecidas como operações de input/output (I/O). 39Programação de Computadores 1.3. Realizando operações básicas Após compreender como é possível criar, compilar e executar programas simples, você irá trabalhar com outras operações além da entrada e da saída de dados. Sabe-se que a cons- trução de algoritmos fundamenta-se, primordialmente, na matemática. Assim, a sequência deste capítulo apresentará os conceitos mais básicos e indispensáveis: variáveis, operações aritméticas e comando de atribuição; sem estes, seria impossível conceber os programas. 1.3.1 Variáveis e a memória Imagine cozinheiros em um restaurante industrial. Para prepararem os pratos, esses cozinheiros têm à disposição vários ingredientes, como cereais, grãos, carnes, queijos, vegetais, temperos etc. Para produzirem a comida, precisarão de recipientes para armaze- nar tais ingredientes. Por exemplo, para fazer um bolo, é necessário reunir ovo, fermento, farinha, dentre outros ingredientes, em uma vasilha (recipiente). Certo, mas o que uma cozinha tem a ver com programas? Do ponto de vista de um algoritmo, pode-se criar uma analogia na qual os dados que são manipulados nos programas seriam como os ingredientes. Para manipular os dados, são utili- zados “recipientes”, assim como na cozinha. Todavia, para os programas, devem-se armazenar os “ingredientes” em memória. Para isso, existe o conceito de variáveis. Assim, analogamente, uma variável é comparada a um “recipiente em memória” no qual os dados ficam armazenados, como ilustra a figura “Analogia: variável e dados como recipiente e ingredientes”. analogia: variável e dados como recipiente e ingredientes © S ay ee d S ez an / / P in te re st . ( A da pt ad o) . Programação de Computadores40 Continuando a analogia, pode-se considerar que a memória do computador é uma espécie de “prateleira”, na qual ficam armazenadas as variáveis. Existem variáveis com diferentes visibilidades: • variáveis globais: podem ser acessadas de qualquer ponto do programae devem ser declaradas fora de qualquer função, inclusive, fora do main(). • variáveis locais: só podem ser acessadas dentro de um escopo específico, por exem- plo, uma variável declarada dentro do main() só estará visível dentro dessa função. Também, há distinção quanto à forma com a qual o computador aloca espaços em memória: • variáveis estáticas: são criadas no momento em que o compilador gera o código binário, ou seja, em tempo de compilação. Durante a execução do programa, variá- veis estáticas globais estarão sempre ocupando espaço em memória, mesmo que não estejam sendo utilizadas. • variáveis dinâmicas: devem ser criadas somente em caso de real necessidade. Com esse tipo de variável, o programador pode optar por alocar ou desalocar espaço em memória em tempo de execução, caso seja necessário. Com variáveis dinâmicas, pode-se tentar otimizar a ocupação da memória do computador. De acordo com Ascencio e Campos (2012), uma variável é representada como sendo um espaço em memória que pode ser identificado por um nome e que possui um tipo de dados. Para declarar uma variável estática em C, é obrigatório informar qual o tipo da variável e dar um nome a ela, de acordo com a sintaxe exibida no Exemplo 7a. Exemplo 7a - Sintaxe de declaração de uma variável estática <tipo> <nome> [, nome2, nome3, …, nomeN]; Os campos nome2, nome3 etc. são opcionais. Na sintaxe do Exemplo 7a, tais campos são listados, pois é possível declarar múltiplas variáveis distintas em uma mesma linha de comandos. Mais adiante, serão apresentados exemplos de declaração de variáveis. 41Programação de Computadores O nome de uma variável é formalmente conhecido como identificador. Ascêncio e Campos (2012) definem regras para a construção de identificadores: a. só são permitidos números, letras (maiúsculas e minúsculas) e sublinhado ou underscore (_). b. o primeiro caractere nunca pode ser um número. É obrigatório que o primeiro dígito do identificador seja um sublinhado (_) ou uma letra. c. é vetado o uso de espaços e caracteres especiais como @, $, *, &, !, #, ¨, (, etc. d. como visto anteriormente, as palavras reservadas correspondem a um comando específico. Assim, uma variável não pode assumir o mesmo nome de uma palavra reservada. Para ficar mais claro, veja alguns exemplos válidos e inválidos a respeito de identifica- dores de variáveis no quadro “Exemplos de identificadores”. Exemplos de identificadores Exemplos válidos Exemplos inválidos media média aritmética total2 1soma A percentual% nome_cliente r-t Como o próprio nome diz, uma variável pode assumir conteúdos variados, os quais podem ser alterados ao longo da vida do programa. Ou seja, sempre que necessário, podem-se alterar os dados armazenados em variáveis do nosso código. Apesar de ser pos- sível alterar o conteúdo ao bel-prazer, uma variável tem capacidade para armazenar apenas um dado por vez (ASCÊNCIO; CAMPOS, 2012). Além do conceito de variável, existem também as constantes. Uma constante é um valor que não pode ser alterado durante a execução do algoritmo. No padrão C ANSI, pode-se dar nome às constantes, de acordo com a sintaxe do Exemplo 7b: Exemplo 7b - Sintaxe de declaração de uma constante #define <identificador> <conteúdo> Programação de Computadores42 O campo identificador do Exemplo 7b segue as mesmas regras de nomenclatura de variáveis e está relacionado ao nome da constante. Já o campo conteúdo deve ser substi- tuído pelo valor ao qual aquela constante se refere. Assim, sempre que o identificador de uma constante for invocado no código-fonte, o programa entenderá que se refere ao conteúdo da constante, como se pode notar no Exemplo 7c. Exemplo 7c - Declaração e utilização de uma constante do tipo caractere #include <stdio.h> #define msg "Hello, world" int main(){ printf("%s", msg); return 0; } Note que o comando de declaração de uma constante não leva ponto e vírgula no final. Apesar de não ser declarado explicitamente, o compilador, de maneira interna, admite que a constante possa ser do tipo inteiro, real ou caractere; tudo depende de como a diretiva #define foi utilizada. Apenas a declaração de constantes do tipo caractere neces- sita da utilização de aspas duplas para definir seu conteúdo. Constantes do tipo real, ou inteiro, não necessitam de aspas duplas para definir seu valor. Experimente executar o Exemplo 7b para verificar a constante msg em ação. Com isso, haverá flexibilidade para trabalhar com os dados que podem variar, ou não, ao longo do algoritmo. Para você compreender melhor o conceito de variável, será desen- volvido um exemplo, na sequência. 1.3.2 Exemplo: somando dois números Primeiramente, deve-se incluir a biblioteca stdio.h para que o programa possa inte- ragir com o usuário. Em seguida, serão declaradas duas variáveis estáticas globais, capa- zes de armazenar números inteiros: numeroA, numeroB. Por fim, será construída a função main(), para que o programa peça ao usuário que insira dois números inteiros, depois, será exibido na tela o resultado da soma entre os dois números. 43Programação de Computadores Exemplo 8 - Somando dois números inteiros 1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int numeroA, numeroB; main(){ printf("Insira o primeiro valor inteiro.\n"); scanf("%d", &numeroA); printf("Insira o segundo valor inteiro.\n"); scanf("%d", &numeroB); printf("Resultado: %d.\n", numeroA+numeroB); return 0; } Na linha 2 do código-fonte do Exemplo 8, nota-se a declaração de duas variáveis, de acordo com a sintaxe que foi especificada no Exemplo 7a. Nas linhas 4 e 6, são encontra- das duas instruções printf(), que têm o propósito de instruir o usuário sobre o que ele deve fazer enquanto o programa estiver em execução. Se forem omitidos comandos como os das linhas 4 e 6, a pessoa que está interagindo com o programa, provavelmente, não saberá o que fazer, tornando ruim a experiência do usuário. No Exemplo 6a, você teve contato com a sintaxe de utilização do scanf(). Agora, no Exemplo 8, o uso dessa função foi materializado. Perceba, portanto, que nas linhas 5 e 7 há, nos scanf(), o emprego do especificador de formato %d (veja a tabela “Comandos de especificação de formato para apresentação”), entre as aspas dos scanf(). Além disso, o destino dos dados informados via teclado serão as variáveis numeroA e numeroB, ou seja, duas variáveis inteiras. É importante notar que as variáveis elencadas nas linhas 5 e 7 levam o operador e-comercial (&) para que o compilador saiba onde as variáveis numeroA e numeroB, res- pectivamente, encontram-se em memória. O uso do operador & é indispensável na leitura de variáveis simples dentro de um scanf(). Entenda por variáveis simples aquelas que só permitem que um único dado seja armazenado por vez (algumas variáveis especiais admi- tem mais de um dado – os vetores). Por fim, repare na linha 8 do Exemplo 8. Nessa instrução, o printf() faz uso, nova- mente, do especificador de formato %d para poder mostrar, na tela, o resultado da soma entre as variáveis numeroA e numeroB. Experimente copiar o código-fonte do exemplo para somar dois números e execu- tá-lo. A execução do programa deverá produzir um resultado semelhante ao que se vê na figura “Possível resultado para a execução do Exemplo 8”. Programação de Computadores44 possível resultado para a execução do Exemplo 8 Note que você tem autonomia para atuar como o usuário do software, com liberdade para escolher quais serão os valores a serem considerados na soma. Assim, constata-se que o programa pode e deve ser generalizado, ou seja, o programa não ficará restrito à soma de dois valores fixos e inalteráveis, produzindo sempre o mesmo resultado. Ao invés disso, a cada execução, o software poderá produzir resultados distintos, levando em conta o desejo do usuário. Todavia, há ocasiões em que não há a necessidade de questionar o usuá- rio quanto aos valores a serem processados. Nesses casos,o programador tem autonomia para fixar valores no código. Valores e procedimentos que ficam registrados no código- fonte de maneira inalterável são ditos “hard-coded”. 1.3.3 Operações aritméticas Obviamente, você não ficará restrito(a) a operações de soma entre números intei- ros. Assim, já é possível falar de outras instruções que recebem suporte da linguagem C. Operações aritméticas, geralmente, são realizadas sob dois operandos; nesses casos, exis- tem os operadores binários, todavia, também, existem operadores aritméticos unários, que operam sob apenas um operando. Acompanhe, no quadro “Operadores aritméticos”, uma lista com alguns dos operadores aritméticos existentes no padrão C ANSI. operadores aritméticos operador Exemplo tipo Descrição + x+y binário Calcula a soma entre os operandos x e y. - -x unário Inverte o sinal do operando x. - x-y binário Calcula a diferença entre os operandos x e y. * x*y binário Calcula a multiplicação entre os operandos x e y. 45Programação de Computadores / x/y binário Valores inteiros: calcula a divisão inteira de x pelo operando y. Valores reais: calcula a divisão real de x pelo operando y. % x%y binário Retorna o resto da divisão inteira (módulo) de x pelo operando y. Fonte: ASCENCIO; CAMPOS, 2012. (Adaptado). A partir de tais operações, o programador terá condições de criar toda e qualquer expressão aritmética que desejar. As expressões podem ser compostas pelos operado- res aritméticos e os operandos podem ser tanto valores literais quanto variáveis ou outras expressões. Note que operações mais complexas, como o cálculo de potências, raízes, logaritmos, funções trigonométricas etc., não se encontram listadas na tabela “Operadores aritméticos”. Para realizar cálculos mais complexos, sem ter que implementar toda a lógica de tais cálculos, pode-se recorrer à biblioteca math.h. 1.3.4 Operadores de atribuição e acumuladores O Exemplo 8 apenas armazena em memória os valores informados pelo usuá- rio. Repare que o resultado da soma entre os dois números é aferido imprimindo-se dire- tamente o cálculo da operação matemática, no printf() da linha 8. Todavia é possível armazenar os dados do cálculo em memória utilizando o operador de atribuição. Assim, caso fosse necessário reaproveitar esse resultado em outro ponto do programa, uma variá- vel poderia manter esse valor em memória para tal fim. Dessa forma, seria possível rees- crever o Exemplo 8 anterior da seguinte maneira. Exemplo 9 - armazenando o resultado de uma expressão em uma variável 1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int numeroA, numeroB, resultado; main(){ printf("Insira o primeiro valor inteiro.\n"); scanf("%d", &numeroA); printf("Insira o segundo valor inteiro.\n"); scanf("%d", &numeroB); resultado = numeroA + numeroB; printf("Resultado: %d.\n", resultado); return 0; } Programação de Computadores46 Analisando o Exemplo 9, pode-se notar que, na linha 8, a variável resultado está sendo igualada à soma das variáveis numeroA e numeroB. Para isso, foi utilizado o operador igual (=), que denota atribuição. Assim, diz-se que a variável resultado recebe numeroA mais numeroB. Dessa forma, o cálculo da expressão aritmética ficará armazenado na memória principal e poderá ser reaproveitado dentro do programa, como observado na linha 9. Vale salientar que o operador de atribuição é binário, ou seja, necessita de dois operan- dos para funcionar. É preciso notar, ainda, que existe sentido na operação de atribuição. Assim sendo, sempre será o operando que se encontra à esquerda que terá seu conteúdo modificado pelo operando que se encontra à direita. O operador da esquerda deve sempre ser uma variá- vel, enquanto o operando da direita pode ser um literal, uma variável ou uma expressão. Dica É possível fazer com que uma variável receba seu próprio conteúdo, ou seu con- teúdo modificado em uma expressão de atribuição. Ou seja,pode-se fazer algo como: “var = var + 1;”. Existem, ainda, operadores que efetuam operações aritméticas em conjunto com a atribuição. Imagine uma variável x que serve para contar algum evento. Desse modo, seria possível criar uma expressão de atribuição como “x = x + 1;” para atualizar o valor de x a cada vez que o evento ocorre. Assim, existem operadores que facilitam a vida, abstraindo expressões de atualização do conteúdo de uma variável. Tais operadores são ditos de acu- mulação; no quadro “Operadores de acumulação” estão listados os principais. operadores de acumulação operador Exemplo Descrição += x += y Equivalente a x = x + y. -= x -= y Equivalente a x = x - y. *= x *= y Equivalente a x = x * y. /= x /= y Equivalente a x = x / y. %= x %= y Equivalente a x = x % y. ++ x++ Equivalente a x = x + 1. -- x-- Equivalente a x = x - 1. Fonte: ASCÊNCIO; CAMPOS, 2012. (Adaptado). 47Programação de Computadores A seguir, serão trabalhados outros tipos de dados, além de valores numéricos intei- ros. Segundo Schildt (1997), a linguagem C permite conversão de dados com apoio do ope- rador de atribuição; ou seja, em C, pode-se ter certa flexibilidade para misturar operandos de diferentes tipos em uma mesma expressão. 1.4. Trabalhando com mais tipos de dados A linguagem C prevê, basicamente, cinco tipos primitivos de dados, a saber: caractere - char; inteiro - int; ponto flutuante ou real - float; ponto flutuante de precisão dupla - dou- ble; ausência de tipo - void (SCHILDT, 1997). O padrão C ANSI não possui o tipo booleano ou lógico de maneira nativa, pois considera que tudo o que for diferente de zero é verdadeiro (ASCÊNCIO; CAMPOS, 2012). De qualquer forma, o programador pode recorrer à biblioteca stdbool.h para contornar o caso. A partir dessa biblioteca, é possível utilizar o tipo de dado bool, bem como os valores true e false, como se fossem nativos à linguagem C ANSI. 1.4.1 Tipos de variáveis Ao recorrer à arquitetura e à organização de computadores, afere-se que as máqui- nas digitais operam em base numérica binária. Todavia, nós, humanos, estamos habitua- dos a realizar cálculos na base decimal. A partir disso, é possível estabelecer relações de representatividade entre a base decimal e a base binária. Assim, há uma limitação quanto à quantia de valores decimais que são representáveis em base binária, dependendo do número de bits utilizados para se representar o decimal (STALLINGS, 2010). Além dos tipos de dados básicos, mencionados recentemente, é possível utili- zar modificadores para alterar a representação de um tipo de dado. Schildt (1997, p. 17) afirma: “Um modificador é usado para alterar o significado de um tipo básico para adaptá -lo mais precisamente às necessidades de diversas situações”. Os modificadores aos quais Schildt (1997) se refere são: signed, unsigned, long e short. A tabela “Tipos de dados do C padrão ANSI” relaciona os tipos básicos de dados, os tipos modificados, o número de bits e a faixa de representação de decimais em binário, no padrão ANSI. tipos de dados do C padrão aNSI tipo N.º de bits Faixa de representação char 8 -127 a 127 unsigned char 8 0 a 255 int 16 -32.767 a 32.767 unsigned int 16 0 a 65.535 Programação de Computadores48 long int 32 -2.147.483.647 a 2.147.483.647 unsigned long int 32 0 a 4.294.967.295 float 32 3,4 × 10-38 a 3,4 × 1038 double 64 1,7 × 10-308 a 1,7 × 10308 long double 80 3,4 × 10-4932 a 3,4 × 104932 Fonte: ASCÊNCIO; CAMPOS, 2012; SCHILDT, 1997. “Adaptado”. Analisando a tabela “Tipos de dados do C padrão ANSI”, percebe-se que os modifi- cadores devem preceder o tipo de dados, quando da declaração de variáveis do respectivo tipo. Além disso, nota-se que o modificador unsigned remove a representação de núme- ros negativos para poder ganhar valores em sua faixa de representação. Por fim, o modifi- cador long tem a finalidade de “duplicar” o número de bits de um tipo primitivo. 1.4.2 Exemplo: média de notas Você está chegando ao final deste capítulo e, com isso, já tem condições de construirprogramas um pouco mais elaborados. Já foi apresentado como empregar o conceito de variáveis, operações aritméticas, operações de entrada e saída e bibliotecas no código. Assim, imagine uma situação na qual um professor da área de TI, cansado de ter que calcular as notas finais de seus alunos de maneira manual, resolve iniciar a automatização desse processo. O docente, então, começa a desenvolver um software que realize o cálculo automaticamente, bastando apenas informar ao programa quais foram as notas bimestrais do aluno. Para isso, o professor cria algumas variáveis do tipo float e utiliza algumas fun- ções de entrada e saída, conforme o Exemplo 10. 49Programação de Computadores Exemplo 10 - Calculando a média entre quatro notas 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> main(){ float nota1, nota2, nota3, nota4, media; printf("Insira a primeira nota.\n"); scanf("%f", ¬a1); printf("Insira a segunda nota.\n"); scanf("%f", ¬a2); printf("Insira a terceira nota.\n"); scanf("%f", ¬a3); printf("Insira a quarta nota.\n"); scanf("%f", ¬a4); media = (nota1 + nota2 + nota3 + nota4)/4; printf("Média final: %f.\n", media); return 0; } No Exemplo 10, surgem elementos que, até então, não apareceram nos exemplos anteriores. Perceba que, agora, o programador decidiu declarar todas as cinco variáveis dentro do escopo da função main(), e não fora (variáveis globais), como anteriormente. Além disso, por serem valores em ponto flutuante, ou seja, por admitirem casas decimais, o especificador de formato utilizado dentro dos scanf() das linhas 5, 7, 9 e 11 é o %f, haja vista que se está lidando com variáveis no domínio dos números reais. Na linha 12, o programador utiliza parênteses para delimitar precedência entre as operações de soma e de divisão, o que significa que, nesse caso, as operações de soma serão executadas antes da divisão. Ainda na linha 12, observe que estão sendo manipula- dos dados do tipo float e, por isso, a operação realizada aqui é a de divisão real, ou seja, o resultado poderá conter casas decimais. Antes de prosseguir para a próxima seção, tente reescrever o código do Exemplo 10 utilizando, para o mesmo propósito, apenas duas variáveis, ao invés de cinco. 1.4.3 Exemplo: recebendo e imprimindo caracteres A biblioteca stdlib.h possui várias funções importantes para manipular caracte- res alfanuméricos. Além da biblioteca C padrão, bibliotecas como a conio.h, string.h e ctype.h dão ao programador um conjunto ainda maior de possibilidades quanto à manipu- lação de dados de texto (SCHILDT, 1997). Programação de Computadores50 Trabalhar com dados alfanuméricos em C pode ser um pouco oneroso, pois a lingua- gem encara dados de texto (strings) como vetores, os quais não fazem parte do escopo deste capítulo. Todavia, pode-se trabalhar com caracteres individuais, o que dá um breve vislumbre sobre como manipular dados desse tipo. Exemplo 11 - lendo e imprimindo um caractere alfanumérico 1 2 3 4 5 6 7 #include <stdio.h> int main(){ char letra; printf("Insira um caractere alfanumérico:\n"); scanf("%c", &letra); printf("O dado inserido foi: %c", letra); } O Exemplo 11 solicita ao usuário que insira um caractere alfanumérico e, na sequên- cia, o imprime para que o usuário confirme sua digitação. Na linha 3, é possível ver que a variável letra é do tipo char. Assim, a variável possui a capacidade de armazenar, além de números, letras e outros caracteres especiais, de acordo com o padrão definido pelo American Standard Code for Information Interchange (ASCII), que pode ser visualizado na tabela “Padrão ASCII para codificação de caracteres alfanuméricos” (ASCII TABLE..., 2010). padrão aSCII para codificação de caracteres alfanuméricos Dec Hx Oct Char Dec Hx Oct Html Chr Dec Hx Oct Html Chr Dec Hx Oct Html Chr 0 0 000 NUL (null) 32 20 040   Space 64 40 100 @ @ 96 60 140 ` ` 1 1 001 SOH (start of heading) 33 21 041 ! ! 65 41 101 A A 97 61 141 a a 2 2 002 STX (start of text) 34 22 042 " “ 66 42 102 B B 98 62 142 b b 3 3 003 ETX (end of text) 35 23 043 # # 67 43 103 C C 99 63 143 c c 4 4 004 EOT (end of transmission) 36 24 044 $ $ 68 44 104 D D 100 64 144 d d 5 5 005 ENQ (enquiry) 37 25 045 % % 69 45 105 E E 101 65 145 e e 6 6 006 ACK (acknowledge) 38 26 046 & & 70 46 106 F F 102 66 146 f f 7 7 007 BEL (bell) 39 27 047 ' ‘ 71 47 107 G G 103 67 147 g g 8 8 010 BS (backspace) 40 28 050 ( ( 72 48 110 H H 104 68 150 h h 9 9 011 TAB (horizontal tab) 41 29 051 ) ) 73 49 111 I I 105 69 151 i i 10 A 012 LF (NL line feed, new line) 42 2A 052 * * 74 4A 112 J J 106 6A 152 j j 11 B 013 VT (vertical tab) 43 2B 053 + + 75 4B 113 K K 107 6B 153 k k 12 C 014 FF (NP form feed, new page) 44 2C 054 , , 76 4C 114 L L 108 6C 154 l l 13 D 015 CR (carriage return) 45 2D 055 - - 77 4D 115 M M 109 6D 155 m m 14 E 016 SO (shift out) 46 2E 056 . . 78 4E 116 N N 110 6E 156 n n 15 F 017 SI (shift in) 47 2F 057 / / 79 4F 117 O O 111 6F 157 o o 51Programação de Computadores 16 10 020 DLE (data link espace) 48 30 060 0 0 80 50 120 P P 112 70 160 p p 17 11 021 DC1 (davice control 1) 49 31 061 1 1 81 51 121 Q Q 113 71 161 q q 18 12 022 DC2 (device control 2) 50 32 062 2 2 82 52 122 R R 114 72 162 r r 19 13 023 DC3 (device control 3) 51 33 063 3 3 83 53 123 S S 115 73 163 s s 20 14 024 DC4 (device constrol 4) 52 34 064 4 4 84 54 124 T T 116 74 164 t t 21 15 025 NAK (negative acknowledge) 53 35 065 5 5 85 55 125 U U 117 75 165 u u 22 16 026 SYN (synchronous idle) 54 36 066 6 6 86 56 126 V V 118 76 166 v v 23 17 027 ETB (end of trans. block) 55 37 067 7 7 87 57 127 W W 119 77 167 w w 24 18 030 CAN (cancel) 56 38 070 8 8 88 58 130 X X 120 78 170 x x 25 19 031 EM (end of medium) 57 39 071 9 9 89 59 131 Y Y 121 79 171 y y 26 1A 032 SUB (substitute) 58 3A 072 : : 90 5A 132 Z Z 122 7A 172 z z 27 1B 033 ESC (escape) 59 3B 073 ; ; 91 5B 133 [ [ 123 7B 173 { { 28 1C 034 FS (file separator) 60 3C 074 < < 92 5C 134 \ \ 124 7C 174 | | 29 1D 035 GS (group separator) 61 3D 075 = = 93 5D 135 ] ] 125 7D 175 } } 30 1E 036 RS (record separator) 62 3E 076 > > 94 5E 136 ^ ^ 126 7E 176 ~ ~ 31 1F 037 US (unit separator) 63 3F 077 ? ? 95 5F 137 _ _ 127 7F 177  DEL Fonte: ASCII table..., 2010, on-line. Observando a tabela “Padrão ASCII para codificação de caracteres alfanuméricos”, nota-se que os caracteres alfanuméricos são, na verdade, representações de um número inteiro convertido em um símbolo. Por exemplo, caso você tente imprimir, na linha 6 do Exemplo 11, a variável letra utilizando o especificador de forma %i (ao invés de %d), estará mostrando ao usuário o valor decimal inteiro correspondente àquele caractere, de acordo com a tabela “Padrão ASCII para codificação de caracteres alfanuméricos”. Para Schildt (1997), dados do tipo char são, no fim das contas, números inteiros, em linguagem C. 1.4.4 Exemplos dirigidos Para fixar seu entendimento, é de suma importância praticar exaustivamente. A seguir, serão apresentadas algumas situações-problemas que serão solucionadas, passo a passo, em linguagem C. problema 1 O gerente de Recursos Humanos (RH) de uma organização solicitou a programadores que construíssem um sistema simples. O programa deveria receber como dados de entrada o número de horas trabalhadas por um colaborador qualquer e, também, o salário mínimo vigente. Como saída, o gerente de RH espera saber qual é o repasse a ser entregue ao cola- borador, de acordo com os seguintes cálculos: Programação de Computadores52 a. o valor da hora trabalhada é igual ao salário mínimo, dividido pelas180 horas comerciais de um mês. b. o valor do salário bruto é o número de horas trabalhadas multiplicado pelo valor da hora trabalhada. c. o imposto é igual a 5% do salário bruto. d. a contribuição previdenciária obrigatória é igual a 11% do salário bruto. e. o repasse é igual ao salário bruto, descontando-se o imposto somado à contribui- ção previdenciária. Solução Antes de mais nada, adiciona-se a biblioteca stdio.h ao código-fonte (Exemplo 12), na linha 1, uma vez que há intenção de interagir com o usuário. Em seguida, deve-se voltar ao enunciado e procurar quais são os dados de entrada e saída do programa. Logo, nota-se que o programa deve receber o número de horas trabalhadas e o valor do salário mínimo vigente. Por isso, são criadas, nas linhas 3 e 4, as variáveis NumHoras e SalMin, do tipo float, para representar os respectivos valores de entrada. A especificação do problema informa que o programa deve produzir o valor do repasse como resultado. Assim, declara-se, na linha 4, a variável Repasse, do tipo float. Todavia o cálculo do repasse deve seguir regras que levam em conta dados como: o valor da hora trabalhada, o salário bruto, a quantidade de imposto a ser pago e a contribuição previdenciária. Por isso, também na linha 4, foram criadas outras quatro variáveis auxilia- res do tipo float: ValHora, SalBruto, Imp e Prev. Em seguida, na linha 5, imprime-se uma mensagem na tela, por meio de um printf(), solicitando ao usuário que insira o número de horas trabalhadas. O scanf() da linha 6 realiza a leitura de um valor real (%f) para dentro da variável NumHoras. Na linha 7, é solicitado que o usuário insira o salário mínimo e, na linha 8, o scanf() irá ler um dado em ponto flutuante (%f) para dentro da variável SalMin. 53Programação de Computadores Exemplo 12 - Solução completa para o problema 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> int main(){ float NumHoras; float SalMin, ValHora, SalBruto, Imp, Prev, Repasse; printf("Insira a quantia de horas trabalhadas:\n"); scanf("%d", &NumHoras); printf("Insira o salário mínimo vigente:\n"); scanf("%f", &SalMin); ValHora = SalMin / 180.00; SalBruto = ValHora * NumHoras; Imp = SalBruto * 0.05; Prev = SalBruto * 0.11; Repasse = SalBruto - (Imp + Prev); printf("Salário a ser pago: %.2f.\n", Repasse); } Após ler os dados, podem-se seguir as regras definidas pelo gerente de RH para pro- duzir o resultado esperado. Assim, na linha 9, é realizado o cálculo do valor da hora traba- lhada, de acordo com o item A do enunciado. Depois, na linha 10, encontra-se o valor do salário bruto, como especificado no item B da descrição do problema. Nas linhas 11 e 12, respectivamente, são calculados o valor do imposto e a contribuição previdenciária, como foi pedido nos itens C e D. Por fim, seguindo as instruções do item E, são descontados o imposto e a contribuição previdenciária do valor do salário bruto. O resultado desse cálculo é atribuído à variável Repasse (linha 13), e, na linha 14, o resultado é impresso na tela. Exemplo 13 - Solução alternativa para o problema 1 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main(){ float NumHoras; float SalMin, Resultado; printf("Insira a quantia de horas trabalhadas:\n"); scanf("%d", &NumHoras); printf("Insira o salário mínimo vigente:\n"); scanf("%f", &SalMin); Resultado = SalMin / 180.00; Resultado *= NumHoras; Resultado = Resultado - (Resultado * 0.05 + Resultado * 0.11); printf("Salário a ser pago: %.2f.\n", Resultado); } Programação de Computadores54 O algoritmo do Exemplo 12 atende plenamente às instruções do enunciado. Porém pode-se ser mais criteriosos quanto ao número de variáveis utilizadas, considerando, hipo- teticamente, que fosse necessário poupar a memória do computador, reduzindo o número de variáveis utilizadas. Seria possível obter, para uma mesma entrada, um resultado igual ao do Exemplo 12, utilizando apenas três variáveis no código-fonte, como é possível cons- tatar no Exemplo 13. Pausa para refletir: É possível utilizar uma mesma variável em ambos os lados de uma atribuição. Assim, seria possível reduzir ainda mais o número de variáveis da solução do Exemplo 13? problema 2 Considere uma aplicação militar, na qual um relógio de precisão atômica avisa a um microcontrolador sempre que um novo segundo se passou. O microcontrolador é capaz de contar quantos segundos se passaram, mas não apresenta essa informação de maneira for- matada. Sua obrigação, enquanto projetista, é desenvolver um programa em linguagem C que seja capaz de receber e processar o valor de tempo, em segundos. O software deve imprimir, na tela, a conversão do dado de entrada em horas, minutos e segundos. Solução De acordo com o enunciado, o programa deverá ler o tempo, em segundos, e trans- formar esse valor em horas, minutos e segundos. Por isso, na linha 3 do Exemplo 14, são declaradas três variáveis inteiras, H, m e s, que representam as horas, os minutos e os segundos, respectivamente. Após solicitar ao usuário que informe o dado de entrada, e ler tal dado, nas linhas 4 e 5, o programa inicia a lógica que irá processar o dado de entrada para produzir a saída desejada. Antes de entender o passo a passo para conversão, é preciso ter em mente que um minuto possui 60 segundos. Também, é importante saber que uma hora possui 60 minu- tos. Assim sendo, multiplicando 60 minutos por 60 segundos, afere-se que uma hora possui 3600 segundos. Com base nisso, é possível dar sequência à análise da solução. 55Programação de Computadores Exemplo 14 - Solução completa para o problema 2 1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> int main(){ int H, m, s; printf("Insira o tempo, em segundos.\n"); scanf("%d", &s); H = s / 3600; s = s - (H * 3600); m = s / 60; s = s - (m * 60); printf("Horas: %d\nMinutos: %d\nSegundos: %d\n", H, m, s); } No Exemplo 14, para calcular quantas horas se passaram, na linha 6, deve-se dividir a variável s por 3600, haja vista que, a cada 3600 segundos, tem-se 1 hora. Uma vez contabi- lizadas as horas, é preciso descontar do valor original (dado informado pelo usuário - linha 5) quantas horas se passaram, em segundos. Isso é feito porque esses segundos não serão mais contabilizados no cálculo de quantos minutos se passaram após a última hora com- pleta. Por isso, na linha 7, subtrai-se de s o valor das horas convertido em segundos (H * 3600). Dessa forma, a variável s conterá o saldo atualizado dos segundos restantes. Depois, na linha 8, trabalha-se no sentido de contabilizar quantos minutos se pas- saram, desde a última hora que se completou, a partir dos segundos restantes, que são encontrados na linha 7. Por fim, na linha 9, o valor de s é atualizado, descontando o valor, em segundos, dos minutos que se passaram, pois eles já foram contabilizados na variável m. Com isso, a variável s estará armazenando os segundos remanescentes desde a conclu- são do último minuto. A linha 10 apenas imprime os resultados obtidos durante o processamento. Experimente executar o código-fonte do Exemplo 14 para averiguar como o programa apresenta a solução esperada. Mas será que esse problema não pode ser resolvido de outras maneiras? O Exemplo 15, a seguir, demonstra que sim. Programação de Computadores56 Exemplo 15 - Solução alternativa para o problema 2 1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main(){ int H, m, s; printf("Insira o tempo, em segundos.\n"); scanf("%d", &s); H = (s / 60) / 60; m = (s / 60) % 60; s = s % 60; printf("\n\nHoras: %d\nMinutos: %d\nSegundos: %d\n", H, m, s); } A solução alternativa do Exemplo 15 difere-se da anterior por utilizar o operador de resto de divisão (%), também conhecido como módulo. Partindo para uma análise do pro- cessamento encontrado entre as linhas 6 e 8, observa-se como a lógica alternativa apre- senta um resultado tão correto quanto o do Exemplo 14. Na linha 6, divide-se s por 60 para saber
Compartilhar